github.com/hedzr/evendeep@v0.4.8/cvts_tool.go (about)

     1  package evendeep
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"math"
     7  	"reflect"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/hedzr/evendeep/dbglog"
    12  	"github.com/hedzr/evendeep/internal/cl"
    13  	"github.com/hedzr/evendeep/internal/syscalls"
    14  	"github.com/hedzr/evendeep/internal/tool"
    15  
    16  	"gopkg.in/hedzr/errors.v3"
    17  )
    18  
    19  // rForBool transform bool -> string.
    20  func rForBool(v reflect.Value) (ret reflect.Value) {
    21  	vs := strconv.FormatBool(v.Bool())
    22  	ret = reflect.ValueOf(vs)
    23  	return
    24  }
    25  
    26  // rToBool transform string (or anything) -> bool.
    27  func rToBool(v reflect.Value) (ret reflect.Value) {
    28  	var b bool
    29  
    30  	if !v.IsValid() || tool.IsNil(v) || tool.IsZero(v) {
    31  		return reflect.ValueOf(b)
    32  	}
    33  
    34  	k := v.Kind()
    35  	switch k { //nolint:exhaustive //no need
    36  	case reflect.Bool:
    37  		b = v.Bool()
    38  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    39  		b = v.Int() != 0
    40  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    41  		b = v.Uint() != 0
    42  	case reflect.Float32, reflect.Float64:
    43  		b = math.Float64bits(v.Float()) != 0
    44  	case reflect.Complex64, reflect.Complex128:
    45  		c := v.Complex()
    46  		b = math.Float64bits(real(c)) != 0 || math.Float64bits(imag(c)) != 0
    47  	case reflect.Array:
    48  		b = !tool.ArrayIsZero(v)
    49  	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
    50  		b = !tool.IsNil(v)
    51  	case reflect.Struct:
    52  		b = !tool.StructIsZero(v)
    53  	case reflect.String:
    54  		b = internalToBool(v.String())
    55  	}
    56  
    57  	ret = reflect.ValueOf(b)
    58  	return
    59  }
    60  
    61  func internalToBool(s string) (b bool) {
    62  	switch val := strings.ToLower(s); val {
    63  	case "y", "t", "1", "yes", "true", "on", "ok", "m", "male":
    64  		b = true
    65  	}
    66  	return
    67  }
    68  
    69  // rForInteger transform integer -> string.
    70  func rForInteger(v reflect.Value) (ret reflect.Value) {
    71  	int64typ := reflect.TypeOf((*int64)(nil)).Elem()
    72  	if !v.IsValid() {
    73  		v = reflect.Zero(int64typ)
    74  	} else if k := v.Kind(); k < reflect.Int || k > reflect.Int64 {
    75  		if tool.CanConvert(&v, int64typ) {
    76  			v = v.Convert(int64typ)
    77  		} else {
    78  			v = reflect.Zero(int64typ)
    79  		}
    80  	}
    81  
    82  	vs := strconv.FormatInt(v.Int(), 10)
    83  	ret = reflect.ValueOf(vs)
    84  	return
    85  }
    86  
    87  const uintSize = 32 << (^uint(0) >> 32 & 1)
    88  
    89  //nolint:dupl //don't
    90  func rToInteger(v reflect.Value, desiredType reflect.Type) (ret reflect.Value, err error) {
    91  	genret := func(ival int64, desiredTypeKind reflect.Kind) (ret reflect.Value) {
    92  		switch desiredTypeKind { //nolint:exhaustive //no need
    93  		case reflect.Int:
    94  			ret = reflect.ValueOf(int(ival))
    95  		case reflect.Int32:
    96  			ret = reflect.ValueOf(int32(ival))
    97  		case reflect.Int16:
    98  			ret = reflect.ValueOf(int16(ival))
    99  		case reflect.Int8:
   100  			ret = reflect.ValueOf(int8(ival))
   101  		default:
   102  			ret = reflect.ValueOf(ival)
   103  		}
   104  		return
   105  	}
   106  	ret, err = toTypeConverter(v, desiredType, 10, //nolint:gomnd //no need
   107  		func(str string, base int, bitSize int) (ret reflect.Value, err error) {
   108  			var ival int64
   109  			ival, err = strconv.ParseInt(str, base, bitSize)
   110  			if err == nil {
   111  				k := desiredType.Kind()
   112  				ret = genret(ival, k)
   113  			} else {
   114  				var fval float64
   115  				fval, err = strconv.ParseFloat(str, bitSize)
   116  				if err == nil {
   117  					ival = int64(math.Floor(fval + 0.5)) //nolint:gomnd //no need
   118  					k := desiredType.Kind()
   119  					ret = genret(ival, k)
   120  				}
   121  			}
   122  			return
   123  		})
   124  	return
   125  }
   126  
   127  // rForUInteger transform uint64 -> string.
   128  func rForUInteger(v reflect.Value) (ret reflect.Value) {
   129  	uint64typ := reflect.TypeOf((*uint64)(nil)).Elem()
   130  	if !v.IsValid() {
   131  		v = reflect.Zero(uint64typ)
   132  	} else if k := v.Kind(); k < reflect.Uint || k > reflect.Uintptr {
   133  		if tool.CanConvert(&v, uint64typ) {
   134  			v = v.Convert(uint64typ)
   135  		} else {
   136  			v = reflect.Zero(uint64typ)
   137  		}
   138  	}
   139  
   140  	vs := strconv.FormatUint(v.Uint(), 10)
   141  	ret = reflect.ValueOf(vs)
   142  	return
   143  }
   144  
   145  //nolint:dupl //don't
   146  func rToUInteger(v reflect.Value, desiredType reflect.Type) (ret reflect.Value, err error) {
   147  	genret := func(ival uint64, desiredTypeKind reflect.Kind) (ret reflect.Value) {
   148  		switch desiredTypeKind { //nolint:exhaustive //no need
   149  		case reflect.Uint:
   150  			ret = reflect.ValueOf(uint(ival))
   151  		case reflect.Uint32:
   152  			ret = reflect.ValueOf(uint32(ival))
   153  		case reflect.Uint16:
   154  			ret = reflect.ValueOf(uint16(ival))
   155  		case reflect.Uint8:
   156  			ret = reflect.ValueOf(uint8(ival))
   157  		default:
   158  			ret = reflect.ValueOf(ival)
   159  		}
   160  		return
   161  	}
   162  	ret, err = toTypeConverter(v, desiredType, 10, //nolint:gomnd //no need
   163  		func(str string, base int, bitSize int) (ret reflect.Value, err error) {
   164  			var ival uint64
   165  			ival, err = strconv.ParseUint(str, base, bitSize)
   166  			if err == nil {
   167  				k := desiredType.Kind()
   168  				ret = genret(ival, k)
   169  			} else {
   170  				var fval float64
   171  				fval, err = strconv.ParseFloat(str, bitSize)
   172  				if err == nil {
   173  					ival = uint64(math.Floor(fval + 0.5)) //nolint:gomnd //no need
   174  					k := desiredType.Kind()
   175  					ret = genret(ival, k)
   176  				}
   177  			}
   178  			return
   179  		})
   180  	return
   181  }
   182  
   183  // rForUIntegerHex transform uintptr/... -> string.
   184  func rForUIntegerHex(u uintptr) (ret reflect.Value) {
   185  	vs := syscalls.UintptrToString(u)
   186  	ret = reflect.ValueOf(vs)
   187  	return
   188  }
   189  
   190  func rToUIntegerHex(s reflect.Value, desiredType reflect.Type) (ret reflect.Value) {
   191  	vs := syscalls.UintptrFromString(s.String())
   192  	log.Printf("vs : %v, k: %v\n", vs, desiredType.Kind())
   193  	switch k := desiredType.Kind(); k { //nolint:exhaustive //no need
   194  	case reflect.Uintptr:
   195  		ret = reflect.ValueOf(vs)
   196  	case reflect.UnsafePointer, reflect.Ptr:
   197  		ret = reflect.ValueOf(vs)
   198  		// u := getPointerAsUintptr(ret)
   199  	}
   200  	return
   201  }
   202  
   203  func getPointerAsUintptr(v reflect.Value) uintptr { //nolint:unused // intergrality
   204  	var p uintptr
   205  	if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
   206  		p = v.Pointer()
   207  	}
   208  	return p
   209  }
   210  
   211  // rForFloat transform float -> string.
   212  func rForFloat(v reflect.Value) (ret reflect.Value) {
   213  	float64typ := reflect.TypeOf((*float64)(nil)).Elem()
   214  	if !v.IsValid() {
   215  		v = reflect.Zero(float64typ)
   216  	} else if k := v.Kind(); k < reflect.Float32 || k > reflect.Float64 {
   217  		if tool.CanConvert(&v, float64typ) {
   218  			v = v.Convert(float64typ)
   219  		} else {
   220  			v = reflect.Zero(float64typ)
   221  		}
   222  	}
   223  
   224  	vs := strconv.FormatFloat(v.Float(), 'g', -1, 64)
   225  	ret = reflect.ValueOf(vs)
   226  	return
   227  }
   228  
   229  func rToFloat(v reflect.Value, desiredType reflect.Type) (ret reflect.Value, err error) {
   230  	toFloat := func(fval float64, desiredType reflect.Type) (ret reflect.Value) {
   231  		if desiredType.Kind() == reflect.Float64 {
   232  			ret = reflect.ValueOf(fval)
   233  		} else {
   234  			ret = reflect.ValueOf(float32(fval))
   235  		}
   236  		return
   237  	}
   238  	ret, err = toTypeConverter(v, desiredType, 10, //nolint:gomnd //no need
   239  		func(str string, base int, bitSize int) (ret reflect.Value, err error) {
   240  			var fval float64
   241  			fval, err = strconv.ParseFloat(str, bitSize)
   242  			if err == nil {
   243  				return toFloat(fval, desiredType), nil
   244  			}
   245  
   246  			var ival int64
   247  			ival, err = strconv.ParseInt(str, 10, bitSize)
   248  			if err == nil {
   249  				return toFloat(float64(ival), desiredType), nil
   250  			}
   251  
   252  			var uval uint64
   253  			uval, err = strconv.ParseUint(str, 10, bitSize)
   254  			if err == nil {
   255  				return toFloat(float64(uval), desiredType), nil
   256  			}
   257  
   258  			var cval complex128
   259  			cval, err = cl.ParseComplex(str)
   260  			if err == nil {
   261  				fval = real(cval)
   262  				ret = toFloat(fval, desiredType)
   263  			}
   264  			return
   265  		})
   266  	return
   267  }
   268  
   269  // rForComplex transform complex -> string.
   270  func rForComplex(v reflect.Value) (ret reflect.Value) {
   271  	complex128typ := reflect.TypeOf((*complex128)(nil)).Elem()
   272  	if !v.IsValid() {
   273  		v = reflect.Zero(complex128typ)
   274  	} else if k := v.Kind(); k < reflect.Complex64 || k > reflect.Complex128 {
   275  		// if canConvert(&v, complex128typ) {
   276  		//	v = v.Convert(complex128typ)
   277  		// } else {
   278  		switch k { //nolint:exhaustive //no need
   279  		case reflect.Float64, reflect.Float32:
   280  			v = reflect.ValueOf(complex(v.Float(), 0.0))
   281  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   282  			v = reflect.ValueOf(complex(float64(v.Int()), 0.0))
   283  		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
   284  			v = reflect.ValueOf(complex(float64(v.Uint()), 0.0))
   285  		default:
   286  			v = reflect.Zero(complex128typ)
   287  		}
   288  		// }
   289  	}
   290  
   291  	vs := cl.FormatComplex(v.Complex(), 'g', -1, 128) //nolint:gomnd //no need
   292  	ret = reflect.ValueOf(vs)
   293  	return
   294  }
   295  
   296  func rToComplex(v reflect.Value, desiredType reflect.Type) (ret reflect.Value, err error) {
   297  	toComplex := func(cval complex128, desiredType reflect.Type) (ret reflect.Value) {
   298  		if desiredType.Kind() == reflect.Complex128 {
   299  			ret = reflect.ValueOf(cval)
   300  		} else {
   301  			ret = reflect.ValueOf(complex64(cval))
   302  		}
   303  		return
   304  	}
   305  	ret, err = toTypeConverter(v, desiredType, 10, //nolint:gomnd //no need
   306  		func(str string, base int, bitSize int) (ret reflect.Value, err error) {
   307  			var cval complex128
   308  			if str[0] != '(' {
   309  				str = "(" + str
   310  			}
   311  			if lastch := str[len(str)-1]; lastch != ')' {
   312  				if lastch != 'i' {
   313  					str += "+0i"
   314  				}
   315  				str += ")"
   316  			}
   317  			cval, err = cl.ParseComplex(str)
   318  			if err == nil {
   319  				ret = toComplex(cval, desiredType)
   320  			}
   321  			return
   322  		})
   323  	return
   324  }
   325  
   326  func toTypeConverter(v reflect.Value, desiredType reflect.Type, base int,
   327  	converter func(str string, base int, bitSize int) (ret reflect.Value, err error),
   328  ) (ret reflect.Value, err error) {
   329  	if !v.IsValid() || tool.IsNil(v) || tool.IsZero(v) {
   330  		ret = reflect.Zero(desiredType)
   331  		return
   332  	}
   333  
   334  	if tool.CanConvert(&v, desiredType) {
   335  		ret = v.Convert(desiredType)
   336  		return
   337  	}
   338  
   339  	val := v.String()
   340  	bitSize := 64
   341  	switch k := desiredType.Kind(); k { //nolint:exhaustive //no need
   342  	case reflect.Int, reflect.Uint:
   343  		bitSize = uintSize
   344  	case reflect.Int32, reflect.Uint32, reflect.Float32:
   345  		bitSize = 32
   346  	case reflect.Int16, reflect.Uint16:
   347  		bitSize = 16
   348  	case reflect.Int8, reflect.Uint8:
   349  		bitSize = 8
   350  	case reflect.Complex128:
   351  		bitSize = 128
   352  		// case reflect.Float64, reflect.Complex64:
   353  		//	bitSize = 64
   354  	}
   355  	ret, err = converter(val, base, bitSize)
   356  	return
   357  }
   358  
   359  func tryStringerIt(source reflect.Value, desiredType reflect.Type) (target reflect.Value, processed bool, err error) {
   360  	val := source.Interface()
   361  	if ss, ok := val.(interface{ String() string }); ok {
   362  		nv := ss.String()
   363  		target = reflect.ValueOf(nv)
   364  		processed = true
   365  		return
   366  	}
   367  
   368  	if tool.CanConvert(&source, desiredType) {
   369  		nv := source.Convert(desiredType)
   370  		// target.Set(nv)
   371  		target = nv
   372  		processed = true
   373  	} else {
   374  		nv := fmt.Sprintf("%v", val)
   375  		// target.Set(reflect.ValueOf(nv))
   376  		target = reflect.ValueOf(nv)
   377  		processed = true
   378  	}
   379  	return
   380  }
   381  
   382  func rToString(source reflect.Value, desiredType reflect.Type) (target reflect.Value, err error) {
   383  	if source.IsValid() {
   384  		switch k := source.Kind(); k { //nolint:exhaustive //no need
   385  		case reflect.Bool:
   386  			target = rForBool(source)
   387  		case reflect.Int64:
   388  			var processed bool
   389  			if target, processed, err = tryStringerIt(source, desiredType); processed {
   390  				return
   391  			}
   392  			fallthrough
   393  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
   394  			target = rForInteger(source)
   395  		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   396  			target = rForUInteger(source)
   397  
   398  		case reflect.Uintptr:
   399  			target = rForUIntegerHex(uintptr(source.Uint()))
   400  		// case reflect.UnsafePointer:
   401  		//	target = rForUIntegerHex(uintptr(source.Uint()))
   402  		// case reflect.Ptr:
   403  		//	target = rForUIntegerHex(source.Pointer())
   404  
   405  		case reflect.Float32, reflect.Float64:
   406  			target = rForFloat(source)
   407  		case reflect.Complex64, reflect.Complex128:
   408  			target = rForComplex(source)
   409  
   410  		case reflect.String:
   411  			target = reflect.ValueOf(source.String())
   412  
   413  		// reflect.Array
   414  		// reflect.Chan
   415  		// reflect.Func
   416  		// reflect.Interface
   417  		// reflect.Map
   418  		// reflect.Slice
   419  		// reflect.Struct
   420  
   421  		default:
   422  			target, _, err = tryStringerIt(source, desiredType)
   423  		}
   424  	} else {
   425  		target = reflect.Zero(tool.StringType)
   426  	}
   427  	return
   428  }
   429  
   430  //nolint:unused,deadcode,lll //reserved
   431  func rToArray(ctx *ValueConverterContext, sources reflect.Value, desiredType reflect.Type, targetLength int) (target reflect.Value, err error) {
   432  	eltyp := desiredType.Elem() // length := desiredType.Len()
   433  	dbglog.Log("  desiredType: %v, el.type: %v", tool.Typfmt(desiredType), tool.Typfmt(eltyp))
   434  
   435  	count, length := sources.Len(), targetLength
   436  	if length <= 0 {
   437  		length = count
   438  	}
   439  	if count > length {
   440  		count = length
   441  	}
   442  
   443  	target = reflect.New(reflect.ArrayOf(length, eltyp)).Elem()
   444  
   445  	for ix := 0; ix < count; ix++ {
   446  		src := sources.Index(ix)
   447  		if ix < length && src.IsValid() {
   448  			if src.Type().AssignableTo(eltyp) {
   449  				target.Index(ix).Set(src)
   450  			} else if src.Type().ConvertibleTo(eltyp) {
   451  				target.Index(ix).Set(src.Convert(eltyp))
   452  			}
   453  		}
   454  	}
   455  	return
   456  }
   457  
   458  //nolint:unused,deadcode,lll //reserved
   459  func rToSlice(ctx *ValueConverterContext, sources reflect.Value, desiredType reflect.Type, targetLength int) (target reflect.Value, err error) {
   460  	eltyp := desiredType.Elem() // length := desiredType.Len()
   461  	dbglog.Log("  desiredType: %v, el.type: %v", tool.Typfmt(desiredType), tool.Typfmt(eltyp))
   462  
   463  	count, length := sources.Len(), targetLength
   464  	if length <= 0 {
   465  		length = count
   466  	}
   467  	if count > length {
   468  		count = length
   469  	}
   470  
   471  	target = reflect.MakeSlice(desiredType, length, length)
   472  	for ix := 0; ix < count; ix++ {
   473  		src := sources.Index(ix)
   474  		if ix < length && src.IsValid() {
   475  			if src.Type().AssignableTo(eltyp) {
   476  				target.Index(ix).Set(src)
   477  			} else if src.Type().ConvertibleTo(eltyp) {
   478  				target.Index(ix).Set(src.Convert(eltyp))
   479  			}
   480  		}
   481  	}
   482  	return
   483  }
   484  
   485  //nolint:unused,deadcode,lll //reserved
   486  func rToMap(ctx *ValueConverterContext, source reflect.Value, fromFuncType, desiredType reflect.Type) (target reflect.Value, err error) {
   487  	ec := errors.New("cannot transform item into map")
   488  	defer ec.Defer(&err)
   489  
   490  	dtyp := desiredType.Elem()
   491  	styp := source.Type()
   492  	// srceltyp := styp.Elem()
   493  	target = reflect.MakeMap(desiredType)
   494  
   495  	if source.IsValid() {
   496  		for ix, key := range source.MapKeys() {
   497  			val := source.MapIndex(key)
   498  			if err = rSetMapValue(ix, target, key, val, styp, dtyp); err != nil {
   499  				ec.Attach(err)
   500  				continue
   501  			}
   502  		}
   503  	}
   504  
   505  	// for i := 0; i < fromFuncType.NumOut(); i++ {
   506  	//	if i >= len(sources) {
   507  	//		continue
   508  	//	}
   509  	//
   510  	//	styp := fromFuncType.Out(i)
   511  	//	sname := styp.Name()
   512  	//	var key reflect.Value
   513  	//	if key, err = nameToMapKey(sname, desiredType); err != nil {
   514  	//		ec.Attach(err)
   515  	//		continue
   516  	//	}
   517  	//
   518  	//	if err = rSetMapValue(target, key, sources[i], styp, dtyp); err != nil {
   519  	//		ec.Attach(err)
   520  	//		continue
   521  	//	}
   522  	// }
   523  	return
   524  }
   525  
   526  //nolint:unused //future
   527  func rSetMapValue(ix int, target, key, srcVal reflect.Value, sTyp, dTyp reflect.Type) (err error) {
   528  	if sTyp.AssignableTo(dTyp) { //nolint:gocritic // no need to switch to 'switch' clause
   529  		target.SetMapIndex(key, srcVal)
   530  	} else if sTyp.ConvertibleTo(dTyp) {
   531  		target.SetMapIndex(key, srcVal.Convert(dTyp))
   532  	} else {
   533  		dstval := target.MapIndex(key)
   534  		err = errors.New("cannot set map[%v] since transforming/converting failed: %v -> %v",
   535  			tool.Valfmt(&key), tool.Valfmt(&srcVal), tool.Valfmt(&dstval))
   536  	}
   537  	return
   538  }
   539  
   540  //nolint:unused //future
   541  func nameToMapKey(name string, mapType reflect.Type) (key reflect.Value, err error) {
   542  	nameval := reflect.ValueOf(name)
   543  	nametyp := nameval.Type()
   544  
   545  	if keytyp := mapType.Key(); nametyp.AssignableTo(keytyp) { //nolint:gocritic // no need to switch to 'switch' clause
   546  		key = nameval
   547  	} else if nametyp.ConvertibleTo(keytyp) {
   548  		key = nameval.Convert(keytyp)
   549  	} else {
   550  		cvt := fromStringConverter{}
   551  		key, err = cvt.Transform(nil, nameval, keytyp)
   552  	}
   553  	return
   554  }
   555  
   556  //nolint:unused,deadcode,lll //reserved
   557  func rToStruct(ctx *ValueConverterContext, source reflect.Value, fromFuncType, desiredType reflect.Type) (target reflect.Value, err error) {
   558  	// result (source) -> struct (target)
   559  
   560  	return
   561  }
   562  
   563  //nolint:unused,deadcode,lll //reserved
   564  func rToFunc(ctx *ValueConverterContext, source reflect.Value, fromFuncType, desiredType reflect.Type) (target reflect.Value, err error) {
   565  	return
   566  }