github.com/avicd/go-utilx@v0.1.0/refx/op.go (about)

     1  package refx
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/avicd/go-utilx/conv"
     6  	"github.com/avicd/go-utilx/logx"
     7  	"math/big"
     8  	"reflect"
     9  )
    10  
    11  const (
    12  	CmpNeq = -2
    13  	CmpLss = -1
    14  	CmpEq  = 0
    15  	CmpGtr = 1
    16  )
    17  
    18  func Zero() reflect.Value {
    19  	return reflect.Value{}
    20  }
    21  
    22  func ZeroOf(vl any) reflect.Value {
    23  	return reflect.New(TypeOf(vl)).Elem()
    24  }
    25  
    26  func ValueOf(vl any) reflect.Value {
    27  	switch tmp := vl.(type) {
    28  	case reflect.Value:
    29  		return tmp
    30  	case *reflect.Value:
    31  		return *tmp
    32  	default:
    33  		return reflect.ValueOf(vl)
    34  	}
    35  }
    36  
    37  func TypeOf(vl any) reflect.Type {
    38  	var value reflect.Value
    39  	switch tmp := vl.(type) {
    40  	case reflect.Type:
    41  		return tmp
    42  	case reflect.Value:
    43  		value = tmp
    44  	case *reflect.Value:
    45  		value = *tmp
    46  	}
    47  	if value.IsValid() {
    48  		return value.Type()
    49  	} else {
    50  		return reflect.TypeOf(vl)
    51  	}
    52  }
    53  
    54  func KindOf(vl any) reflect.Kind {
    55  	switch tmp := vl.(type) {
    56  	case reflect.Value:
    57  		return tmp.Kind()
    58  	case *reflect.Value:
    59  		return tmp.Kind()
    60  	case reflect.Type:
    61  		if tmp != nil {
    62  			return tmp.Kind()
    63  		} else {
    64  			return reflect.Invalid
    65  		}
    66  	default:
    67  		if tp := reflect.TypeOf(vl); tp != nil {
    68  			return tp.Kind()
    69  		}
    70  	}
    71  	return reflect.Invalid
    72  }
    73  
    74  func IndirectKind(val any) reflect.Kind {
    75  	if IsPointer(val) || IsInterface(val) {
    76  		switch tmp := val.(type) {
    77  		case reflect.Value:
    78  			return KindOf(IndirectType(tmp))
    79  		case *reflect.Value:
    80  			return KindOf(IndirectType(*tmp))
    81  		case reflect.Type:
    82  			return KindOf(IndirectType(tmp))
    83  		default:
    84  			return KindOf(IndirectType(val))
    85  		}
    86  	}
    87  	return KindOf(val)
    88  }
    89  
    90  func Indirect(vl any) reflect.Value {
    91  	buf := ValueOf(vl)
    92  	for buf.Kind() == reflect.Pointer || buf.Kind() == reflect.Interface {
    93  		buf = buf.Elem()
    94  	}
    95  	return buf
    96  }
    97  
    98  func IndirectType(vl any) reflect.Type {
    99  	buf := TypeOf(vl)
   100  	for buf != nil {
   101  		if buf.Kind() == reflect.Pointer {
   102  			buf = buf.Elem()
   103  		} else {
   104  			break
   105  		}
   106  	}
   107  	return buf
   108  }
   109  
   110  func NewOf(vl any) reflect.Value {
   111  	target := TypeOf(vl)
   112  	if IsInvalid(target) {
   113  		return Zero()
   114  	}
   115  	if target.Kind() == reflect.Pointer {
   116  		p := reflect.New(target)
   117  		p.Elem().Set(NewOf(target.Elem()).Addr())
   118  		return p.Elem()
   119  	} else if target.Kind() == reflect.Map {
   120  		return reflect.MakeMap(target)
   121  	} else {
   122  		return reflect.New(target).Elem()
   123  	}
   124  }
   125  
   126  func AddrAbleOf(vl any) (reflect.Value, bool) {
   127  	buf := ValueOf(vl)
   128  	for (IsPointer(buf) || IsInterface(buf)) && !buf.CanAddr() {
   129  		buf = buf.Elem()
   130  	}
   131  	if buf.CanAddr() {
   132  		return buf, true
   133  	}
   134  	return reflect.Value{}, false
   135  }
   136  
   137  func Assign(dest any, vl any) bool {
   138  	target, ok := AddrAbleOf(dest)
   139  	if ok {
   140  		target.Set(NewOf(target))
   141  	} else {
   142  		logx.Fatal("dest is unaddressable")
   143  	}
   144  	if IsNil(vl) {
   145  		return false
   146  	}
   147  	value := ValueOf(vl)
   148  	if IsPointer(target) {
   149  		if target.Type() == value.Type() {
   150  			target.Set(value)
   151  			return true
   152  		} else if target.Type().Elem() == value.Type() {
   153  			buf := NewOf(target)
   154  			buf.Elem().Set(value)
   155  			target.Set(buf)
   156  			return true
   157  		}
   158  	} else if IsInterface(target) {
   159  		if IsPointer(value) {
   160  			if value.CanConvert(TypeOf(target.Type())) {
   161  				target.Set(value)
   162  				return true
   163  			}
   164  		} else {
   165  			pointer := reflect.New(TypeOf(value))
   166  			if pointer.CanConvert(target.Type()) {
   167  				pointer.Elem().Set(value)
   168  				target.Set(pointer)
   169  				return true
   170  			}
   171  		}
   172  	}
   173  	el := Indirect(value)
   174  	if target.Type() == el.Type() {
   175  		target.Set(el)
   176  		return true
   177  	}
   178  	failed := false
   179  	if IsNumber(target) {
   180  		if IsString(el) {
   181  			if IsGeneralInt(target) {
   182  				num := conv.ParseInt(el.String())
   183  				if target.CanInt() {
   184  					target.SetInt(num)
   185  				} else {
   186  					target.SetUint(uint64(num))
   187  				}
   188  			} else {
   189  				target.SetFloat(conv.ParseFloat(el.String()))
   190  			}
   191  			return true
   192  		}
   193  
   194  		if target.CanInt() {
   195  			if el.CanInt() {
   196  				target.SetInt(el.Int())
   197  			} else if el.CanUint() {
   198  				target.SetInt(int64(el.Uint()))
   199  			} else if el.CanFloat() {
   200  				target.SetInt(int64(el.Float()))
   201  			} else {
   202  				failed = true
   203  			}
   204  		} else if target.CanUint() {
   205  			if el.CanUint() {
   206  				target.SetUint(el.Uint())
   207  			} else if el.CanInt() {
   208  				target.SetUint(uint64(el.Int()))
   209  			} else if el.CanFloat() {
   210  				target.SetUint(uint64(el.Float()))
   211  			} else {
   212  				failed = true
   213  			}
   214  		} else if target.CanFloat() {
   215  			if el.CanFloat() {
   216  				target.SetFloat(el.Float())
   217  			} else if el.CanInt() {
   218  				target.SetFloat(float64(el.Int()))
   219  			} else if el.CanUint() {
   220  				target.SetFloat(float64(el.Uint()))
   221  			} else {
   222  				failed = true
   223  			}
   224  		}
   225  	} else if IsString(target) {
   226  		if IsString(el) {
   227  			target.SetString(el.String())
   228  		} else {
   229  			target.SetString(fmt.Sprintf("%v", vl))
   230  		}
   231  	} else if IsBool(target) {
   232  		if IsBool(el) {
   233  			target.SetBool(el.Bool())
   234  		} else {
   235  			target.SetBool(!el.IsZero())
   236  		}
   237  	} else {
   238  		failed = true
   239  	}
   240  	if failed {
   241  		logx.Fatalf("can't assign %s to %s", TypeOf(vl), TypeOf(dest))
   242  	}
   243  	return true
   244  }
   245  
   246  func Clone(dest any, src any) {
   247  	var target reflect.Value
   248  	if buf, ok := AddrAbleOf(dest); ok {
   249  		buf.Set(NewOf(buf))
   250  		target = Indirect(buf)
   251  	} else {
   252  		logx.Fatal("dest is unaddressable")
   253  	}
   254  	el := Indirect(src)
   255  	if IsNil(el) {
   256  		return
   257  	}
   258  	if el.Type() != target.Type() {
   259  		logx.Fatalf("can't clone %s into %s", el.Type(), target.Type())
   260  	}
   261  	if IsBasic(target) {
   262  		target.Set(el)
   263  		return
   264  	}
   265  	switch el.Kind() {
   266  	case reflect.Slice, reflect.Array:
   267  		for i := 0; i < el.Len(); i++ {
   268  			sf := el.Index(i)
   269  			if !IsBasic(sf) {
   270  				newVal := NewOf(el.Type().Elem())
   271  				Clone(newVal.Addr(), sf)
   272  				sf = newVal
   273  			}
   274  			newTarget := reflect.Append(target, sf)
   275  			target.Set(newTarget)
   276  		}
   277  	case reflect.Struct:
   278  		for i := 0; i < el.Type().NumField(); i++ {
   279  			tf := el.Type().Field(i)
   280  			if !tf.IsExported() {
   281  				continue
   282  			}
   283  			sf := el.Field(i)
   284  			if !IsBasic(tf.Type) {
   285  				target.Field(i).Set(sf)
   286  			} else {
   287  				newVal := NewOf(tf.Type)
   288  				Clone(newVal.Addr(), sf)
   289  				sf = newVal
   290  			}
   291  			target.Field(i).Set(sf)
   292  		}
   293  	case reflect.Map:
   294  		for itr := el.MapRange(); itr.Next(); {
   295  			sf := itr.Value()
   296  			if IsBasic(sf) {
   297  				target.SetMapIndex(itr.Key(), sf)
   298  			} else {
   299  				var newVal reflect.Value
   300  				if IsInterface(el.Type().Elem()) {
   301  					newVal = NewOf(sf.Elem())
   302  				} else {
   303  					newVal = NewOf(el.Type().Elem())
   304  				}
   305  				Clone(newVal.Addr(), sf)
   306  				target.SetMapIndex(itr.Key(), newVal)
   307  			}
   308  		}
   309  	}
   310  }
   311  
   312  func Merge(dest any, src any) {
   313  	if IsNil(src) {
   314  		return
   315  	}
   316  	to := Indirect(dest)
   317  	if IsBasic(to) || IsList(to) || IsNil(to) {
   318  		if target, ok := AddrAbleOf(dest); ok {
   319  			if IsNil(target) {
   320  				target.Set(NewOf(target))
   321  			}
   322  			to = Indirect(target)
   323  		} else {
   324  			logx.Fatal("dest is unaddressable")
   325  		}
   326  	}
   327  	from := Indirect(src)
   328  
   329  	if !IsList(to) && !IsList(from) && to.Type() != from.Type() {
   330  		logx.Fatalf("can't merge %s into %s", TypeOf(src), TypeOf(dest))
   331  	}
   332  	switch to.Kind() {
   333  	case reflect.Slice:
   334  		buf := NewOf(to)
   335  		buf.Set(to)
   336  		for i := 0; i < from.Len(); i++ {
   337  			sf := from.Index(i)
   338  			buf = reflect.Append(buf, sf)
   339  		}
   340  		to.Set(buf)
   341  	case reflect.Array:
   342  		for i := 0; i < from.Len() && i < to.Len(); i++ {
   343  			sf := from.Index(i)
   344  			if IsInterface(sf) {
   345  				sf = sf.Elem()
   346  			}
   347  			if !sf.IsZero() {
   348  				to.Index(i).Set(sf)
   349  			}
   350  		}
   351  	case reflect.Struct:
   352  		for i := 0; i < from.Type().NumField(); i++ {
   353  			tf := from.Type().Field(i)
   354  			if !tf.IsExported() {
   355  				continue
   356  			}
   357  			left := to.Field(i)
   358  			right := from.Field(i)
   359  			if IsBasic(tf.Type) {
   360  				if right.IsValid() && !right.IsZero() {
   361  					left.Set(right)
   362  				}
   363  			} else if !right.IsZero() {
   364  				if IsNil(left) {
   365  					left.Set(NewOf(tf.Type))
   366  				}
   367  				Merge(left.Addr(), right)
   368  			}
   369  		}
   370  	case reflect.Map:
   371  		for itr := from.MapRange(); itr.Next(); {
   372  			left := to.MapIndex(itr.Key())
   373  			right := itr.Value()
   374  			if IsInterface(left) {
   375  				left = left.Elem()
   376  			}
   377  			if IsInterface(right) {
   378  				right = right.Elem()
   379  			}
   380  			if left.IsValid() {
   381  				if !IsBasic(left) && left.Type() == right.Type() {
   382  					var newVal reflect.Value
   383  					if IsInterface(from.Type().Elem()) {
   384  						newVal = NewOf(left)
   385  					} else {
   386  						newVal = NewOf(from.Type().Elem())
   387  					}
   388  					newVal.Set(left)
   389  					Merge(newVal.Addr(), right)
   390  					to.SetMapIndex(itr.Key(), newVal)
   391  				} else if !right.IsZero() {
   392  					to.SetMapIndex(itr.Key(), right)
   393  				}
   394  			} else {
   395  				to.SetMapIndex(itr.Key(), right)
   396  			}
   397  		}
   398  	default:
   399  		if !from.IsZero() {
   400  			to.Set(from)
   401  		}
   402  	}
   403  }
   404  
   405  func FieldOf(src any, props ...any) (reflect.Value, bool) {
   406  	vl := ValueOf(src)
   407  	if IsBasic(vl) || len(props) < 1 || IsNil(vl) {
   408  		return Zero(), false
   409  	}
   410  	buf := vl
   411  	for _, key := range props {
   412  		el := Indirect(buf)
   413  		switch el.Kind() {
   414  		case reflect.Map:
   415  			index := AsOf(el.Type().Key(), key)
   416  			buf = el.MapIndex(index)
   417  			if IsInterface(buf) {
   418  				buf = buf.Elem()
   419  			}
   420  		case reflect.Struct:
   421  			name := AsString(key)
   422  			if sf, ok := el.Type().FieldByName(name); ok && sf.IsExported() {
   423  				buf = el.FieldByName(name)
   424  			} else {
   425  				return Zero(), false
   426  			}
   427  		case reflect.Slice, reflect.Array:
   428  			index := AsInt(key)
   429  			if index >= 0 && index < el.Len() {
   430  				buf = el.Index(index)
   431  			} else {
   432  				return Zero(), false
   433  			}
   434  		default:
   435  			return Zero(), false
   436  		}
   437  		if !buf.IsValid() || !buf.CanInterface() {
   438  			return Zero(), false
   439  		}
   440  	}
   441  	return buf, true
   442  }
   443  
   444  func TypeOfField(vl any, props ...any) (reflect.Type, bool) {
   445  	if _, ok := vl.(reflect.Type); !ok && !IsNil(vl) {
   446  		if sf, exist := FieldOf(vl, props...); exist {
   447  			return TypeOf(sf), true
   448  		}
   449  	}
   450  	buf := TypeOf(vl)
   451  	if len(props) < 1 || buf == nil {
   452  		return nil, false
   453  	}
   454  	for _, key := range props {
   455  		buf = IndirectType(buf)
   456  		switch buf.Kind() {
   457  		case reflect.Struct:
   458  			name := AsString(key)
   459  			if sf, ok := buf.FieldByName(name); ok {
   460  				buf = sf.Type
   461  			} else {
   462  				return nil, false
   463  			}
   464  		case reflect.Array, reflect.Slice, reflect.Map:
   465  			buf = buf.Elem()
   466  		default:
   467  			return nil, false
   468  		}
   469  	}
   470  	return buf, true
   471  }
   472  
   473  func TypeOfId(vl any, ident string) (reflect.Type, bool) {
   474  	props := AsList(conv.StrToArr(ident, "."))
   475  	return TypeOfField(vl, props...)
   476  }
   477  
   478  func PropOf(src any, props ...any) (any, bool) {
   479  	vl := ValueOf(src)
   480  	if IsBasic(vl) || len(props) < 1 || IsNil(vl) {
   481  		return nil, false
   482  	}
   483  	if value, ok := FieldOf(vl, props...); ok {
   484  		return value.Interface(), true
   485  	} else {
   486  		return nil, false
   487  	}
   488  }
   489  
   490  func PropOfId(src any, ident string) (any, bool) {
   491  	if IsBasic(src) || IsNil(src) {
   492  		return nil, false
   493  	}
   494  	props := AsList(conv.StrToArr(ident, "."))
   495  	if val, ok := PropOf(src, props...); ok {
   496  		return val, true
   497  	} else if IsMap(src) && len(props) > 1 {
   498  		return PropOf(src, ident)
   499  	} else {
   500  		return nil, false
   501  	}
   502  }
   503  
   504  func Set(dest any, vl any, props ...any) bool {
   505  	if IsBasic(dest) {
   506  		return Assign(dest, vl)
   507  	}
   508  	value := ValueOf(vl)
   509  	buf := Indirect(dest)
   510  	if IsNil(buf) || IsArray(dest) {
   511  		if target, ok := AddrAbleOf(dest); !ok {
   512  			logx.Fatal("dest is unaddressable")
   513  		} else {
   514  			buf = target
   515  		}
   516  	}
   517  	for i, key := range props {
   518  		if IsNil(buf) {
   519  			buf.Set(NewOf(buf))
   520  		}
   521  		el := Indirect(buf)
   522  		switch el.Kind() {
   523  		case reflect.Map:
   524  			index := AsOf(el.Type().Key(), key)
   525  			buf = el.MapIndex(index)
   526  			if len(props)-i > 1 {
   527  				if !buf.IsValid() {
   528  					if IsInterface(el.Type().Elem()) {
   529  						next := props[i+1]
   530  						if IsNumber(next) || IsString(next) {
   531  							buf = NewOf(TMapStrAny)
   532  						} else {
   533  							buf = NewOf(reflect.MapOf(TypeOf(next), el.Type().Elem()))
   534  						}
   535  					} else {
   536  						buf = NewOf(el.Type().Elem())
   537  					}
   538  					el.SetMapIndex(index, buf)
   539  					continue
   540  				}
   541  			} else {
   542  				el.SetMapIndex(index, value)
   543  				break
   544  			}
   545  		case reflect.Struct:
   546  			name := AsString(key)
   547  			if tf, ok := el.Type().FieldByName(name); ok && tf.IsExported() {
   548  				buf = el.FieldByName(name)
   549  				if IsPointer(buf) && buf.IsNil() {
   550  					buf.Set(NewOf(tf.Type))
   551  				}
   552  			} else {
   553  				return false
   554  			}
   555  		case reflect.Slice, reflect.Array:
   556  			index := AsInt(key)
   557  			if index >= 0 && index < el.Len() {
   558  				buf = el.Index(index)
   559  			} else {
   560  				return false
   561  			}
   562  		}
   563  		if i == len(props)-1 {
   564  			if buf.IsValid() {
   565  				Assign(buf.Addr(), value)
   566  			} else {
   567  				return false
   568  			}
   569  		}
   570  	}
   571  	return true
   572  }
   573  
   574  func SetById(dest any, vl any, ident string) bool {
   575  	props := AsList(conv.StrToArr(ident, "."))
   576  	if ok := Set(dest, vl, props...); ok {
   577  		return true
   578  	} else if IsMap(dest) && len(props) > 1 {
   579  		return Set(dest, vl, ident)
   580  	} else {
   581  		return false
   582  	}
   583  }
   584  
   585  func MethodOf(target any, props ...any) (reflect.Value, bool) {
   586  	vl := ValueOf(target)
   587  	if !vl.IsValid() || IsBasic(vl) || len(props) < 1 {
   588  		return Zero(), false
   589  	}
   590  	owner := vl
   591  	level := len(props)
   592  	if level > 1 {
   593  		if sf, ok := FieldOf(owner, props[:level-1]...); ok {
   594  			owner = sf
   595  		} else {
   596  			return Zero(), false
   597  		}
   598  	}
   599  	name := AsString(props[level-1])
   600  	method := owner.MethodByName(name)
   601  	if method.IsValid() && method.CanInterface() {
   602  		return method, true
   603  	}
   604  	return Zero(), false
   605  }
   606  
   607  func MethodOfId(target any, ident string) (reflect.Value, bool) {
   608  	props := AsList(conv.StrToArr(ident, "."))
   609  	return MethodOf(target, props...)
   610  }
   611  
   612  func ForEach(target any, fn func(key any, val any)) {
   613  	if IsBasic(target) || IsNil(target) {
   614  		return
   615  	}
   616  	vl := ValueOf(target)
   617  	el := Indirect(vl)
   618  	switch el.Kind() {
   619  	case reflect.Map:
   620  		for itr := el.MapRange(); itr.Next(); {
   621  			fn(itr.Key().Interface(), itr.Value().Interface())
   622  		}
   623  	case reflect.Slice, reflect.Array:
   624  		for i := 0; i < el.Len(); i++ {
   625  			fn(i, el.Index(i).Interface())
   626  		}
   627  	case reflect.Struct:
   628  		for i := 0; i < el.Type().NumField(); i++ {
   629  			tf := el.Type().Field(i)
   630  			field := el.Field(i)
   631  			if !tf.IsExported() {
   632  				continue
   633  			}
   634  			fn(tf.Name, field.Interface())
   635  		}
   636  	}
   637  }
   638  
   639  func Cmp(x any, y any) int {
   640  	if IsNumber(x) && IsNumber(y) {
   641  		return big.NewFloat(AsFloat64(x)).Cmp(big.NewFloat(AsFloat64(y)))
   642  	} else if IsString(x) && IsString(y) {
   643  		str1 := AsString(x)
   644  		str2 := AsString(y)
   645  		if str1 == str2 {
   646  			return CmpEq
   647  		} else if str1 > str2 {
   648  			return CmpGtr
   649  		} else {
   650  			return CmpLss
   651  		}
   652  	} else if reflect.DeepEqual(x, y) {
   653  		return CmpEq
   654  	}
   655  	return CmpNeq
   656  }