add array struct and map supported

This commit is contained in:
fancl 2023-09-12 15:42:28 +08:00
parent fbb08c6eb4
commit 9cfa81115f
2 changed files with 151 additions and 38 deletions

View File

@ -1,6 +1,7 @@
package reflect package reflect
import ( import (
"errors"
"fmt" "fmt"
"reflect" "reflect"
"strconv" "strconv"
@ -11,6 +12,10 @@ var (
allowTags = []string{"json", "yaml", "xml", "name"} allowTags = []string{"json", "yaml", "xml", "name"}
) )
var (
ErrValueAssociated = errors.New("value cannot be associated")
)
func findField(v reflect.Value, field string) reflect.Value { func findField(v reflect.Value, field string) reflect.Value {
var ( var (
pos int pos int
@ -64,7 +69,7 @@ func safeAssignment(variable reflect.Value, value interface{}) (err error) {
variable.SetInt(n) variable.SetInt(n)
} }
default: 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: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
switch rv.Kind() { switch rv.Kind() {
@ -79,7 +84,7 @@ func safeAssignment(variable reflect.Value, value interface{}) (err error) {
variable.SetUint(un) variable.SetUint(un)
} }
default: 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: case reflect.Float32, reflect.Float64:
switch rv.Kind() { switch rv.Kind() {
@ -94,7 +99,7 @@ func safeAssignment(variable reflect.Value, value interface{}) (err error) {
variable.SetFloat(fn) variable.SetFloat(fn)
} }
default: default:
err = fmt.Errorf("unsupported kind %s", rv.Kind()) err = fmt.Errorf("decimal value can not assign %s", rv.Kind())
} }
case reflect.String: case reflect.String:
switch rv.Kind() { switch rv.Kind() {
@ -139,10 +144,30 @@ func Set(hacky interface{}, field string, value interface{}) (err error) {
} }
switch fieldKind { switch fieldKind {
case reflect.Struct: case reflect.Struct:
switch rv.Kind() { if rv.Kind() != reflect.Map {
case 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() keys := rv.MapKeys()
subVal := reflect.New(refField.Type()) subVal := reflect.New(elemType.Elem())
for _, key := range keys { for _, key := range keys {
pv := rv.MapIndex(key) pv := rv.MapIndex(key)
if key.Kind() == reflect.String { if key.Kind() == reflect.String {
@ -151,46 +176,102 @@ func Set(hacky interface{}, field string, value interface{}) (err error) {
} }
} }
} }
refField.Set(subVal.Elem()) refField.Set(subVal)
default:
err = fmt.Errorf("struct unsupported assign kind %s", rv.Kind())
} }
case reflect.Ptr: case reflect.Map:
elemType := refField.Type() if rv.Kind() != reflect.Map {
if elemType.Elem().Kind() == reflect.Struct { return ErrValueAssociated
switch rv.Kind() { }
case reflect.Map: targetValue := reflect.MakeMap(refField.Type())
keys := rv.MapKeys() keys := rv.MapKeys()
subVal := reflect.New(elemType.Elem()) for _, key := range keys {
for _, key := range keys { pv := rv.MapIndex(key)
pv := rv.MapIndex(key) kVal := reflect.New(refField.Type().Key())
if key.Kind() == reflect.String { eVal := reflect.New(refField.Type().Elem())
if err = Set(subVal.Interface(), key.String(), pv.Interface()); err != nil { 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 return err
} }
} }
} }
refField.Set(subVal) targetValue.SetMapIndex(kVal.Elem(), eVal.Elem())
default: } else {
err = fmt.Errorf("struct unsupported assign kind %s", rv.Kind()) 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: case reflect.Array, reflect.Slice:
n = 0
innerType := refField.Type().Elem() innerType := refField.Type().Elem()
if rv.Kind() == reflect.Array || rv.Kind() == reflect.Slice { if rv.Kind() == reflect.Array || rv.Kind() == reflect.Slice {
sliceVar := reflect.MakeSlice(refField.Type(), rv.Len(), rv.Len()) if innerType.Kind() == reflect.Struct {
n = 0 sliceVar := reflect.MakeSlice(refField.Type(), rv.Len(), rv.Len())
for i := 0; i < rv.Len(); i++ { for i := 0; i < rv.Len(); i++ {
srcVal := rv.Index(i) srcVal := rv.Index(i)
dstVal := reflect.New(innerType).Elem() if srcVal.Kind() != reflect.Map {
if err = safeAssignment(dstVal, srcVal); err == nil { 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) sliceVar.Index(n).Set(dstVal)
n++ 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: default:
err = safeAssignment(refField, value) err = safeAssignment(refField, value)

View File

@ -6,17 +6,50 @@ import (
) )
type Fakeb struct { 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 { type fake struct {
Name string `json:"name"` Name string `json:"name"`
Age int `json:"age"` Age int `json:"age"`
Usage *Fakeb `json:"usage"` 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) { func TestSetter(t *testing.T) {
dst := &fake{} 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) err := Setter(dst, ms)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -25,7 +58,6 @@ func TestSetter(t *testing.T) {
if dst.Age != 5 { if dst.Age != 5 {
t.Errorf("setter failed") t.Errorf("setter failed")
} else { } else {
fmt.Println(dst.Usage.In)
fmt.Printf("%+v", dst) fmt.Printf("%+v", dst)
} }
} }