package decoder
import (
"fmt"
"reflect"
"strconv"
)
var (
nilValue = reflect .ValueOf (nil )
)
func AssignValue (src , dst reflect .Value ) error {
if dst .Type ().Kind () != reflect .Ptr {
return fmt .Errorf ("invalid dst type. required pointer type: %T" , dst .Type ())
}
casted , err := castValue (dst .Elem ().Type (), src )
if err != nil {
return err
}
dst .Elem ().Set (casted )
return nil
}
func castValue(t reflect .Type , v reflect .Value ) (reflect .Value , error ) {
switch t .Kind () {
case reflect .Int :
vv , err := castInt (v )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (int (vv .Int ())), nil
case reflect .Int8 :
vv , err := castInt (v )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (int8 (vv .Int ())), nil
case reflect .Int16 :
vv , err := castInt (v )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (int16 (vv .Int ())), nil
case reflect .Int32 :
vv , err := castInt (v )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (int32 (vv .Int ())), nil
case reflect .Int64 :
return castInt (v )
case reflect .Uint :
vv , err := castUint (v )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (uint (vv .Uint ())), nil
case reflect .Uint8 :
vv , err := castUint (v )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (uint8 (vv .Uint ())), nil
case reflect .Uint16 :
vv , err := castUint (v )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (uint16 (vv .Uint ())), nil
case reflect .Uint32 :
vv , err := castUint (v )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (uint32 (vv .Uint ())), nil
case reflect .Uint64 :
return castUint (v )
case reflect .Uintptr :
vv , err := castUint (v )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (uintptr (vv .Uint ())), nil
case reflect .String :
return castString (v )
case reflect .Bool :
return castBool (v )
case reflect .Float32 :
vv , err := castFloat (v )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (float32 (vv .Float ())), nil
case reflect .Float64 :
return castFloat (v )
case reflect .Array :
return castArray (t , v )
case reflect .Slice :
return castSlice (t , v )
case reflect .Map :
return castMap (t , v )
case reflect .Struct :
return castStruct (t , v )
}
return v , nil
}
func castInt(v reflect .Value ) (reflect .Value , error ) {
switch v .Type ().Kind () {
case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
return v , nil
case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
return reflect .ValueOf (int64 (v .Uint ())), nil
case reflect .String :
i64 , err := strconv .ParseInt (v .String (), 10 , 64 )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (i64 ), nil
case reflect .Bool :
if v .Bool () {
return reflect .ValueOf (int64 (1 )), nil
}
return reflect .ValueOf (int64 (0 )), nil
case reflect .Float32 , reflect .Float64 :
return reflect .ValueOf (int64 (v .Float ())), nil
case reflect .Array :
if v .Len () > 0 {
return castInt (v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to int64 from empty array" )
case reflect .Slice :
if v .Len () > 0 {
return castInt (v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to int64 from empty slice" )
case reflect .Interface :
return castInt (reflect .ValueOf (v .Interface ()))
case reflect .Map :
return nilValue , fmt .Errorf ("failed to cast to int64 from map" )
case reflect .Struct :
return nilValue , fmt .Errorf ("failed to cast to int64 from struct" )
case reflect .Ptr :
return castInt (v .Elem ())
}
return nilValue , fmt .Errorf ("failed to cast to int64 from %s" , v .Type ().Kind ())
}
func castUint(v reflect .Value ) (reflect .Value , error ) {
switch v .Type ().Kind () {
case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
return reflect .ValueOf (uint64 (v .Int ())), nil
case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
return v , nil
case reflect .String :
u64 , err := strconv .ParseUint (v .String (), 10 , 64 )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (u64 ), nil
case reflect .Bool :
if v .Bool () {
return reflect .ValueOf (uint64 (1 )), nil
}
return reflect .ValueOf (uint64 (0 )), nil
case reflect .Float32 , reflect .Float64 :
return reflect .ValueOf (uint64 (v .Float ())), nil
case reflect .Array :
if v .Len () > 0 {
return castUint (v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to uint64 from empty array" )
case reflect .Slice :
if v .Len () > 0 {
return castUint (v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to uint64 from empty slice" )
case reflect .Interface :
return castUint (reflect .ValueOf (v .Interface ()))
case reflect .Map :
return nilValue , fmt .Errorf ("failed to cast to uint64 from map" )
case reflect .Struct :
return nilValue , fmt .Errorf ("failed to cast to uint64 from struct" )
case reflect .Ptr :
return castUint (v .Elem ())
}
return nilValue , fmt .Errorf ("failed to cast to uint64 from %s" , v .Type ().Kind ())
}
func castString(v reflect .Value ) (reflect .Value , error ) {
switch v .Type ().Kind () {
case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
return reflect .ValueOf (fmt .Sprint (v .Int ())), nil
case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
return reflect .ValueOf (fmt .Sprint (v .Uint ())), nil
case reflect .String :
return v , nil
case reflect .Bool :
if v .Bool () {
return reflect .ValueOf ("true" ), nil
}
return reflect .ValueOf ("false" ), nil
case reflect .Float32 , reflect .Float64 :
return reflect .ValueOf (fmt .Sprint (v .Float ())), nil
case reflect .Array :
if v .Len () > 0 {
return castString (v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to string from empty array" )
case reflect .Slice :
if v .Len () > 0 {
return castString (v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to string from empty slice" )
case reflect .Interface :
return castString (reflect .ValueOf (v .Interface ()))
case reflect .Map :
return nilValue , fmt .Errorf ("failed to cast to string from map" )
case reflect .Struct :
return nilValue , fmt .Errorf ("failed to cast to string from struct" )
case reflect .Ptr :
return castString (v .Elem ())
}
return nilValue , fmt .Errorf ("failed to cast to string from %s" , v .Type ().Kind ())
}
func castBool(v reflect .Value ) (reflect .Value , error ) {
switch v .Type ().Kind () {
case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
switch v .Int () {
case 0 :
return reflect .ValueOf (false ), nil
case 1 :
return reflect .ValueOf (true ), nil
}
return nilValue , fmt .Errorf ("failed to cast to bool from %d" , v .Int ())
case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
switch v .Uint () {
case 0 :
return reflect .ValueOf (false ), nil
case 1 :
return reflect .ValueOf (true ), nil
}
return nilValue , fmt .Errorf ("failed to cast to bool from %d" , v .Uint ())
case reflect .String :
b , err := strconv .ParseBool (v .String ())
if err != nil {
return nilValue , err
}
return reflect .ValueOf (b ), nil
case reflect .Bool :
return v , nil
case reflect .Float32 , reflect .Float64 :
switch v .Float () {
case 0 :
return reflect .ValueOf (false ), nil
case 1 :
return reflect .ValueOf (true ), nil
}
return nilValue , fmt .Errorf ("failed to cast to bool from %f" , v .Float ())
case reflect .Array :
if v .Len () > 0 {
return castBool (v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to string from empty array" )
case reflect .Slice :
if v .Len () > 0 {
return castBool (v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to string from empty slice" )
case reflect .Interface :
return castBool (reflect .ValueOf (v .Interface ()))
case reflect .Map :
return nilValue , fmt .Errorf ("failed to cast to string from map" )
case reflect .Struct :
return nilValue , fmt .Errorf ("failed to cast to string from struct" )
case reflect .Ptr :
return castBool (v .Elem ())
}
return nilValue , fmt .Errorf ("failed to cast to bool from %s" , v .Type ().Kind ())
}
func castFloat(v reflect .Value ) (reflect .Value , error ) {
switch v .Type ().Kind () {
case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 :
return reflect .ValueOf (float64 (v .Int ())), nil
case reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr :
return reflect .ValueOf (float64 (v .Uint ())), nil
case reflect .String :
f64 , err := strconv .ParseFloat (v .String (), 64 )
if err != nil {
return nilValue , err
}
return reflect .ValueOf (f64 ), nil
case reflect .Bool :
if v .Bool () {
return reflect .ValueOf (float64 (1 )), nil
}
return reflect .ValueOf (float64 (0 )), nil
case reflect .Float32 , reflect .Float64 :
return v , nil
case reflect .Array :
if v .Len () > 0 {
return castFloat (v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to float64 from empty array" )
case reflect .Slice :
if v .Len () > 0 {
return castFloat (v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to float64 from empty slice" )
case reflect .Interface :
return castFloat (reflect .ValueOf (v .Interface ()))
case reflect .Map :
return nilValue , fmt .Errorf ("failed to cast to float64 from map" )
case reflect .Struct :
return nilValue , fmt .Errorf ("failed to cast to float64 from struct" )
case reflect .Ptr :
return castFloat (v .Elem ())
}
return nilValue , fmt .Errorf ("failed to cast to float64 from %s" , v .Type ().Kind ())
}
func castArray(t reflect .Type , v reflect .Value ) (reflect .Value , error ) {
kind := v .Type ().Kind ()
if kind == reflect .Interface {
return castArray (t , reflect .ValueOf (v .Interface ()))
}
if kind != reflect .Slice && kind != reflect .Array {
return nilValue , fmt .Errorf ("failed to cast to array from %s" , kind )
}
if t .Elem () == v .Type ().Elem () {
return v , nil
}
if t .Len () != v .Len () {
return nilValue , fmt .Errorf ("failed to cast [%d]array from slice of %d length" , t .Len (), v .Len ())
}
ret := reflect .New (t ).Elem ()
for i := 0 ; i < v .Len (); i ++ {
vv , err := castValue (t .Elem (), v .Index (i ))
if err != nil {
return nilValue , err
}
ret .Index (i ).Set (vv )
}
return ret , nil
}
func castSlice(t reflect .Type , v reflect .Value ) (reflect .Value , error ) {
kind := v .Type ().Kind ()
if kind == reflect .Interface {
return castSlice (t , reflect .ValueOf (v .Interface ()))
}
if kind != reflect .Slice && kind != reflect .Array {
return nilValue , fmt .Errorf ("failed to cast to slice from %s" , kind )
}
if t .Elem () == v .Type ().Elem () {
return v , nil
}
ret := reflect .MakeSlice (t , v .Len (), v .Len ())
for i := 0 ; i < v .Len (); i ++ {
vv , err := castValue (t .Elem (), v .Index (i ))
if err != nil {
return nilValue , err
}
ret .Index (i ).Set (vv )
}
return ret , nil
}
func castMap(t reflect .Type , v reflect .Value ) (reflect .Value , error ) {
ret := reflect .MakeMap (t )
switch v .Type ().Kind () {
case reflect .Map :
iter := v .MapRange ()
for iter .Next () {
key , err := castValue (t .Key (), iter .Key ())
if err != nil {
return nilValue , err
}
value , err := castValue (t .Elem (), iter .Value ())
if err != nil {
return nilValue , err
}
ret .SetMapIndex (key , value )
}
return ret , nil
case reflect .Interface :
return castMap (t , reflect .ValueOf (v .Interface ()))
case reflect .Slice :
if v .Len () > 0 {
return castMap (t , v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to map from empty slice" )
}
return nilValue , fmt .Errorf ("failed to cast to map from %s" , v .Type ().Kind ())
}
func castStruct(t reflect .Type , v reflect .Value ) (reflect .Value , error ) {
ret := reflect .New (t ).Elem ()
switch v .Type ().Kind () {
case reflect .Map :
iter := v .MapRange ()
for iter .Next () {
key := iter .Key ()
k , err := castString (key )
if err != nil {
return nilValue , err
}
fieldName := k .String ()
field , ok := t .FieldByName (fieldName )
if ok {
value , err := castValue (field .Type , iter .Value ())
if err != nil {
return nilValue , err
}
ret .FieldByName (fieldName ).Set (value )
}
}
return ret , nil
case reflect .Struct :
for i := 0 ; i < v .Type ().NumField (); i ++ {
name := v .Type ().Field (i ).Name
ret .FieldByName (name ).Set (v .FieldByName (name ))
}
return ret , nil
case reflect .Interface :
return castStruct (t , reflect .ValueOf (v .Interface ()))
case reflect .Slice :
if v .Len () > 0 {
return castStruct (t , v .Index (0 ))
}
return nilValue , fmt .Errorf ("failed to cast to struct from empty slice" )
default :
return nilValue , fmt .Errorf ("failed to cast to struct from %s" , v .Type ().Kind ())
}
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .