github.com/hedzr/evendeep@v0.4.8/internal/tool/ref.go (about) 1 package tool 2 3 import ( 4 "fmt" 5 "math" 6 "reflect" 7 "unsafe" 8 ) 9 10 // 11 // ref.go - the routines about reflect operations 12 // 13 14 // Rdecode decodes an interface{} or a pointer to something to its 15 // underlying data type. 16 // 17 // Suppose we have an interface{} pointer Value which stored a 18 // pointer to an integer, Rdecode will extract or retrieve the Value 19 // of that integer. 20 // 21 // See our TestRdecode() in ref_test.go 22 // 23 // var b = 11 24 // var i interface{} = &b 25 // var v = reflect.ValueOf(&i) 26 // var n = Rdecode(v) 27 // println(n.Type()) // = int 28 // 29 // `prev` returns the previous Value before we arrived at the 30 // final `ret` Value. 31 // In another word, the value of `prev` Value is a pointer which 32 // points to the value of `ret` Value. Or, it's a interface{} 33 // wrapped about `ret`. 34 // 35 // A interface{} will be unboxed to its underlying datatype after 36 // Rdecode invoked. 37 func Rdecode(reflectValue reflect.Value) (ret, prev reflect.Value) { 38 return Rskip(reflectValue, reflect.Ptr, reflect.Interface) 39 } 40 41 // Rdecodesimple is a shortcut to Rdecode without `prev` returned. 42 func Rdecodesimple(reflectValue reflect.Value) (ret reflect.Value) { 43 ret, _ = Rdecode(reflectValue) 44 return 45 } 46 47 func Rskip(reflectValue reflect.Value, kinds ...reflect.Kind) (ret, prev reflect.Value) { 48 ret, prev = reflectValue, reflectValue 49 retry: 50 k := ret.Kind() 51 for _, kk := range kinds { 52 if k == kk { 53 prev = ret 54 ret = ret.Elem() 55 goto retry 56 } 57 } 58 return 59 } 60 61 // Rdecodetype try to strip off ptr and interface{} from a type. 62 // 63 // It might not work properly on some cases because interface{} cannot 64 // be stripped with calling typ.Elem(). 65 // 66 // In this case, use rdecodesimple(value).Type() instead 67 // of Rdecodetypesimple(value.Type()). 68 func Rdecodetype(reflectType reflect.Type) (ret, prev reflect.Type) { 69 return Rskiptype(reflectType, reflect.Ptr, reflect.Interface) 70 } 71 72 // Rdecodetypesimple try to strip off ptr and interface{} from a type. 73 // 74 // It might not work properly on some cases because interface{} cannot 75 // be stripped with calling typ.Elem(). 76 // For this case, use Rdecodesimple(value).Type() instead 77 // of Rdecodetypesimple(value.Type()). 78 func Rdecodetypesimple(reflectType reflect.Type) (ret reflect.Type) { 79 ret, _ = Rdecodetype(reflectType) 80 return 81 } 82 83 func Rskiptype(reflectType reflect.Type, kinds ...reflect.Kind) (ret, prev reflect.Type) { 84 ret, prev = reflectType, reflectType 85 retry: 86 k := ret.Kind() 87 for _, kk := range kinds { 88 if k == kk { 89 if canElem(k) { 90 prev = ret 91 ret = ret.Elem() 92 goto retry 93 } 94 } 95 } 96 return 97 } 98 99 func canElem(k reflect.Kind) bool { 100 switch k { //nolint:exhaustive //others unlisted cases can be ignored 101 case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice: 102 return true 103 } 104 return false 105 } 106 107 func Rindirect(reflectValue reflect.Value) reflect.Value { 108 for reflectValue.Kind() == reflect.Ptr { 109 reflectValue = reflectValue.Elem() 110 } 111 return reflectValue 112 } 113 114 func RindirectType(reflectType reflect.Type) reflect.Type { 115 for reflectType.Kind() == reflect.Ptr { // || reflectType.Kind() == reflect.Slice { 116 reflectType = reflectType.Elem() 117 } 118 return reflectType 119 } 120 121 func Rwant(reflectValue reflect.Value, kinds ...reflect.Kind) reflect.Value { 122 k := reflectValue.Kind() 123 retry: 124 for _, kk := range kinds { 125 if k == kk { 126 return reflectValue 127 } 128 } 129 130 if k == reflect.Interface || k == reflect.Ptr { 131 reflectValue = reflectValue.Elem() 132 k = reflectValue.Kind() 133 goto retry 134 } 135 136 return reflectValue 137 } 138 139 func IsNumericType(t reflect.Type) bool { return IsNumericKind(t.Kind()) } 140 func IsNumIntegerType(t reflect.Type) bool { return IsNumIntegerKind(t.Kind()) } 141 func IsNumericKind(k reflect.Kind) bool { return k >= reflect.Int && k < reflect.Array } 142 func IsNumSIntegerKind(k reflect.Kind) bool { return k >= reflect.Int && k <= reflect.Int64 } 143 func IsNumUIntegerKind(k reflect.Kind) bool { return k >= reflect.Uint && k <= reflect.Uint64 } 144 func IsNumIntegerKind(k reflect.Kind) bool { return k >= reflect.Int && k <= reflect.Uint64 } 145 func IsNumFloatKind(k reflect.Kind) bool { return k >= reflect.Float32 && k <= reflect.Float64 } 146 func IsNumComplexKind(k reflect.Kind) bool { return k >= reflect.Complex64 && k <= reflect.Complex128 } 147 148 func KindIs(k reflect.Kind, list ...reflect.Kind) bool { 149 for _, l := range list { 150 if k == l { 151 return true 152 } 153 } 154 return false 155 } 156 157 func Typfmtvlite(v *reflect.Value) string { 158 if v == nil || !v.IsValid() { 159 return "<invalid>" //nolint:goconst //why need const it? 160 } 161 t := v.Type() 162 return fmt.Sprintf("%v", t) //nolint:gocritic //safe string with fmt lib 163 } 164 165 func Typfmtv(v *reflect.Value) string { 166 if v == nil || !v.IsValid() { 167 return "<invalid>" 168 } 169 t := v.Type() 170 return fmt.Sprintf("%v (%v)", t, t.Kind()) 171 } 172 173 func Typfmt(t reflect.Type) string { 174 return fmt.Sprintf("%v (%v)", t, t.Kind()) 175 } 176 177 func Typfmtptr(t *reflect.Type) string { //nolint:gocritic //ptrToRefParam: consider `t' to be of non-pointer type 178 if t == nil { 179 return "???" 180 } 181 return fmt.Sprintf("%v (%v)", *t, (*t).Kind()) 182 } 183 184 // Valfmtptr will step into a ptr value at first, then Valfmt. 185 func Valfmtptr(v *reflect.Value) string { 186 s := ValfmtptrPure(v) 187 if len(s) > maxValueStringLen { 188 return s[0:maxValueStringLen-3] + "..." 189 } 190 return s 191 } 192 193 // ValfmtptrPure will step into a ptr value at first, then Valfmt. 194 func ValfmtptrPure(v *reflect.Value) string { 195 if v == nil || !v.IsValid() { 196 return "<invalid>" 197 } 198 if v.Kind() == reflect.Ptr { 199 vp := v.Elem() 200 return Valfmtptr(&vp) 201 } 202 return Valfmt(v) 203 } 204 205 const maxValueStringLen = 320 206 207 func Valfmtv(v reflect.Value) string { 208 return Valfmt(&v) 209 } 210 211 func Valfmt(v *reflect.Value) string { 212 s := ValfmtPure(v) 213 if len(s) > maxValueStringLen { 214 return s[0:maxValueStringLen-3] + "..." 215 } 216 return s 217 } 218 219 func ValfmtPure(v *reflect.Value) string { 220 if v == nil || !v.IsValid() { 221 return "<invalid>" 222 } 223 if v.Kind() == reflect.Bool { 224 if v.Bool() { 225 return "true" 226 } 227 return "false" 228 } 229 if IsNil(*v) { 230 return "<nil>" 231 } 232 if IsZero(*v) { 233 return "<zero>" 234 } 235 if v.Kind() == reflect.String { 236 return v.String() 237 } 238 if HasStringer(v) { 239 res := v.MethodByName("String").Call(nil) 240 return res[0].String() 241 } 242 if IsNumericKind(v.Kind()) { 243 return fmt.Sprintf("%v", v.Interface()) 244 } 245 if CanConvert(v, StringType) { 246 return v.Convert(StringType).String() 247 } 248 if v.CanInterface() { 249 return fmt.Sprintf("%v", v.Interface()) 250 } 251 return fmt.Sprintf("<%v>", v.Kind()) 252 } 253 254 func Iserrortype(typ reflect.Type) bool { 255 return typ.Implements(errtyp) 256 } 257 258 var errtyp = reflect.TypeOf((*error)(nil)).Elem() 259 260 var stringerType = reflect.TypeOf((*interface{ String() string })(nil)).Elem() //nolint:gochecknoglobals //i know that 261 var StringType = reflect.TypeOf((*string)(nil)).Elem() //nolint:gochecknoglobals //i know that 262 var Niltyp = reflect.TypeOf((*string)(nil)) //nolint:gochecknoglobals //i know that 263 264 // IsZero for go1.12+, the difference is it never panic on unavailable kinds. 265 // see also reflect.IsZero. 266 func IsZero(v reflect.Value) (ret bool) { 267 return IsZerov(&v) 268 } 269 270 // IsZerov for go1.12+, the difference is it never panic on unavailable kinds. 271 // see also reflect.IsZero. 272 func IsZerov(v *reflect.Value) (ret bool) { 273 if v != nil { 274 switch k := v.Kind(); k { //nolint:exhaustive //others unlisted cases can be ignored 275 case reflect.Bool: 276 ret = !v.Bool() 277 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 278 ret = v.Int() == 0 279 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 280 ret = v.Uint() == 0 281 case reflect.Float32, reflect.Float64: 282 ret = math.Float64bits(v.Float()) == 0 283 case reflect.Complex64, reflect.Complex128: 284 c := v.Complex() 285 ret = math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0 286 case reflect.Slice: 287 ret = v.Len() == 0 288 case reflect.Array: 289 ret = ArrayIsZerov(v) 290 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.UnsafePointer: 291 ret = IsNilv(v) 292 case reflect.Struct: 293 ret = StructIsZerov(v) 294 case reflect.String: 295 ret = v.Len() == 0 296 } 297 } 298 return 299 } 300 301 func StructIsZero(v reflect.Value) bool { return StructIsZerov(&v) } 302 func StructIsZerov(v *reflect.Value) bool { 303 for i := 0; i < v.NumField(); i++ { 304 if !IsZero(v.Field(i)) { 305 return false 306 } 307 } 308 return true 309 } 310 311 func ArrayIsZero(v reflect.Value) bool { return ArrayIsZerov(&v) } 312 func ArrayIsZerov(v *reflect.Value) bool { 313 for i := 0; i < v.Len(); i++ { 314 if !IsZero(v.Index(i)) { 315 return false 316 } 317 } 318 return true 319 } 320 321 // IsNil for go1.12+, the difference is it never panic on unavailable kinds. 322 // see also reflect.IsNil. 323 func IsNil(v reflect.Value) bool { 324 return IsNilv(&v) 325 } 326 327 // IsNilv for go1.12+, the difference is it never panic on unavailable kinds. 328 // see also reflect.IsNil. 329 func IsNilv(v *reflect.Value) bool { 330 if v != nil { 331 switch k := v.Kind(); k { //nolint:exhaustive //no need 332 case reflect.Uintptr: 333 if v.CanAddr() { 334 return v.UnsafeAddr() == 0 // special: reflect.IsNil assumed nil check on an uintptr is illegal, faint! 335 } 336 case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr: 337 return v.IsNil() 338 case reflect.UnsafePointer: 339 return v.Pointer() == 0 // for go1.11, this is a workaround even not bad 340 case reflect.Interface, reflect.Slice: 341 return v.IsNil() 342 // case reflect.Array: 343 // // never true, for an array, it is never IsNil 344 // case reflect.String: 345 // case reflect.Struct: 346 } 347 } 348 return false 349 } 350 351 // func (v Value) IsNil() bool { 352 // k := v.kind() 353 // switch k { 354 // case Chan, Func, Map, Pointer, UnsafePointer: 355 // if v.flag&flagMethod != 0 { 356 // return false 357 // } 358 // ptr := v.ptr 359 // if v.flag&flagIndir != 0 { 360 // ptr = *(*unsafe.Pointer)(ptr) 361 // } 362 // return ptr == nil 363 // case Interface, Slice: 364 // // Both interface and slice are nil if first word is 0. 365 // // Both are always bigger than a word; assume flagIndir. 366 // return *(*unsafe.Pointer)(v.ptr) == nil 367 // } 368 // panic(&ValueError{"reflect.Value.IsNil", v.kind()}) 369 // } 370 371 // IsExported reports whether the field is exported. 372 func IsExported(f *reflect.StructField) bool { 373 return f.PkgPath == "" 374 } 375 376 // CanConvertHelper is a shorthand of CanConvert. 377 func CanConvertHelper(v reflect.Value, t reflect.Type) bool { 378 return CanConvert(&v, t) 379 } 380 381 // CanConvert reports whether the value v can be converted to type t. 382 // If v.CanConvert(t) returns true then v.Convert(t) will not panic. 383 func CanConvert(v *reflect.Value, t reflect.Type) bool { 384 if !v.IsValid() { 385 return false 386 } 387 388 vt := v.Type() 389 if !vt.ConvertibleTo(t) { 390 // Currently the only conversion that is OK in terms of type 391 // but that can panic depending on the value is converting 392 // from slice to pointer-to-array. 393 if vt.Kind() == reflect.Slice && t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Array { 394 n := t.Elem().Len() 395 type sliceHeader struct { 396 Data unsafe.Pointer 397 Len int 398 Cap int 399 } 400 h := (*sliceHeader)(unsafe.Pointer(v.Pointer())) 401 return n <= h.Len 402 } 403 404 return false 405 } 406 return true 407 } 408 409 func hasImplements(v *reflect.Value, interfaceType reflect.Type) bool { 410 vt := v.Type() 411 return vt.Implements(interfaceType) 412 } 413 414 func HasStringer(v *reflect.Value) bool { 415 return hasImplements(v, stringerType) 416 }