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  }