github.com/mavryk-network/mvgo@v1.19.9/contract/bind/unmarshal.go (about) 1 package bind 2 3 import ( 4 "math/big" 5 "reflect" 6 "time" 7 8 "github.com/mavryk-network/mvgo/mavryk" 9 "github.com/mavryk-network/mvgo/micheline" 10 11 "github.com/pkg/errors" 12 ) 13 14 // UnmarshalPrimPath unmarshals a nested prim contained in root, obtained using the given path, 15 // into v. 16 // 17 // v must be a non-nil pointer to the expected result. 18 func UnmarshalPrimPath(root micheline.Prim, path string, v any) error { 19 prim, err := root.GetPath(path) 20 if err != nil { 21 return errors.Wrap(err, "failed to get path") 22 } 23 return UnmarshalPrim(prim, v) 24 } 25 26 // UnmarshalPrimPaths unmarshals a Prim into a map of (path => destination). 27 func UnmarshalPrimPaths(root micheline.Prim, dst map[string]any) error { 28 for path, v := range dst { 29 if err := UnmarshalPrimPath(root, path, v); err != nil { 30 return errors.Wrapf(err, "failed to unmarshal for path %s", path) 31 } 32 } 33 return nil 34 } 35 36 // UnmarshalPrim unmarshals a prim into v. 37 // 38 // v must be a non-nil pointer to the expected result. 39 func UnmarshalPrim(prim micheline.Prim, v any) error { 40 val := reflect.ValueOf(v) 41 if val.Kind() != reflect.Ptr || val.IsNil() { 42 return errors.New("v should be a non-nil pointer") 43 } 44 45 return unmarshalPrimVal(prim, val) 46 } 47 48 var _ micheline.PrimUnmarshaler = &Bigmap[string, []byte]{} 49 50 func unmarshalPrimVal(prim micheline.Prim, val reflect.Value) error { 51 // Init Elem value if val is Nil 52 if val.Kind() == reflect.Ptr && val.IsNil() { 53 val.Set(reflect.New(val.Type().Elem())) 54 } 55 56 // Check PrimUnmarshaler interface first 57 if unmarshaler, ok := val.Interface().(micheline.PrimUnmarshaler); ok { 58 return unmarshaler.UnmarshalPrim(prim) 59 } else if _, ok = val.Elem().Interface().(micheline.PrimUnmarshaler); ok { 60 return unmarshalPrimVal(prim, val.Elem()) 61 } 62 63 // Check scalar and container types 64 switch prim.Type { 65 case micheline.PrimInt: 66 return unmarshalInt(prim.Int, val) 67 case micheline.PrimString: 68 return unmarshalString(prim.String, val) 69 case micheline.PrimBytes: 70 return unmarshalBytes(prim.Bytes, val) 71 case micheline.PrimSequence: 72 return unmarshalSlice(prim, val) 73 case micheline.PrimNullary: 74 switch prim.OpCode { 75 case micheline.D_TRUE, micheline.D_FALSE: 76 return unmarshalBool(prim.OpCode == micheline.D_TRUE, val) 77 case micheline.D_UNIT: 78 // v should be a struct{}, so we don't have to set anything 79 return nil 80 } 81 } 82 83 // Wasn't handled with *T, try with T 84 if val.Kind() == reflect.Ptr { 85 return unmarshalPrimVal(prim, val.Elem()) 86 } 87 88 return errors.Errorf("prim type not handled: %s", prim.Type) 89 } 90 91 func unmarshalInt(i *big.Int, v reflect.Value) error { 92 if v.Kind() == reflect.Ptr && v.Type() != tBigInt { 93 return unmarshalInt(i, v.Elem()) 94 } 95 96 switch v.Type() { 97 case tBigInt: 98 v.Set(reflect.ValueOf(i)) 99 case tTime: 100 v.Set(reflect.ValueOf(time.Unix(i.Int64(), 0))) 101 default: 102 return errors.Errorf("unexpected type for int prim: %T", v.Type()) 103 } 104 105 return nil 106 } 107 108 func unmarshalString(str string, v reflect.Value) error { 109 if v.Kind() == reflect.Ptr { 110 return unmarshalString(str, v.Elem()) 111 } 112 113 switch v.Type() { 114 case tString: 115 v.SetString(str) 116 case tTime: 117 t, err := time.Parse(time.RFC3339, str) 118 if err != nil { 119 return errors.Wrapf(err, "failed to parse time: %s", str) 120 } 121 v.Set(reflect.ValueOf(t)) 122 case tAddress: 123 address, err := mavryk.ParseAddress(str) 124 if err != nil { 125 return errors.Wrapf(err, "failed to parse address: %s", str) 126 } 127 v.Set(reflect.ValueOf(address)) 128 case tKey: 129 key, err := mavryk.ParseKey(str) 130 if err != nil { 131 return errors.Wrapf(err, "failed to parse key: %s", str) 132 } 133 v.Set(reflect.ValueOf(key)) 134 case tSignature: 135 sig, err := mavryk.ParseSignature(str) 136 if err != nil { 137 return errors.Wrapf(err, "failed to parse signature: %s", str) 138 } 139 v.Set(reflect.ValueOf(sig)) 140 case tChainIdHash: 141 chainID, err := mavryk.ParseChainIdHash(str) 142 if err != nil { 143 return errors.Wrapf(err, "failed to parse chainID: %s", str) 144 } 145 v.Set(reflect.ValueOf(chainID)) 146 default: 147 return errors.Errorf("unexpected type for string prim: %T", v.Type()) 148 } 149 return nil 150 } 151 152 func unmarshalBytes(b []byte, v reflect.Value) error { 153 if v.Kind() == reflect.Ptr { 154 return unmarshalBytes(b, v.Elem()) 155 } 156 157 switch v.Type() { 158 case tBytes: 159 v.Set(reflect.ValueOf(b)) 160 case tAddress: 161 var addr mavryk.Address 162 if err := addr.UnmarshalBinary(b); err != nil { 163 return errors.Wrapf(err, "failed to parse address: %v", b) 164 } 165 v.Set(reflect.ValueOf(addr)) 166 case tKey: 167 var key mavryk.Key 168 if err := key.UnmarshalBinary(b); err != nil { 169 return errors.Wrapf(err, "failed to parse key: %v", b) 170 } 171 v.Set(reflect.ValueOf(key)) 172 case tSignature: 173 var sig mavryk.Signature 174 if err := sig.UnmarshalBinary(b); err != nil { 175 return errors.Wrapf(err, "failed to parse key: %v", b) 176 } 177 v.Set(reflect.ValueOf(sig)) 178 case tChainIdHash: 179 var chainID mavryk.ChainIdHash 180 if err := chainID.UnmarshalBinary(b); err != nil { 181 return errors.Wrapf(err, "failed to parse chainID: %v", b) 182 } 183 v.Set(reflect.ValueOf(chainID)) 184 default: 185 return errors.Errorf("unexpected type for bytes prim: %T", v.Type()) 186 } 187 return nil 188 } 189 190 func unmarshalBool(b bool, v reflect.Value) error { 191 if v.Kind() == reflect.Ptr { 192 return unmarshalBool(b, v.Elem()) 193 } 194 195 if v.Type() != tBool { 196 return errors.Errorf("unexpected type for bool prim: %T", v.Type()) 197 } 198 199 v.Set(reflect.ValueOf(b)) 200 return nil 201 } 202 203 // unmarshalSlice unmarshals a Prim sequence, into a slice (through a reflect.Value). 204 func unmarshalSlice(prim micheline.Prim, v reflect.Value) error { 205 if v.Kind() == reflect.Ptr { 206 return unmarshalSlice(prim, v.Elem()) 207 } 208 209 if v.Kind() != reflect.Slice { 210 return errors.Errorf("unexpected type for sequence prim: %T", v.Type()) 211 } 212 213 elemType := v.Type().Elem() 214 215 // probably improvable 216 lenArgs := len(prim.Args) 217 newSlice := reflect.MakeSlice(v.Type(), lenArgs, lenArgs) 218 for i, arg := range prim.Args { 219 elem := reflect.New(elemType) 220 err := UnmarshalPrim(arg, elem.Interface()) 221 if err != nil { 222 return err 223 } 224 newSlice.Index(i).Set(elem.Elem()) 225 } 226 v.Set(newSlice) 227 228 return nil 229 } 230 231 // pre-computed reflect types 232 var ( 233 tBigInt = reflect.TypeOf((*big.Int)(nil)) 234 tString = reflect.TypeOf("") 235 tBytes = reflect.TypeOf(([]byte)(nil)) 236 tBool = reflect.TypeOf(true) 237 tTime = reflect.TypeOf(time.Time{}) 238 tAddress = reflect.TypeOf(mavryk.Address{}) 239 tKey = reflect.TypeOf(mavryk.Key{}) 240 tSignature = reflect.TypeOf(mavryk.Signature{}) 241 tChainIdHash = reflect.TypeOf(mavryk.ChainIdHash{}) 242 )