github.com/graemephi/kahugo@v0.62.3-0.20211121071557-d78c0423784d/common/hreflect/helpers.go (about) 1 // Copyright 2019 The Hugo Authors. All rights reserved. 2 // Some functions in this file (see comments) is based on the Go source code, 3 // copyright The Go Authors and governed by a BSD-style license. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 // Package hreflect contains reflect helpers. 17 package hreflect 18 19 import ( 20 "reflect" 21 22 "github.com/gohugoio/hugo/common/types" 23 ) 24 25 // TODO(bep) replace the private versions in /tpl with these. 26 // IsNumber returns whether the given kind is a number. 27 func IsNumber(kind reflect.Kind) bool { 28 return IsInt(kind) || IsUint(kind) || IsFloat(kind) 29 } 30 31 // IsInt returns whether the given kind is an int. 32 func IsInt(kind reflect.Kind) bool { 33 switch kind { 34 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 35 return true 36 default: 37 return false 38 } 39 } 40 41 // IsUint returns whether the given kind is an uint. 42 func IsUint(kind reflect.Kind) bool { 43 switch kind { 44 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 45 return true 46 default: 47 return false 48 } 49 } 50 51 // IsFloat returns whether the given kind is a float. 52 func IsFloat(kind reflect.Kind) bool { 53 switch kind { 54 case reflect.Float32, reflect.Float64: 55 return true 56 default: 57 return false 58 } 59 } 60 61 // IsTruthful returns whether in represents a truthful value. 62 // See IsTruthfulValue 63 func IsTruthful(in interface{}) bool { 64 switch v := in.(type) { 65 case reflect.Value: 66 return IsTruthfulValue(v) 67 default: 68 return IsTruthfulValue(reflect.ValueOf(in)) 69 } 70 } 71 72 var zeroType = reflect.TypeOf((*types.Zeroer)(nil)).Elem() 73 74 // IsTruthfulValue returns whether the given value has a meaningful truth value. 75 // This is based on template.IsTrue in Go's stdlib, but also considers 76 // IsZero and any interface value will be unwrapped before it's considered 77 // for truthfulness. 78 // 79 // Based on: 80 // https://github.com/golang/go/blob/178a2c42254166cffed1b25fb1d3c7a5727cada6/src/text/template/exec.go#L306 81 func IsTruthfulValue(val reflect.Value) (truth bool) { 82 val = indirectInterface(val) 83 84 if !val.IsValid() { 85 // Something like var x interface{}, never set. It's a form of nil. 86 return 87 } 88 89 if val.Type().Implements(zeroType) { 90 return !val.Interface().(types.Zeroer).IsZero() 91 } 92 93 switch val.Kind() { 94 case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 95 truth = val.Len() > 0 96 case reflect.Bool: 97 truth = val.Bool() 98 case reflect.Complex64, reflect.Complex128: 99 truth = val.Complex() != 0 100 case reflect.Chan, reflect.Func, reflect.Ptr, reflect.Interface: 101 truth = !val.IsNil() 102 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 103 truth = val.Int() != 0 104 case reflect.Float32, reflect.Float64: 105 truth = val.Float() != 0 106 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 107 truth = val.Uint() != 0 108 case reflect.Struct: 109 truth = true // Struct values are always true. 110 default: 111 return 112 } 113 114 return 115 } 116 117 // Based on: https://github.com/golang/go/blob/178a2c42254166cffed1b25fb1d3c7a5727cada6/src/text/template/exec.go#L931 118 func indirectInterface(v reflect.Value) reflect.Value { 119 if v.Kind() != reflect.Interface { 120 return v 121 } 122 if v.IsNil() { 123 return reflect.Value{} 124 } 125 return v.Elem() 126 }