accounts/abi: Modified unpackAtomic to accept struct lvalues
This commit is contained in:
		
							parent
							
								
									13b566e06e
								
							
						
					
					
						commit
						60a999f238
					
				| @ -86,7 +86,7 @@ func (abi ABI) Unpack(v interface{}, name string, output []byte) (err error) { | |||||||
| 		} | 		} | ||||||
| 		return method.Outputs.Unpack(v, output) | 		return method.Outputs.Unpack(v, output) | ||||||
| 	} else if event, ok := abi.Events[name]; ok { | 	} else if event, ok := abi.Events[name]; ok { | ||||||
| 		return event.Inputs.unpackTuple(v, output) | 		return event.Inputs.Unpack(v, output) | ||||||
| 	} | 	} | ||||||
| 	return fmt.Errorf("abi: could not locate named method or event") | 	return fmt.Errorf("abi: could not locate named method or event") | ||||||
| } | } | ||||||
|  | |||||||
| @ -113,16 +113,8 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa | |||||||
| 	} | 	} | ||||||
| 	// If the output interface is a struct, make sure names don't collide
 | 	// If the output interface is a struct, make sure names don't collide
 | ||||||
| 	if kind == reflect.Struct { | 	if kind == reflect.Struct { | ||||||
| 		exists := make(map[string]bool) | 		if err := requireUniqueStructFieldNames(arguments); err != nil { | ||||||
| 		for _, arg := range arguments { | 			return err | ||||||
| 			field := capitalise(arg.Name) |  | ||||||
| 			if field == "" { |  | ||||||
| 				return fmt.Errorf("abi: purely underscored output cannot unpack to struct") |  | ||||||
| 			} |  | ||||||
| 			if exists[field] { |  | ||||||
| 				return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field) |  | ||||||
| 			} |  | ||||||
| 			exists[field] = true |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	for i, arg := range arguments.NonIndexed() { | 	for i, arg := range arguments.NonIndexed() { | ||||||
| @ -131,14 +123,9 @@ func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interfa | |||||||
| 
 | 
 | ||||||
| 		switch kind { | 		switch kind { | ||||||
| 		case reflect.Struct: | 		case reflect.Struct: | ||||||
| 			name := capitalise(arg.Name) | 			err := unpackStruct(value, reflectValue, arg) | ||||||
| 			for j := 0; j < typ.NumField(); j++ { | 			if err != nil { | ||||||
| 				// TODO read tags: `abi:"fieldName"`
 | 				return err | ||||||
| 				if typ.Field(j).Name == name { |  | ||||||
| 					if err := set(value.Field(j), reflectValue, arg); err != nil { |  | ||||||
| 						return err |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} | 			} | ||||||
| 		case reflect.Slice, reflect.Array: | 		case reflect.Slice, reflect.Array: | ||||||
| 			if value.Len() < i { | 			if value.Len() < i { | ||||||
| @ -165,8 +152,20 @@ func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interf | |||||||
| 		return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues)) | 		return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues)) | ||||||
| 	} | 	} | ||||||
| 	elem := reflect.ValueOf(v).Elem() | 	elem := reflect.ValueOf(v).Elem() | ||||||
|  | 	kind := elem.Kind() | ||||||
| 	reflectValue := reflect.ValueOf(marshalledValues[0]) | 	reflectValue := reflect.ValueOf(marshalledValues[0]) | ||||||
|  | 
 | ||||||
|  | 	if kind == reflect.Struct { | ||||||
|  | 		//make sure names don't collide
 | ||||||
|  | 		if err := requireUniqueStructFieldNames(arguments); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		return unpackStruct(elem, reflectValue, arguments[0]) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return set(elem, reflectValue, arguments.NonIndexed()[0]) | 	return set(elem, reflectValue, arguments.NonIndexed()[0]) | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Computes the full size of an array;
 | // Computes the full size of an array;
 | ||||||
| @ -278,3 +277,18 @@ func capitalise(input string) string { | |||||||
| 	} | 	} | ||||||
| 	return strings.ToUpper(input[:1]) + input[1:] | 	return strings.ToUpper(input[:1]) + input[1:] | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | //unpackStruct extracts each argument into its corresponding struct field
 | ||||||
|  | func unpackStruct(value, reflectValue reflect.Value, arg Argument) error { | ||||||
|  | 	name := capitalise(arg.Name) | ||||||
|  | 	typ := value.Type() | ||||||
|  | 	for j := 0; j < typ.NumField(); j++ { | ||||||
|  | 		// TODO read tags: `abi:"fieldName"`
 | ||||||
|  | 		if typ.Field(j).Name == name { | ||||||
|  | 			if err := set(value.Field(j), reflectValue, arg); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | |||||||
| @ -110,3 +110,19 @@ func requireUnpackKind(v reflect.Value, t reflect.Type, k reflect.Kind, | |||||||
| 	} | 	} | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // requireUniqueStructFieldNames makes sure field names don't collide
 | ||||||
|  | func requireUniqueStructFieldNames(args Arguments) error { | ||||||
|  | 	exists := make(map[string]bool) | ||||||
|  | 	for _, arg := range args { | ||||||
|  | 		field := capitalise(arg.Name) | ||||||
|  | 		if field == "" { | ||||||
|  | 			return fmt.Errorf("abi: purely underscored output cannot unpack to struct") | ||||||
|  | 		} | ||||||
|  | 		if exists[field] { | ||||||
|  | 			return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field) | ||||||
|  | 		} | ||||||
|  | 		exists[field] = true | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user