github.com/Aoi-hosizora/ahlib@v1.5.1-0.20230404072829-241b93cf91c7/xreflect/xreflect.go (about)

     1  package xreflect
     2  
     3  import (
     4  	"math"
     5  	"reflect"
     6  	"unsafe"
     7  )
     8  
     9  // ====================
    10  // kind checker related
    11  // ====================
    12  
    13  // IsIntKind checks whether given reflect.Kind represents integers or not.
    14  func IsIntKind(kind reflect.Kind) bool {
    15  	return kind == reflect.Int || kind == reflect.Int8 || kind == reflect.Int16 || kind == reflect.Int32 || kind == reflect.Int64
    16  }
    17  
    18  // IsUintKind checks whether given reflect.Kind represents unsigned integers or not.
    19  func IsUintKind(kind reflect.Kind) bool {
    20  	return kind == reflect.Uint || kind == reflect.Uint8 || kind == reflect.Uint16 || kind == reflect.Uint32 || kind == reflect.Uint64 || kind == reflect.Uintptr
    21  }
    22  
    23  // IsFloatKind checks whether given reflect.Kind represents floating points or not.
    24  func IsFloatKind(kind reflect.Kind) bool {
    25  	return kind == reflect.Float32 || kind == reflect.Float64
    26  }
    27  
    28  // IsComplexKind checks whether given reflect.Kind represents complex numerics or not.
    29  func IsComplexKind(kind reflect.Kind) bool {
    30  	return kind == reflect.Complex64 || kind == reflect.Complex128
    31  }
    32  
    33  // IsNumericKind checks whether given reflect.Kind represents numerics or not.
    34  //
    35  // Numeric types: integers, unsigned integers, floating points, complex numerics.
    36  func IsNumericKind(kind reflect.Kind) bool {
    37  	return kind == reflect.Int || kind == reflect.Int8 || kind == reflect.Int16 || kind == reflect.Int32 || kind == reflect.Int64 ||
    38  		kind == reflect.Uint || kind == reflect.Uint8 || kind == reflect.Uint16 || kind == reflect.Uint32 || kind == reflect.Uint64 || kind == reflect.Uintptr ||
    39  		kind == reflect.Float32 || kind == reflect.Float64 || kind == reflect.Complex64 || kind == reflect.Complex128
    40  }
    41  
    42  // IsCollectionKind checks whether given reflect.Kind represents collections or not, whose related reflect.Value's ``Len()'' method is invokable.
    43  //
    44  // Collection types: string, array, slice, map, chan.
    45  func IsCollectionKind(kind reflect.Kind) bool {
    46  	return kind == reflect.String || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan
    47  }
    48  
    49  // IsNillableKind checks whether given reflect.Kind represents nillable types or not, whose related reflect.Value's ``IsNil()'' method is invokable.
    50  //
    51  // Nillable types: ptr, func, interface, unsafePtr, slice, map, chan.
    52  func IsNillableKind(kind reflect.Kind) bool {
    53  	return kind == reflect.Ptr || kind == reflect.Func || kind == reflect.Interface || kind == reflect.UnsafePointer ||
    54  		kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan
    55  }
    56  
    57  // IsSlicableKind checks whether given reflect.Kind represents slice invokable types or not, whose related reflect.Value's ``Slice()'' and ``Index()'' methods are invokable.
    58  //
    59  // Slicable types: slice, array, string.
    60  func IsSlicableKind(kind reflect.Kind) bool {
    61  	return kind == reflect.Slice || kind == reflect.Array || kind == reflect.String
    62  }
    63  
    64  // IsPointerableKind checks whether given reflect.Kind represents pointer gettable types or not, whose related reflect.Value's ``Pointer()'' and ``UnsafePointer()'' methods are invokable.
    65  // Note that these two methods can not be called on string and interface reflect.Value.
    66  //
    67  // Pointerable types: ptr, func, unsafePtr, slice, map, chan.
    68  func IsPointerableKind(kind reflect.Kind) bool {
    69  	return kind == reflect.Ptr || kind == reflect.Func || kind == reflect.UnsafePointer ||
    70  		kind == reflect.Slice || kind == reflect.Map || kind == reflect.Chan
    71  }
    72  
    73  // =====================
    74  // value checker related
    75  // =====================
    76  
    77  // IsNilValue checks whether given value is nil in its type or not. Note that this will also check the wrapped data of given interface{}.
    78  func IsNilValue(v interface{}) bool {
    79  	if v == nil {
    80  		return true
    81  	}
    82  	val := reflect.ValueOf(v)
    83  	switch val.Kind() {
    84  	case reflect.Ptr, reflect.Func, reflect.Interface, reflect.UnsafePointer, reflect.Slice, reflect.Map, reflect.Chan:
    85  		return val.IsNil()
    86  	}
    87  	return false
    88  }
    89  
    90  // IsZeroValue checks whether given value is the zero value of its type or not. Note that all non-nil nillable collection values (such as empty []int{}
    91  // and map[string]int{}) are regarded as not zero.
    92  func IsZeroValue(v interface{}) bool {
    93  	if v == nil {
    94  		return true
    95  	}
    96  	zero := reflect.Zero(reflect.TypeOf(v)).Interface()
    97  	return reflect.DeepEqual(v, zero)
    98  	// return reflect.ValueOf(v).IsZero()
    99  }
   100  
   101  // IsEmptyCollection checks whether given collection value is empty or not. Note that empty means its value is nil or its length is zero.
   102  func IsEmptyCollection(v interface{}) bool {
   103  	val := reflect.ValueOf(v)
   104  	switch val.Kind() {
   105  	case reflect.String, reflect.Array, reflect.Slice, reflect.Map, reflect.Chan:
   106  		return val.Len() == 0 // call val.Len() directly without unnecessary val.IsNil()
   107  	}
   108  	return false // including reflect.Invalid
   109  }
   110  
   111  // IsEmptyValue checks whether given value is empty or not. Note that empty means zero value, nil value, zero item and zero field, and this works
   112  // almost the same as json.isEmptyValue for "omitempty".
   113  func IsEmptyValue(v interface{}) bool {
   114  	val := reflect.ValueOf(v)
   115  	switch val.Kind() {
   116  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   117  		return val.Int() == 0
   118  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   119  		return val.Uint() == 0
   120  	case reflect.Float32, reflect.Float64:
   121  		f := val.Float()
   122  		return math.Float64bits(f) == 0
   123  	case reflect.Complex64, reflect.Complex128:
   124  		c := val.Complex()
   125  		return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
   126  	case reflect.Bool:
   127  		return !val.Bool()
   128  	case reflect.String, reflect.Array, reflect.Slice, reflect.Map, reflect.Chan:
   129  		return val.Len() == 0 // => val.IsNil() || val.Len() == 0, do not check fields recursively
   130  	case reflect.Interface, reflect.Ptr, reflect.UnsafePointer, reflect.Func:
   131  		return val.IsNil()
   132  	case reflect.Struct:
   133  		return val.NumField() == 0 // do not check fields recursively (different with val.Zero())
   134  	default:
   135  		// reflect.Invalid, that is untyped "nil"
   136  		return true
   137  	}
   138  }
   139  
   140  // =====================
   141  // numeric value related
   142  // =====================
   143  
   144  // Float64Value returns the float64 value for given numeric value, returns false if given value is not numeric value.
   145  func Float64Value(v interface{}) (float64, bool) {
   146  	switch vv := v.(type) {
   147  	case int:
   148  		return float64(vv), true
   149  	case int8:
   150  		return float64(vv), true
   151  	case int16:
   152  		return float64(vv), true
   153  	case int32:
   154  		return float64(vv), true
   155  	case int64:
   156  		return float64(vv), true
   157  	case uint:
   158  		return float64(vv), true
   159  	case uint8:
   160  		return float64(vv), true
   161  	case uint16:
   162  		return float64(vv), true
   163  	case uint32:
   164  		return float64(vv), true
   165  	case uint64:
   166  		return float64(vv), true
   167  	case uintptr:
   168  		return float64(vv), true
   169  	case float32:
   170  		return float64(vv), true
   171  	case float64:
   172  		return vv, true
   173  	}
   174  	return 0, false
   175  }
   176  
   177  // Uint64Value returns the uint64 value for given numeric value, returns false if given value is not numeric value.
   178  func Uint64Value(v interface{}) (uint64, bool) {
   179  	switch vv := v.(type) {
   180  	case int:
   181  		return uint64(vv), true
   182  	case int8:
   183  		return uint64(vv), true
   184  	case int16:
   185  		return uint64(vv), true
   186  	case int32:
   187  		return uint64(vv), true
   188  	case int64:
   189  		return uint64(vv), true
   190  	case uint:
   191  		return uint64(vv), true
   192  	case uint8:
   193  		return uint64(vv), true
   194  	case uint16:
   195  		return uint64(vv), true
   196  	case uint32:
   197  		return uint64(vv), true
   198  	case uint64:
   199  		return vv, true
   200  	case uintptr:
   201  		return uint64(vv), true
   202  	case float32:
   203  		return uint64(vv), true
   204  	case float64:
   205  		return uint64(vv), true
   206  	}
   207  	return 0, false
   208  }
   209  
   210  // ========================
   211  // unexported field related
   212  // ========================
   213  
   214  // GetUnexportedField gets the reflect.Value of unexported struct field's. Note that this is an unsafe function.
   215  //
   216  // Example:
   217  // 	GetUnexportedField(reflect.ValueOf(app).Elem().FieldByName("noMethod")).Interface().(gin.HandlersChain)             // (*app).noMethod is a gin.HandlersChain
   218  // 	GetUnexportedField(FieldValueOf(app, "noMethod")).Interface().(gin.HandlersChain)                                   // <- or in this way
   219  // 	GetUnexportedField(reflect.ValueOf(trans).Elem().FieldByName("translations")).MapIndex(reflect.ValueOf("required")) // (*trans).translations is a map[string]xxx
   220  // 	GetUnexportedField(FieldValueOf(trans, "translations")).Interface().(gin.HandlersChain)                             // <- or in this way
   221  func GetUnexportedField(field reflect.Value) reflect.Value {
   222  	return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem()
   223  }
   224  
   225  // SetUnexportedField sets reflect.Value to unexported struct field. Note that this is an unsafe function.
   226  //
   227  // Example:
   228  // 	SetUnexportedField(reflect.ValueOf(ctx).Elem().FieldByName("fullPath"), reflect.ValueOf(newFullPath)) // (*ctx).fullPath and newFullPath is a string
   229  // 	SetUnexportedField(FieldValueOf(ctx, "fullPath"), reflect.ValueOf(newFullPath))                       // <- or in this way
   230  // 	SetUnexportedField(reflect.ValueOf(val).Elem().FieldByName("tagNameFunc"), reflect.ValueOf(nilFunc))  // (*val).tagNameFunc and nilFunc is a func
   231  // 	SetUnexportedField(FieldValueOf(val, "tagNameFunc"), reflect.ValueOf(newFullPath))                    // <- or in this way
   232  func SetUnexportedField(field reflect.Value, value reflect.Value) {
   233  	reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Set(value)
   234  }
   235  
   236  const (
   237  	panicNilInterface           = "xreflect: nil interface"
   238  	panicNilPtr                 = "xreflect: nil pointer"
   239  	panicNonStructOrPtrOfStruct = "xreflect: not a struct or pointers of struct"
   240  	panicNonexistentField       = "xreflect: nonexistent struct field"
   241  )
   242  
   243  // FieldValueOf returns the reflect.Value of specific struct field from given struct or pointers of struct.
   244  //
   245  // Example:
   246  // 	FieldValueOf(app, "noMethod")       // equals to reflect.ValueOf(app)[.Elem()*].FieldByName("noMethod")
   247  // 	FieldValueOf(trans, "translations") // equals to reflect.ValueOf(trans)[.Elem()*].FieldByName("translations")
   248  func FieldValueOf(v interface{}, name string) reflect.Value {
   249  	if v == nil {
   250  		panic(panicNilInterface)
   251  	}
   252  	val := reflect.ValueOf(v)
   253  	for val.Kind() == reflect.Ptr && !val.IsNil() {
   254  		val = val.Elem()
   255  	}
   256  
   257  	if val.Kind() == reflect.Ptr && val.IsNil() {
   258  		panic(panicNilPtr)
   259  	}
   260  	if val.Kind() != reflect.Struct {
   261  		panic(panicNonStructOrPtrOfStruct)
   262  	}
   263  	fval := val.FieldByName(name)
   264  	if !fval.IsValid() { // not existed
   265  		panic(panicNonexistentField)
   266  	}
   267  	return fval
   268  }
   269  
   270  // Attention:
   271  //
   272  // 1. For searching function by name, please refer to https://github.com/alangpierce/go-forceexport/blob/8f1d6941cd/forceexport.go#L10-L22
   273  // and http://www.alangpierce.com/blog/2016/03/17/adventures-in-go-accessing-unexported-functions.
   274  //
   275  // 2. For calling unexported struct methods, please refer to https://github.com/spance/go-callprivate/blob/d8b9b55236/examples.go#L20-L22.
   276  
   277  // ==============
   278  // mass functions
   279  // ==============
   280  
   281  // eface keeps the same as runtime.eface, which is the internal representation of interface{}.
   282  type eface struct {
   283  	_type uintptr // *runtime._type
   284  	data  unsafe.Pointer
   285  }
   286  
   287  // HasZeroEface checks whether given interface value has no type information or wrapped data (more than `== nil`). Note that this is an unsafe function.
   288  func HasZeroEface(v interface{}) bool {
   289  	e := (*eface)(unsafe.Pointer(&v))
   290  	return e._type == 0 || uintptr(e.data) == 0
   291  }
   292  
   293  // DeepEqualInValue checks whether given two values are deeply equal without considering their types. Note that the only different between this function and
   294  // reflect.DeepEqual is: this function checks by checking type convertable and comparing after type conversion.
   295  func DeepEqualInValue(v1, v2 interface{}) bool {
   296  	if reflect.DeepEqual(v1, v2) {
   297  		return true
   298  	}
   299  	val1, val2 := reflect.ValueOf(v1), reflect.ValueOf(v2)
   300  	if !val1.IsValid() || !val2.IsValid() {
   301  		return false
   302  	}
   303  
   304  	// check convertable, and compare after type conversion
   305  	type1, type2 := val1.Type(), val2.Type()
   306  	if type1.ConvertibleTo(type2) {
   307  		return reflect.DeepEqual(val1.Convert(type2).Interface(), v2)
   308  	}
   309  	if type2.ConvertibleTo(type1) {
   310  		return reflect.DeepEqual(v1, val2.Convert(type1).Interface())
   311  	}
   312  	return false // not equal
   313  }
   314  
   315  // SameUnderlyingPointer checks whether given two values can get underlying pointer, and whether their underlying pointers point to the same address.
   316  func SameUnderlyingPointer(p1, p2 interface{}) bool {
   317  	val1, val2 := reflect.ValueOf(p1), reflect.ValueOf(p2)
   318  	if !IsPointerableKind(val1.Kind()) || !IsPointerableKind(val2.Kind()) {
   319  		return false
   320  	}
   321  
   322  	// compare the underlying pointers of two values
   323  	return val1.Pointer() == val2.Pointer()
   324  }
   325  
   326  // SameUnderlyingPointerWithType checks whether given two values can get underlying pointer, and whether they have the same typ, and their underlying pointers
   327  // point to the same address.
   328  func SameUnderlyingPointerWithType(p1, p2 interface{}) bool {
   329  	return SameUnderlyingPointerWithTypeAndKind(p1, p2, 999)
   330  }
   331  
   332  // SameUnderlyingPointerWithTypeAndKind checks whether given two values can get underlying pointer, and whether they have the same type and match given kind,
   333  // and their underlying pointers point to the same address.
   334  func SameUnderlyingPointerWithTypeAndKind(p1, p2 interface{}, kind reflect.Kind) bool {
   335  	val1, val2 := reflect.ValueOf(p1), reflect.ValueOf(p2)
   336  	if !IsPointerableKind(val1.Kind()) || !IsPointerableKind(val2.Kind()) {
   337  		return false
   338  	}
   339  
   340  	if val1.Type() != val2.Type() {
   341  		return false
   342  	}
   343  	if kind <= reflect.UnsafePointer /* `> 26` => DO check kind */ && (val1.Kind() != kind || val2.Kind() != kind) {
   344  		return false
   345  	}
   346  
   347  	// compare the underlying pointers of two values
   348  	return val1.Pointer() == val2.Pointer()
   349  }
   350  
   351  const (
   352  	panicNonNilMap = "xreflect: not a non-nil map"
   353  )
   354  
   355  // hmap keeps the same as runtime.hmap, which represents a header for a Go map.
   356  type hmap struct {
   357  	count int
   358  	flags uint8
   359  	B     uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
   360  	// ...
   361  }
   362  
   363  // GetMapB returns the B value from given map value. Note that this is an unsafe function, and returned value may differ in different Go versions.
   364  func GetMapB(m interface{}) (b uint8) {
   365  	if m == nil {
   366  		panic(panicNonNilMap)
   367  	}
   368  	val := reflect.ValueOf(m)
   369  	if val.Kind() != reflect.Map || val.IsNil() {
   370  		panic(panicNonNilMap)
   371  	}
   372  
   373  	// https://hackernoon.com/some-insights-on-maps-in-golang-rm5v3ywh
   374  	e := (*eface)(unsafe.Pointer(&m))
   375  	h := (*hmap)(e.data)
   376  	return h.B
   377  }
   378  
   379  // GetMapBuckets returns the B value and the buckets count from given map value. Note that this is an unsafe function, and returned value may
   380  // differ in different Go versions.
   381  func GetMapBuckets(m interface{}) (b uint8, buckets uint64) {
   382  	b = GetMapB(m)
   383  	buckets = uint64(math.Pow(2, float64(b))) // 2^B
   384  	return b, buckets
   385  }