chore: better structure decoder

This commit is contained in:
wwqgtxx 2022-12-13 21:13:31 +08:00
parent afb2364ca2
commit 8a2d1ec5a7

View file

@ -86,11 +86,16 @@ func (d *Decoder) Decode(src map[string]any, dst any) error {
} }
func (d *Decoder) decode(name string, data any, val reflect.Value) error { func (d *Decoder) decode(name string, data any, val reflect.Value) error {
switch val.Kind() { kind := val.Kind()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: switch {
case isInt(kind):
return d.decodeInt(name, data, val) return d.decodeInt(name, data, val)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: case isUint(kind):
return d.decodeUint(name, data, val) return d.decodeUint(name, data, val)
case isFloat(kind):
return d.decodeFloat(name, data, val)
}
switch kind {
case reflect.String: case reflect.String:
return d.decodeString(name, data, val) return d.decodeString(name, data, val)
case reflect.Bool: case reflect.Bool:
@ -108,15 +113,42 @@ func (d *Decoder) decode(name string, data any, val reflect.Value) error {
} }
} }
func isInt(kind reflect.Kind) bool {
switch kind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return true
default:
return false
}
}
func isUint(kind reflect.Kind) bool {
switch kind {
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return true
default:
return false
}
}
func isFloat(kind reflect.Kind) bool {
switch kind {
case reflect.Float32, reflect.Float64:
return true
default:
return false
}
}
func (d *Decoder) decodeInt(name string, data any, val reflect.Value) (err error) { func (d *Decoder) decodeInt(name string, data any, val reflect.Value) (err error) {
dataVal := reflect.ValueOf(data) dataVal := reflect.ValueOf(data)
kind := dataVal.Kind() kind := dataVal.Kind()
switch { switch {
case kind == reflect.Int || kind == reflect.Int8 || kind == reflect.Int16 || kind == reflect.Int32 || kind == reflect.Int64: case isInt(kind):
val.SetInt(dataVal.Int()) val.SetInt(dataVal.Int())
case (kind == reflect.Uint || kind == reflect.Uint8 || kind == reflect.Uint16 || kind == reflect.Uint32 || kind == reflect.Uint64) && d.option.WeaklyTypedInput: case isUint(kind) && d.option.WeaklyTypedInput:
val.SetInt(int64(dataVal.Uint())) val.SetInt(int64(dataVal.Uint()))
case kind == reflect.Float64 && d.option.WeaklyTypedInput: case isFloat(kind) && d.option.WeaklyTypedInput:
val.SetInt(int64(dataVal.Float())) val.SetInt(int64(dataVal.Float()))
case kind == reflect.String && d.option.WeaklyTypedInput: case kind == reflect.String && d.option.WeaklyTypedInput:
var i int64 var i int64
@ -139,12 +171,12 @@ func (d *Decoder) decodeUint(name string, data any, val reflect.Value) (err erro
dataVal := reflect.ValueOf(data) dataVal := reflect.ValueOf(data)
kind := dataVal.Kind() kind := dataVal.Kind()
switch { switch {
case kind == reflect.Uint || kind == reflect.Uint8 || kind == reflect.Uint16 || kind == reflect.Uint32 || kind == reflect.Uint64: case isUint(kind):
val.SetUint(dataVal.Uint()) val.SetUint(dataVal.Uint())
case (kind == reflect.Int || kind == reflect.Int8 || kind == reflect.Int16 || kind == reflect.Int32 || kind == reflect.Int64) && d.option.WeaklyTypedInput: case isInt(kind) && d.option.WeaklyTypedInput:
val.SetUint(uint64(dataVal.Int())) val.SetUint(uint64(dataVal.Int()))
case kind == reflect.Float64 && d.option.WeaklyTypedInput: case isFloat(kind) && d.option.WeaklyTypedInput:
val.SetUint(uint64(int64(dataVal.Float()))) val.SetUint(uint64(dataVal.Float()))
case kind == reflect.String && d.option.WeaklyTypedInput: case kind == reflect.String && d.option.WeaklyTypedInput:
var i uint64 var i uint64
i, err = strconv.ParseUint(dataVal.String(), 0, val.Type().Bits()) i, err = strconv.ParseUint(dataVal.String(), 0, val.Type().Bits())
@ -162,14 +194,45 @@ func (d *Decoder) decodeUint(name string, data any, val reflect.Value) (err erro
return err return err
} }
func (d *Decoder) decodeFloat(name string, data any, val reflect.Value) (err error) {
dataVal := reflect.ValueOf(data)
kind := dataVal.Kind()
switch {
case isFloat(kind):
val.SetFloat(dataVal.Float())
case isUint(kind):
val.SetFloat(float64(dataVal.Uint()))
case isInt(kind) && d.option.WeaklyTypedInput:
val.SetFloat(float64(dataVal.Int()))
case kind == reflect.String && d.option.WeaklyTypedInput:
var i float64
i, err = strconv.ParseFloat(dataVal.String(), val.Type().Bits())
if err == nil {
val.SetFloat(i)
} else {
err = fmt.Errorf("cannot parse '%s' as int: %s", name, err)
}
default:
err = fmt.Errorf(
"'%s' expected type '%s', got unconvertible type '%s'",
name, val.Type(), dataVal.Type(),
)
}
return err
}
func (d *Decoder) decodeString(name string, data any, val reflect.Value) (err error) { func (d *Decoder) decodeString(name string, data any, val reflect.Value) (err error) {
dataVal := reflect.ValueOf(data) dataVal := reflect.ValueOf(data)
kind := dataVal.Kind() kind := dataVal.Kind()
switch { switch {
case kind == reflect.String: case kind == reflect.String:
val.SetString(dataVal.String()) val.SetString(dataVal.String())
case kind == reflect.Int && d.option.WeaklyTypedInput: case isInt(kind) && d.option.WeaklyTypedInput:
val.SetString(strconv.FormatInt(dataVal.Int(), 10)) val.SetString(strconv.FormatInt(dataVal.Int(), 10))
case isUint(kind) && d.option.WeaklyTypedInput:
val.SetString(strconv.FormatUint(dataVal.Uint(), 10))
case isFloat(kind) && d.option.WeaklyTypedInput:
val.SetString(strconv.FormatFloat(dataVal.Float(), 'E', -1, dataVal.Type().Bits()))
default: default:
err = fmt.Errorf( err = fmt.Errorf(
"'%s' expected type '%s', got unconvertible type '%s'", "'%s' expected type '%s', got unconvertible type '%s'",
@ -185,8 +248,10 @@ func (d *Decoder) decodeBool(name string, data any, val reflect.Value) (err erro
switch { switch {
case kind == reflect.Bool: case kind == reflect.Bool:
val.SetBool(dataVal.Bool()) val.SetBool(dataVal.Bool())
case kind == reflect.Int && d.option.WeaklyTypedInput: case isInt(kind) && d.option.WeaklyTypedInput:
val.SetBool(dataVal.Int() != 0) val.SetBool(dataVal.Int() != 0)
case isUint(kind) && d.option.WeaklyTypedInput:
val.SetString(strconv.FormatUint(dataVal.Uint(), 10))
default: default:
err = fmt.Errorf( err = fmt.Errorf(
"'%s' expected type '%s', got unconvertible type '%s'", "'%s' expected type '%s', got unconvertible type '%s'",
@ -201,7 +266,7 @@ func (d *Decoder) decodeSlice(name string, data any, val reflect.Value) error {
valType := val.Type() valType := val.Type()
valElemType := valType.Elem() valElemType := valType.Elem()
if dataVal.Kind() == reflect.String && valElemType.Kind() == reflect.Uint8 { if dataVal.Kind() == reflect.String && valElemType.Kind() == reflect.Uint8 { // from encoding/json
s := []byte(dataVal.String()) s := []byte(dataVal.String())
b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
n, err := base64.StdEncoding.Decode(b, s) n, err := base64.StdEncoding.Decode(b, s)