github.com/searKing/golang/go@v1.2.117/reflect/value.go (about) 1 // Copyright 2020 The searKing Author. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package reflect 6 7 import ( 8 "bytes" 9 "fmt" 10 "reflect" 11 "unsafe" 12 13 bytes_ "github.com/searKing/golang/go/bytes" 14 "github.com/searKing/golang/go/container/traversal" 15 ) 16 17 const PtrSize = unsafe.Sizeof(uintptr(0)) // an ideal const, sizeof *void, as 4 << (^uintptr(0) >> 63) 18 19 // IsEmptyValue reports whether v is empty value for its type. 20 // 21 // The zero value is: 22 // 23 // 0 for numeric types, 24 // false for the boolean type, and 25 // "" (the empty string) for strings, and 26 // {} (the empty struct) for structs, and 27 // untyped nil or typed nil or len == 0 for maps, slices, pointers, functions, interfaces, and channels. 28 // Code borrowed from https://github.com/golang/go/blob/go1.22.0/src/encoding/json/encode.go#L306 29 func IsEmptyValue(v reflect.Value) bool { 30 if !v.IsValid() { 31 return true 32 } 33 switch v.Kind() { 34 case reflect.Array, reflect.Map, reflect.Slice, reflect.String: 35 return v.Len() == 0 36 case reflect.Bool, 37 reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 38 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, 39 reflect.Float32, reflect.Float64, 40 reflect.Interface, reflect.Pointer: 41 return v.IsZero() 42 default: 43 return reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface()) 44 } 45 } 46 47 // IsZeroValue reports whether v is zero value for its type. 48 // Zero values are variables declared without an explicit initial value are given their zero value. 49 // 50 // The zero value is: 51 // 52 // 0 for numeric types, 53 // false for the boolean type, and 54 // "" (the empty string) for strings. 55 // untyped nil or typed nil for maps, slices, pointers, functions, interfaces, and channels. 56 func IsZeroValue(v reflect.Value) bool { 57 if !v.IsValid() { 58 return true 59 } 60 61 // Use v.IsZero instead since go1.13. 62 return v.IsZero() 63 } 64 65 // IsNilValue reports whether v is untyped nil or typed nil for its type. 66 func IsNilValue(v reflect.Value) bool { 67 var zeroV reflect.Value 68 if v == zeroV { 69 return true 70 } 71 if !v.IsValid() { 72 // This should never happen, but will act as a safeguard for later, 73 // as a default value doesn't make sense here. 74 panic(&reflect.ValueError{Method: "reflect.Value.IsNilValue", Kind: v.Kind()}) 75 } 76 switch v.Kind() { 77 case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer, reflect.UnsafePointer, 78 reflect.Interface, reflect.Slice: 79 return v.IsNil() 80 default: 81 return false 82 } 83 } 84 85 func FollowValuePointer(v reflect.Value) reflect.Value { 86 v = reflect.Indirect(v) 87 if v.Kind() == reflect.Ptr { 88 return FollowValuePointer(v) 89 } 90 return v 91 } 92 93 // FieldValueInfo represents a single field found in a struct. 94 type FieldValueInfo struct { 95 value reflect.Value 96 structField reflect.StructField 97 index []int 98 } 99 100 func (info FieldValueInfo) MiddleNodes() []any { 101 102 if !info.value.IsValid() { 103 return nil 104 } 105 if IsNilType(info.value.Type()) { 106 return nil 107 } 108 val := FollowValuePointer(info.value) 109 if val.Kind() != reflect.Struct { 110 return nil 111 } 112 113 var middles []any 114 // Scan typ for fields to include. 115 for i := 0; i < val.NumField(); i++ { 116 index := make([]int, len(info.index)+1) 117 copy(index, info.index) 118 index[len(info.index)] = i 119 middles = append(middles, FieldValueInfo{ 120 value: val.Field(i), 121 structField: val.Type().Field(i), 122 index: index, 123 }) 124 } 125 return middles 126 } 127 func (info FieldValueInfo) Depth() int { 128 return len(info.index) 129 } 130 131 func (info FieldValueInfo) Value() reflect.Value { 132 return info.value 133 } 134 135 func (info FieldValueInfo) StructField() (reflect.StructField, bool) { 136 if IsEmptyValue(reflect.ValueOf(info.structField)) { 137 return info.structField, false 138 } 139 return info.structField, true 140 } 141 142 func (info FieldValueInfo) Index() []int { 143 return info.index 144 } 145 146 func (info *FieldValueInfo) String() string { 147 //if IsNilValue(info.value) { 148 // return fmt.Sprintf("%+v", nil) 149 //} 150 //info.value.String() 151 //return fmt.Sprintf("%+v %+v", info.value.Type().String(), info.value) 152 153 switch k := info.value.Kind(); k { 154 case reflect.Invalid: 155 return "<invalid value>" 156 case reflect.String: 157 return "[string: " + info.value.String() + "]" 158 } 159 // If you call String on a reflect.value of other type, it's better to 160 // print something than to panic. Useful in debugging. 161 return "[" + info.value.Type().String() + ":" + func() string { 162 if info.value.CanInterface() && info.value.Interface() == nil { 163 return "<nil value>" 164 } 165 return fmt.Sprintf(" %+v", info.value) 166 }() + "]" 167 } 168 169 type FieldValueInfoHandler interface { 170 Handler(info FieldValueInfo) (goon bool) 171 } 172 type FieldValueInfoHandlerFunc func(info FieldValueInfo) (goon bool) 173 174 func (f FieldValueInfoHandlerFunc) Handler(info FieldValueInfo) (goon bool) { 175 return f(info) 176 } 177 178 func WalkValueDFS(val reflect.Value, handler FieldValueInfoHandler) { 179 traversal.DepthFirstSearchOrder(FieldValueInfo{ 180 value: val, 181 }, traversal.HandlerFunc(func(node any, depth int) (goon bool) { 182 return handler.Handler(node.(FieldValueInfo)) 183 })) 184 } 185 186 func WalkValueBFS(val reflect.Value, handler FieldValueInfoHandler) { 187 traversal.BreadthFirstSearchOrder(FieldValueInfo{ 188 value: val, 189 }, traversal.HandlerFunc(func(node any, depth int) (goon bool) { 190 return handler.Handler(node.(FieldValueInfo)) 191 })) 192 } 193 194 func DumpValueInfoDFS(v reflect.Value) string { 195 dumpInfo := &bytes.Buffer{} 196 first := true 197 WalkValueDFS(v, FieldValueInfoHandlerFunc(func(info FieldValueInfo) (goon bool) { 198 if first { 199 first = false 200 bytes_.NewIndent(dumpInfo, "", "\t", info.Depth()) 201 } else { 202 bytes_.NewLine(dumpInfo, "", "\t", info.Depth()) 203 } 204 dumpInfo.WriteString(fmt.Sprintf("%+v", info.String())) 205 return true 206 })) 207 return dumpInfo.String() 208 } 209 210 func DumpValueInfoBFS(v reflect.Value) string { 211 dumpInfo := &bytes.Buffer{} 212 first := true 213 WalkValueBFS(v, FieldValueInfoHandlerFunc(func(info FieldValueInfo) (goon bool) { 214 if first { 215 first = false 216 bytes_.NewIndent(dumpInfo, "", "\t", info.Depth()) 217 } else { 218 bytes_.NewLine(dumpInfo, "", "\t", info.Depth()) 219 } 220 dumpInfo.WriteString(fmt.Sprintf("%+v", info.String())) 221 return true 222 })) 223 return dumpInfo.String() 224 }