github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/ztype/conv.go (about)

     1  package ztype
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/sohaha/zlsgo/zreflect"
    11  )
    12  
    13  type Conver struct {
    14  	MatchName  func(mapKey, fieldName string) bool
    15  	ConvHook   func(i reflect.Value, o reflect.Type) (reflect.Value, error)
    16  	TagName    string
    17  	ZeroFields bool
    18  	Squash     bool
    19  	Deep       bool
    20  	Merge      bool
    21  }
    22  
    23  var conv = Conver{TagName: tagName, Squash: true, MatchName: strings.EqualFold}
    24  
    25  func To(input, out interface{}, opt ...func(*Conver)) error {
    26  	return ValueConv(input, zreflect.ValueOf(out), opt...)
    27  }
    28  
    29  func ValueConv(input interface{}, out reflect.Value, opt ...func(*Conver)) error {
    30  	o := conv
    31  	for _, f := range opt {
    32  		f(&o)
    33  	}
    34  	if out.Kind() != reflect.Ptr {
    35  		return errors.New("out must be a pointer")
    36  	}
    37  	if !out.Elem().CanAddr() {
    38  		return errors.New("out must be addressable (a pointer)")
    39  	}
    40  	return o.to("input", input, out)
    41  }
    42  
    43  func (d *Conver) to(name string, input interface{}, outVal reflect.Value) error {
    44  	var inputVal reflect.Value
    45  	if input != nil {
    46  		inputVal = zreflect.ValueOf(input)
    47  		if inputVal.Kind() == reflect.Ptr && inputVal.IsNil() {
    48  			input = nil
    49  		}
    50  	}
    51  
    52  	t := outVal.Type()
    53  	if input == nil {
    54  		if d.ZeroFields {
    55  			outVal.Set(reflect.Zero(t))
    56  		}
    57  		return nil
    58  	}
    59  
    60  	if !inputVal.IsValid() {
    61  		outVal.Set(reflect.Zero(t))
    62  		return nil
    63  	}
    64  
    65  	var err error
    66  	outputKind := zreflect.GetAbbrKind(outVal)
    67  
    68  	if d.ConvHook != nil {
    69  		if i, err := d.ConvHook(inputVal, t); err != nil {
    70  			return err
    71  		} else {
    72  			input = i.Interface()
    73  		}
    74  	}
    75  
    76  	switch outputKind {
    77  	case reflect.Bool:
    78  		outVal.SetBool(ToBool(input))
    79  	case reflect.Interface:
    80  		err = d.basic(name, input, outVal)
    81  	case reflect.String:
    82  		outVal.SetString(ToString(input))
    83  	case reflect.Int:
    84  		outVal.SetInt(ToInt64(input))
    85  	case reflect.Uint:
    86  		outVal.SetUint(ToUint64(input))
    87  	case reflect.Float64:
    88  		outVal.SetFloat(ToFloat64(input))
    89  	case reflect.Struct:
    90  		err = d.toStruct(name, input, outVal)
    91  	case reflect.Map:
    92  		err = d.toMap(name, input, outVal)
    93  	case reflect.Ptr:
    94  		err = d.toPtr(name, input, outVal)
    95  	case reflect.Slice:
    96  		err = d.toSlice(name, input, outVal)
    97  	case reflect.Array:
    98  		err = d.toArray(name, input, outVal)
    99  	case reflect.Func:
   100  		err = d.toFunc(name, input, outVal)
   101  	default:
   102  		return errors.New(name + ": unsupported type: " + outputKind.String())
   103  	}
   104  
   105  	return err
   106  }
   107  
   108  func (d *Conver) basic(name string, data interface{}, val reflect.Value) error {
   109  	if val.IsValid() && val.Elem().IsValid() {
   110  		elem, copied := val.Elem(), false
   111  		if !elem.CanAddr() {
   112  			copied = true
   113  			nVal := reflect.New(elem.Type())
   114  			nVal.Elem().Set(elem)
   115  			elem = nVal
   116  		}
   117  
   118  		if err := d.to(name, data, elem); err != nil || !copied {
   119  			return err
   120  		}
   121  
   122  		val.Set(elem.Elem())
   123  		return nil
   124  	}
   125  
   126  	dataVal := zreflect.ValueOf(data)
   127  	if dataVal.Kind() == reflect.Ptr && dataVal.Type().Elem() == val.Type() {
   128  		dataVal = reflect.Indirect(dataVal)
   129  	}
   130  
   131  	if !dataVal.IsValid() {
   132  		dataVal = reflect.Zero(val.Type())
   133  	}
   134  
   135  	dataValType := dataVal.Type()
   136  	if !dataValType.AssignableTo(val.Type()) {
   137  		return fmt.Errorf(
   138  			"'%s' expected type '%s', got '%s'",
   139  			name, val.Type(), dataValType)
   140  	}
   141  
   142  	val.Set(dataVal)
   143  	return nil
   144  }
   145  
   146  func (d *Conver) toStruct(name string, data interface{}, val reflect.Value) error {
   147  	dataVal := reflect.Indirect(zreflect.ValueOf(data))
   148  	if dataVal.Type() == val.Type() {
   149  		val.Set(dataVal)
   150  		return nil
   151  	}
   152  
   153  	switch dataVal.Kind() {
   154  	case reflect.Map:
   155  		return d.toStructFromMap(name, dataVal, val)
   156  	case reflect.Struct:
   157  		mapType := reflect.TypeOf((map[string]interface{})(nil))
   158  		mval := reflect.MakeMap(mapType)
   159  		addrVal := reflect.New(mval.Type())
   160  		reflect.Indirect(addrVal).Set(mval)
   161  		err := d.toMapFromStruct(name, dataVal, reflect.Indirect(addrVal), mval)
   162  		if err != nil {
   163  			return err
   164  		}
   165  
   166  		return d.toStructFromMap(name, reflect.Indirect(addrVal), val)
   167  
   168  	default:
   169  		return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind())
   170  	}
   171  }
   172  
   173  func (d *Conver) toStructFromMap(name string, dataVal, val reflect.Value) error {
   174  	dataValType := dataVal.Type()
   175  	if kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface {
   176  		return fmt.Errorf(
   177  			"'%s' needs a map with string keys, has '%s' keys",
   178  			name, dataValType.Key().Kind())
   179  	}
   180  
   181  	dataValKeys := make(map[reflect.Value]struct{})
   182  	dataValKeysUnused := make(map[interface{}]struct{})
   183  	for _, dataValKey := range dataVal.MapKeys() {
   184  		dataValKeys[dataValKey] = struct{}{}
   185  		dataValKeysUnused[dataValKey.Interface()] = struct{}{}
   186  	}
   187  
   188  	targetValKeysUnused, structs := make(map[interface{}]struct{}), make([]reflect.Value, 1, 5)
   189  	structs[0] = val
   190  
   191  	type field struct {
   192  		val   reflect.Value
   193  		field reflect.StructField
   194  	}
   195  
   196  	var remainField *field
   197  
   198  	fields := make([]field, 0)
   199  	for len(structs) > 0 {
   200  		structVal := structs[0]
   201  		structs = structs[1:]
   202  		structType := structVal.Type()
   203  
   204  		for i := 0; i < structType.NumField(); i++ {
   205  			fieldType := structType.Field(i)
   206  			fieldVal := structVal.Field(i)
   207  			if fieldVal.Kind() == reflect.Ptr && fieldVal.Elem().Kind() == reflect.Struct {
   208  				fieldVal = fieldVal.Elem()
   209  			}
   210  
   211  			squash := d.Squash && fieldVal.Kind() == reflect.Struct && fieldType.Anonymous
   212  			remain := false
   213  			_, opt := zreflect.GetStructTag(fieldType, d.TagName, tagNameLesser)
   214  			tagParts := strings.Split(opt, ",")
   215  			for _, tag := range tagParts {
   216  				if tag == "squash" {
   217  					squash = true
   218  					break
   219  				}
   220  
   221  				if tag == "remain" {
   222  					remain = true
   223  					break
   224  				}
   225  			}
   226  
   227  			if squash {
   228  				if fieldVal.Kind() != reflect.Struct {
   229  					return fmt.Errorf("cannot squash non-struct type '%s'", fieldVal.Type())
   230  				} else {
   231  					structs = append(structs, fieldVal)
   232  				}
   233  				continue
   234  			}
   235  
   236  			if remain {
   237  				remainField = &field{field: fieldType, val: fieldVal}
   238  			} else {
   239  				fields = append(fields, field{field: fieldType, val: fieldVal})
   240  			}
   241  		}
   242  	}
   243  
   244  	for _, f := range fields {
   245  		field, fieldValue := f.field, f.val
   246  		fieldName, _ := zreflect.GetStructTag(field, d.TagName, tagNameLesser)
   247  		rawMapKey := zreflect.ValueOf(fieldName)
   248  		rawMapVal := dataVal.MapIndex(rawMapKey)
   249  		if !rawMapVal.IsValid() {
   250  			for dataValKey := range dataValKeys {
   251  				mK, ok := dataValKey.Interface().(string)
   252  				if !ok {
   253  					continue
   254  				}
   255  
   256  				if d.MatchName(mK, fieldName) {
   257  					rawMapKey = dataValKey
   258  					rawMapVal = dataVal.MapIndex(dataValKey)
   259  					break
   260  				}
   261  			}
   262  
   263  			if !rawMapVal.IsValid() {
   264  				targetValKeysUnused[fieldName] = struct{}{}
   265  				continue
   266  			}
   267  		}
   268  
   269  		if !fieldValue.IsValid() {
   270  			panic("field is not valid")
   271  		}
   272  
   273  		if !fieldValue.CanSet() {
   274  			continue
   275  		}
   276  
   277  		delete(dataValKeysUnused, rawMapKey.Interface())
   278  
   279  		if name != "" {
   280  			fieldName = name + "." + fieldName
   281  		}
   282  
   283  		if err := d.to(fieldName, rawMapVal.Interface(), fieldValue); err != nil {
   284  			return err
   285  		}
   286  	}
   287  
   288  	if remainField != nil && len(dataValKeysUnused) > 0 {
   289  		remain := map[interface{}]interface{}{}
   290  		for key := range dataValKeysUnused {
   291  			remain[key] = dataVal.MapIndex(zreflect.ValueOf(key)).Interface()
   292  		}
   293  
   294  		if err := d.toMap(name, remain, remainField.val); err != nil {
   295  			return err
   296  		}
   297  	}
   298  
   299  	return nil
   300  }
   301  
   302  func (d *Conver) toMap(name string, data interface{}, val reflect.Value) error {
   303  	valType := val.Type()
   304  	valKeyType := valType.Key()
   305  	valElemType := valType.Elem()
   306  	valMap := val
   307  
   308  	if valMap.IsNil() || d.ZeroFields {
   309  		mapType := reflect.MapOf(valKeyType, valElemType)
   310  		valMap = reflect.MakeMap(mapType)
   311  	}
   312  
   313  	dataVal := reflect.Indirect(zreflect.ValueOf(data))
   314  	switch dataVal.Kind() {
   315  	case reflect.Map:
   316  		return d.toMapFromMap(name, dataVal, val, valMap)
   317  	case reflect.Struct:
   318  		return d.toMapFromStruct(name, dataVal, val, valMap)
   319  	case reflect.Array, reflect.Slice:
   320  		return d.toMapFromSlice(name, dataVal, val, valMap)
   321  	default:
   322  		return fmt.Errorf("'%s' expected a map, got '%s'", name, dataVal.Kind())
   323  	}
   324  }
   325  
   326  func (d *Conver) toMapFromSlice(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {
   327  	if dataVal.Len() == 0 {
   328  		val.Set(valMap)
   329  		return nil
   330  	}
   331  
   332  	for i := 0; i < dataVal.Len(); i++ {
   333  		err := d.to(
   334  			name+"["+strconv.Itoa(i)+"]",
   335  			dataVal.Index(i).Interface(), val)
   336  		if err != nil {
   337  			return err
   338  		}
   339  	}
   340  
   341  	return nil
   342  }
   343  
   344  func (d *Conver) toMapFromMap(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {
   345  	valType := val.Type()
   346  	valKeyType := valType.Key()
   347  	valElemType := valType.Elem()
   348  
   349  	if dataVal.Len() == 0 {
   350  		if dataVal.IsNil() {
   351  			if !val.IsNil() {
   352  				val.Set(dataVal)
   353  			}
   354  		} else {
   355  			val.Set(valMap)
   356  		}
   357  
   358  		return nil
   359  	}
   360  
   361  	for _, k := range dataVal.MapKeys() {
   362  		fieldName := name + "[" + k.String() + "]"
   363  		currentKey := reflect.Indirect(reflect.New(valKeyType))
   364  		if err := d.to(fieldName, k.Interface(), currentKey); err != nil {
   365  			return err
   366  		}
   367  
   368  		v := dataVal.MapIndex(k).Interface()
   369  		currentVal := reflect.Indirect(reflect.New(valElemType))
   370  		if err := d.to(fieldName, v, currentVal); err != nil {
   371  			return err
   372  		}
   373  
   374  		valMap.SetMapIndex(currentKey, currentVal)
   375  	}
   376  
   377  	val.Set(valMap)
   378  
   379  	return nil
   380  }
   381  
   382  func (d *Conver) toMapFromStruct(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {
   383  	typ := dataVal.Type()
   384  	for i := 0; i < typ.NumField(); i++ {
   385  		f := typ.Field(i)
   386  
   387  		fmt.Println(name, f.PkgPath, f.Name, dataVal.IsValid())
   388  		if f.PkgPath != "" {
   389  			continue
   390  		}
   391  
   392  		v := dataVal.Field(i)
   393  		if !v.Type().AssignableTo(valMap.Type().Elem()) {
   394  			return fmt.Errorf("cannot assign type '%s' to map value field of type '%s'", v.Type(), valMap.Type().Elem())
   395  		}
   396  
   397  		keyName, opt := zreflect.GetStructTag(f, d.TagName, tagNameLesser)
   398  		if keyName == "" {
   399  			continue
   400  		}
   401  		squash := d.Squash && v.Kind() == reflect.Struct && f.Anonymous
   402  
   403  		if !(v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct) {
   404  			nv := v.Elem()
   405  			for i := 0; i < typ.NumField(); i++ {
   406  				f := typ.Field(i)
   407  				keyName, _ := zreflect.GetStructTag(f, d.TagName, tagNameLesser)
   408  				if keyName != "" {
   409  					v = nv
   410  					break
   411  				}
   412  			}
   413  		}
   414  
   415  		if opt != "" {
   416  			if strings.Index(opt, "omitempty") != -1 && !zreflect.Nonzero(v) {
   417  				continue
   418  			}
   419  
   420  			squash = squash || strings.Index(opt, "squash") != -1
   421  			if squash {
   422  				if v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {
   423  					v = v.Elem()
   424  				}
   425  				if v.Kind() != reflect.Struct {
   426  					return fmt.Errorf("cannot squash non-struct type '%s'", v.Type())
   427  				}
   428  			}
   429  		}
   430  
   431  		switch v.Kind() {
   432  		case reflect.Struct:
   433  			x := reflect.New(v.Type())
   434  			x.Elem().Set(v)
   435  			vType := valMap.Type()
   436  			vKeyType := vType.Key()
   437  			vElemType := vType.Elem()
   438  			mType := reflect.MapOf(vKeyType, vElemType)
   439  			vMap := reflect.MakeMap(mType)
   440  			addrVal := reflect.New(vMap.Type())
   441  			reflect.Indirect(addrVal).Set(vMap)
   442  
   443  			err := d.to(keyName, x.Interface(), reflect.Indirect(addrVal))
   444  			if err != nil {
   445  				return err
   446  			}
   447  
   448  			vMap = reflect.Indirect(addrVal)
   449  			if squash {
   450  				for _, k := range vMap.MapKeys() {
   451  					valMap.SetMapIndex(k, vMap.MapIndex(k))
   452  				}
   453  			} else {
   454  				valMap.SetMapIndex(zreflect.ValueOf(keyName), vMap)
   455  			}
   456  
   457  		default:
   458  			valMap.SetMapIndex(zreflect.ValueOf(keyName), v)
   459  		}
   460  	}
   461  
   462  	if val.CanAddr() {
   463  		val.Set(valMap)
   464  	}
   465  
   466  	return nil
   467  }
   468  
   469  func (d *Conver) toPtr(name string, data interface{}, val reflect.Value) error {
   470  	isNil := data == nil
   471  	if !isNil {
   472  		switch v := reflect.Indirect(zreflect.ValueOf(data)); v.Kind() {
   473  		case reflect.Chan,
   474  			reflect.Func,
   475  			reflect.Interface,
   476  			reflect.Map,
   477  			reflect.Ptr,
   478  			reflect.Slice:
   479  			isNil = v.IsNil()
   480  		}
   481  	}
   482  
   483  	if isNil {
   484  		if !val.IsNil() && val.CanSet() {
   485  			nilValue := reflect.New(val.Type()).Elem()
   486  			val.Set(nilValue)
   487  		}
   488  
   489  		return nil
   490  	}
   491  
   492  	valType := val.Type()
   493  	valElemType := valType.Elem()
   494  	if val.CanSet() {
   495  		realVal := val
   496  		if realVal.IsNil() || d.ZeroFields {
   497  			realVal = reflect.New(valElemType)
   498  		}
   499  
   500  		if err := d.to(name, data, reflect.Indirect(realVal)); err != nil {
   501  			return err
   502  		}
   503  
   504  		val.Set(realVal)
   505  	} else {
   506  		if err := d.to(name, data, reflect.Indirect(val)); err != nil {
   507  			return err
   508  		}
   509  	}
   510  	return nil
   511  }
   512  
   513  func (d *Conver) toSlice(name string, data interface{}, val reflect.Value) error {
   514  	dataVal := reflect.Indirect(zreflect.ValueOf(data))
   515  	dataValKind := dataVal.Kind()
   516  	valType := val.Type()
   517  	valElemType := valType.Elem()
   518  	sliceType := reflect.SliceOf(valElemType)
   519  
   520  	if dataValKind != reflect.Array && dataValKind != reflect.Slice {
   521  		switch {
   522  		case dataValKind == reflect.Slice, dataValKind == reflect.Array:
   523  			break
   524  		case dataValKind == reflect.Map:
   525  			if dataVal.Len() == 0 {
   526  				val.Set(reflect.MakeSlice(sliceType, 0, 0))
   527  				return nil
   528  			}
   529  			return d.toSlice(name, []interface{}{data}, val)
   530  		case dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8:
   531  			return d.toSlice(name, []byte(dataVal.String()), val)
   532  		default:
   533  			return d.toSlice(name, []interface{}{data}, val)
   534  		}
   535  	}
   536  
   537  	if dataValKind != reflect.Array && dataVal.IsNil() {
   538  		return nil
   539  	}
   540  
   541  	valSlice := val
   542  	if valSlice.IsNil() || d.ZeroFields {
   543  		valSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len())
   544  	} else if valSlice.Len() > dataVal.Len() {
   545  		valSlice = valSlice.Slice(0, dataVal.Len())
   546  	}
   547  
   548  	for i := 0; i < dataVal.Len(); i++ {
   549  		currentData := dataVal.Index(i).Interface()
   550  		for valSlice.Len() <= i {
   551  			valSlice = reflect.Append(valSlice, reflect.Zero(valElemType))
   552  		}
   553  		currentField := valSlice.Index(i)
   554  		fieldName := name + "[" + strconv.Itoa(i) + "]"
   555  		if err := d.to(fieldName, currentData, currentField); err != nil {
   556  			return err
   557  		}
   558  	}
   559  
   560  	val.Set(valSlice)
   561  
   562  	return nil
   563  }
   564  
   565  func (d *Conver) toArray(name string, data interface{}, val reflect.Value) error {
   566  	dataVal := reflect.Indirect(zreflect.ValueOf(data))
   567  	dataValKind, valType := dataVal.Kind(), val.Type()
   568  	valElemType := valType.Elem()
   569  	arrayType, valArray := reflect.ArrayOf(valType.Len(), valElemType), val
   570  	if valArray.Interface() == reflect.Zero(valArray.Type()).Interface() || d.ZeroFields {
   571  		if dataValKind != reflect.Array && dataValKind != reflect.Slice {
   572  			switch {
   573  			case dataValKind == reflect.Map:
   574  				if dataVal.Len() == 0 {
   575  					val.Set(reflect.Zero(arrayType))
   576  					return nil
   577  				}
   578  			default:
   579  				return d.toArray(name, []interface{}{data}, val)
   580  			}
   581  		}
   582  		if dataVal.Len() > arrayType.Len() {
   583  			return fmt.Errorf(
   584  				"'%s': expected source data to have length less or equal to %d, got %d", name, arrayType.Len(), dataVal.Len())
   585  		}
   586  
   587  		valArray = reflect.New(arrayType).Elem()
   588  	}
   589  
   590  	for i := 0; i < dataVal.Len(); i++ {
   591  		currentData := dataVal.Index(i).Interface()
   592  		currentField := valArray.Index(i)
   593  
   594  		fieldName := name + "[" + strconv.Itoa(i) + "]"
   595  		if err := d.to(fieldName, currentData, currentField); err != nil {
   596  			return err
   597  		}
   598  	}
   599  
   600  	val.Set(valArray)
   601  
   602  	return nil
   603  }
   604  
   605  func (d *Conver) toFunc(name string, data interface{}, val reflect.Value) error {
   606  	dataVal := reflect.Indirect(zreflect.ValueOf(data))
   607  	if val.Type() != dataVal.Type() {
   608  		return fmt.Errorf(
   609  			"'%s' expected type '%s', got unconvertible type '%s', value: '%v'",
   610  			name, val.Type(), dataVal.Type(), data)
   611  	}
   612  	val.Set(dataVal)
   613  	return nil
   614  }