diff --git a/util/reflect/reflect.go b/util/reflect/reflect.go index e65f2ee..d6b1130 100644 --- a/util/reflect/reflect.go +++ b/util/reflect/reflect.go @@ -1,6 +1,7 @@ package reflect import ( + "errors" "fmt" "reflect" "strconv" @@ -11,6 +12,10 @@ var ( allowTags = []string{"json", "yaml", "xml", "name"} ) +var ( + ErrValueAssociated = errors.New("value cannot be associated") +) + func findField(v reflect.Value, field string) reflect.Value { var ( pos int @@ -64,7 +69,7 @@ func safeAssignment(variable reflect.Value, value interface{}) (err error) { variable.SetInt(n) } default: - err = fmt.Errorf("unsupported kind %s", rv.Kind()) + err = fmt.Errorf("integer value can not assign %s", rv.Kind()) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: switch rv.Kind() { @@ -79,7 +84,7 @@ func safeAssignment(variable reflect.Value, value interface{}) (err error) { variable.SetUint(un) } default: - err = fmt.Errorf("unsupported kind %s", rv.Kind()) + err = fmt.Errorf("unsigned integer value can not assign %s", rv.Kind()) } case reflect.Float32, reflect.Float64: switch rv.Kind() { @@ -94,7 +99,7 @@ func safeAssignment(variable reflect.Value, value interface{}) (err error) { variable.SetFloat(fn) } default: - err = fmt.Errorf("unsupported kind %s", rv.Kind()) + err = fmt.Errorf("decimal value can not assign %s", rv.Kind()) } case reflect.String: switch rv.Kind() { @@ -139,10 +144,30 @@ func Set(hacky interface{}, field string, value interface{}) (err error) { } switch fieldKind { case reflect.Struct: - switch rv.Kind() { - case reflect.Map: + if rv.Kind() != reflect.Map { + return ErrValueAssociated + } + keys := rv.MapKeys() + subVal := reflect.New(refField.Type()) + for _, key := range keys { + pv := rv.MapIndex(key) + if key.Kind() == reflect.String { + if err = Set(subVal.Interface(), key.String(), pv.Interface()); err != nil { + return err + } + } + } + refField.Set(subVal.Elem()) + case reflect.Ptr: + elemType := refField.Type() + if elemType.Elem().Kind() != reflect.Struct { + return ErrValueAssociated + } else { + if rv.Kind() != reflect.Map { + return ErrValueAssociated + } keys := rv.MapKeys() - subVal := reflect.New(refField.Type()) + subVal := reflect.New(elemType.Elem()) for _, key := range keys { pv := rv.MapIndex(key) if key.Kind() == reflect.String { @@ -151,46 +176,102 @@ func Set(hacky interface{}, field string, value interface{}) (err error) { } } } - refField.Set(subVal.Elem()) - default: - err = fmt.Errorf("struct unsupported assign kind %s", rv.Kind()) + refField.Set(subVal) } - case reflect.Ptr: - elemType := refField.Type() - if elemType.Elem().Kind() == reflect.Struct { - switch rv.Kind() { - case reflect.Map: - keys := rv.MapKeys() - subVal := reflect.New(elemType.Elem()) - for _, key := range keys { - pv := rv.MapIndex(key) - if key.Kind() == reflect.String { - if err = Set(subVal.Interface(), key.String(), pv.Interface()); err != nil { + case reflect.Map: + if rv.Kind() != reflect.Map { + return ErrValueAssociated + } + targetValue := reflect.MakeMap(refField.Type()) + keys := rv.MapKeys() + for _, key := range keys { + pv := rv.MapIndex(key) + kVal := reflect.New(refField.Type().Key()) + eVal := reflect.New(refField.Type().Elem()) + if err = safeAssignment(kVal.Elem(), key.Interface()); err != nil { + return ErrValueAssociated + } + if refField.Type().Elem().Kind() == reflect.Struct { + if pv.Elem().Kind() != reflect.Map { + return ErrValueAssociated + } + subKeys := pv.Elem().MapKeys() + for _, subKey := range subKeys { + subVal := pv.Elem().MapIndex(subKey) + if subKey.Kind() == reflect.String { + if err = Set(eVal.Interface(), subKey.String(), subVal.Interface()); err != nil { return err } } } - refField.Set(subVal) - default: - err = fmt.Errorf("struct unsupported assign kind %s", rv.Kind()) + targetValue.SetMapIndex(kVal.Elem(), eVal.Elem()) + } else { + if err = safeAssignment(eVal.Elem(), pv.Interface()); err != nil { + return ErrValueAssociated + } + targetValue.SetMapIndex(kVal.Elem(), eVal.Elem()) } - } else { - err = fmt.Errorf("ptr can't set kind %s", elemType.Elem().Kind()) } + refField.Set(targetValue) case reflect.Array, reflect.Slice: + n = 0 innerType := refField.Type().Elem() if rv.Kind() == reflect.Array || rv.Kind() == reflect.Slice { - sliceVar := reflect.MakeSlice(refField.Type(), rv.Len(), rv.Len()) - n = 0 - for i := 0; i < rv.Len(); i++ { - srcVal := rv.Index(i) - dstVal := reflect.New(innerType).Elem() - if err = safeAssignment(dstVal, srcVal); err == nil { + if innerType.Kind() == reflect.Struct { + sliceVar := reflect.MakeSlice(refField.Type(), rv.Len(), rv.Len()) + for i := 0; i < rv.Len(); i++ { + srcVal := rv.Index(i) + if srcVal.Kind() != reflect.Map { + return ErrValueAssociated + } + dstVal := reflect.New(innerType) + keys := srcVal.MapKeys() + for _, key := range keys { + kv := srcVal.MapIndex(key) + if key.Kind() == reflect.String { + if err = Set(dstVal.Interface(), key.String(), kv.Interface()); err != nil { + return + } + } + } + sliceVar.Index(n).Set(dstVal.Elem()) + n++ + } + refField.Set(sliceVar.Slice(0, n)) + } else if innerType.Kind() == reflect.Ptr { + sliceVar := reflect.MakeSlice(refField.Type(), rv.Len(), rv.Len()) + for i := 0; i < rv.Len(); i++ { + srcVal := rv.Index(i) + if srcVal.Kind() != reflect.Map { + return ErrValueAssociated + } + dstVal := reflect.New(innerType.Elem()) + keys := srcVal.MapKeys() + for _, key := range keys { + kv := srcVal.MapIndex(key) + if key.Kind() == reflect.String { + if err = Set(dstVal.Interface(), key.String(), kv.Interface()); err != nil { + return + } + } + } sliceVar.Index(n).Set(dstVal) n++ } + refField.Set(sliceVar.Slice(0, n)) + } else { + sliceVar := reflect.MakeSlice(refField.Type(), rv.Len(), rv.Len()) + for i := 0; i < rv.Len(); i++ { + srcVal := rv.Index(i) + dstVal := reflect.New(innerType).Elem() + if err = safeAssignment(dstVal, srcVal.Interface()); err != nil { + return + } + sliceVar.Index(n).Set(dstVal) + n++ + } + refField.Set(sliceVar.Slice(0, n)) } - refField.Set(sliceVar.Slice(0, n)) } default: err = safeAssignment(refField, value) diff --git a/util/reflection/reflection_test.go b/util/reflection/reflection_test.go index 7a26aad..4841c7a 100644 --- a/util/reflection/reflection_test.go +++ b/util/reflection/reflection_test.go @@ -6,17 +6,50 @@ import ( ) type Fakeb struct { - In int `json:"in"` + In int `json:"in"` + BS map[string]string `json:"bs"` } + +type Ab struct { + Name string `json:"name"` +} + type fake struct { - Name string `json:"name"` - Age int `json:"age"` - Usage *Fakeb `json:"usage"` + Name string `json:"name"` + Age int `json:"age"` + Usage []Fakeb `json:"usage"` + XX Fakeb `json:"xx"` + AX *Fakeb `json:"ax"` + SS []string `json:"ss"` + DS []int `json:"ds"` + Ms map[string]int `json:"ms"` + AB map[string]Ab `json:"ab"` } func TestSetter(t *testing.T) { dst := &fake{} - ms := map[string]any{"name": "aa", "age": "5", "usage": map[string]any{"in": 15}} + ms := map[string]any{ + "name": "aa", + "age": "5", + "usage": []map[string]any{ + { + "in": 15, + "bs": map[string]any{ + "aa": "vv", + }, + }, + }, + "xx": map[string]any{"in": 45}, + "ax": map[string]any{"in": 55}, + "ss": []string{"11", "ss"}, + "ds": []int{55, 55, 34}, + "ms": map[string]any{"aa": "23"}, + "ab": map[string]any{ + "xx": map[string]any{ + "name": "xxx", + }, + }, + } err := Setter(dst, ms) if err != nil { t.Error(err) @@ -25,7 +58,6 @@ func TestSetter(t *testing.T) { if dst.Age != 5 { t.Errorf("setter failed") } else { - fmt.Println(dst.Usage.In) fmt.Printf("%+v", dst) } }