convert.go (3168B)
1 // Copyright 2019 The Hugo Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package types 15 16 import ( 17 "encoding/json" 18 "fmt" 19 "html/template" 20 "reflect" 21 "time" 22 23 "github.com/spf13/cast" 24 ) 25 26 // ToDuration converts v to time.Duration. 27 // See ToDurationE if you need to handle errors. 28 func ToDuration(v any) time.Duration { 29 d, _ := ToDurationE(v) 30 return d 31 } 32 33 // ToDurationE converts v to time.Duration. 34 func ToDurationE(v any) (time.Duration, error) { 35 if n := cast.ToInt(v); n > 0 { 36 return time.Duration(n) * time.Millisecond, nil 37 } 38 d, err := time.ParseDuration(cast.ToString(v)) 39 if err != nil { 40 return 0, fmt.Errorf("cannot convert %v to time.Duration", v) 41 } 42 return d, nil 43 } 44 45 // ToStringSlicePreserveString is the same as ToStringSlicePreserveStringE, 46 // but it never fails. 47 func ToStringSlicePreserveString(v any) []string { 48 vv, _ := ToStringSlicePreserveStringE(v) 49 return vv 50 } 51 52 // ToStringSlicePreserveStringE converts v to a string slice. 53 // If v is a string, it will be wrapped in a string slice. 54 func ToStringSlicePreserveStringE(v any) ([]string, error) { 55 if v == nil { 56 return nil, nil 57 } 58 if sds, ok := v.(string); ok { 59 return []string{sds}, nil 60 } 61 result, err := cast.ToStringSliceE(v) 62 if err == nil { 63 return result, nil 64 } 65 66 // Probably []int or similar. Fall back to reflect. 67 vv := reflect.ValueOf(v) 68 69 switch vv.Kind() { 70 case reflect.Slice, reflect.Array: 71 result = make([]string, vv.Len()) 72 for i := 0; i < vv.Len(); i++ { 73 s, err := cast.ToStringE(vv.Index(i).Interface()) 74 if err != nil { 75 return nil, err 76 } 77 result[i] = s 78 } 79 return result, nil 80 default: 81 return nil, fmt.Errorf("failed to convert %T to a string slice", v) 82 } 83 84 } 85 86 // TypeToString converts v to a string if it's a valid string type. 87 // Note that this will not try to convert numeric values etc., 88 // use ToString for that. 89 func TypeToString(v any) (string, bool) { 90 switch s := v.(type) { 91 case string: 92 return s, true 93 case template.HTML: 94 return string(s), true 95 case template.CSS: 96 return string(s), true 97 case template.HTMLAttr: 98 return string(s), true 99 case template.JS: 100 return string(s), true 101 case template.JSStr: 102 return string(s), true 103 case template.URL: 104 return string(s), true 105 case template.Srcset: 106 return string(s), true 107 } 108 109 return "", false 110 } 111 112 // ToString converts v to a string. 113 func ToString(v any) string { 114 s, _ := ToStringE(v) 115 return s 116 } 117 118 // ToStringE converts v to a string. 119 func ToStringE(v any) (string, error) { 120 if s, ok := TypeToString(v); ok { 121 return s, nil 122 } 123 124 switch s := v.(type) { 125 case json.RawMessage: 126 return string(s), nil 127 default: 128 return cast.ToStringE(v) 129 } 130 }