stackitem: split TryMake and Make

Sometimes we may need something that doesn't panic.

Signed-off-by: Roman Khimov <roman@nspcc.ru>
This commit is contained in:
Roman Khimov 2025-01-23 22:42:50 +03:00
parent 673b26fdb1
commit 4da753f822

View file

@ -93,86 +93,94 @@ func mkInvConversion(from Item, to Type) error {
return fmt.Errorf("%w: %s/%s", ErrInvalidConversion, from, to) return fmt.Errorf("%w: %s/%s", ErrInvalidConversion, from, to)
} }
// Make tries to make an appropriate stack item from the provided value. // TryMake tries to make an appropriate stack item from the provided value.
// It will panic if it's not possible. func TryMake(v any) (Item, error) {
func Make(v any) Item {
switch val := v.(type) { switch val := v.(type) {
case int: case int:
return (*BigInteger)(big.NewInt(int64(val))) return (*BigInteger)(big.NewInt(int64(val))), nil
case int64: case int64:
return (*BigInteger)(big.NewInt(val)) return (*BigInteger)(big.NewInt(val)), nil
case uint8: case uint8:
return (*BigInteger)(big.NewInt(int64(val))) return (*BigInteger)(big.NewInt(int64(val))), nil
case uint16: case uint16:
return (*BigInteger)(big.NewInt(int64(val))) return (*BigInteger)(big.NewInt(int64(val))), nil
case uint32: case uint32:
return (*BigInteger)(big.NewInt(int64(val))) return (*BigInteger)(big.NewInt(int64(val))), nil
case uint64: case uint64:
return (*BigInteger)(new(big.Int).SetUint64(val)) return (*BigInteger)(new(big.Int).SetUint64(val)), nil
case []byte: case []byte:
return NewByteArray(val) return NewByteArray(val), nil
case string: case string:
return NewByteArray([]byte(val)) return NewByteArray([]byte(val)), nil
case bool: case bool:
return Bool(val) return Bool(val), nil
case []Item: case []Item:
return &Array{ return &Array{
value: val, value: val,
} }, nil
case *big.Int: case *big.Int:
return NewBigInteger(val) return NewBigInteger(val), nil
case Item: case Item:
return val return val, nil
case []int: case []int:
var res = make([]Item, len(val)) var res = make([]Item, len(val))
for i := range val { for i := range val {
res[i] = Make(val[i]) res[i], _ = TryMake(val[i]) // Can't fail for int
} }
return Make(res) return TryMake(res)
case []string: case []string:
var res = make([]Item, len(val)) var res = make([]Item, len(val))
for i := range val { for i := range val {
res[i] = Make(val[i]) res[i], _ = TryMake(val[i]) // Can't fail for string
} }
return Make(res) return TryMake(res)
case []any: case []any:
res := make([]Item, len(val)) res := make([]Item, len(val))
for i := range val { for i := range val {
res[i] = Make(val[i]) var err error
res[i], err = TryMake(val[i])
if err != nil {
return nil, err
} }
return Make(res) }
return TryMake(res)
case util.Uint160: case util.Uint160:
return Make(val.BytesBE()) return TryMake(val.BytesBE())
case util.Uint256: case util.Uint256:
return Make(val.BytesBE()) return TryMake(val.BytesBE())
case *util.Uint160: case *util.Uint160:
if val == nil { if val == nil {
return Null{} return Null{}, nil
} }
return Make(*val) return TryMake(*val)
case *util.Uint256: case *util.Uint256:
if val == nil { if val == nil {
return Null{} return Null{}, nil
} }
return Make(*val) return TryMake(*val)
case nil: case nil:
return Null{} return Null{}, nil
default: default:
i64T := reflect.TypeOf(int64(0)) i64T := reflect.TypeOf(int64(0))
if reflect.TypeOf(val).ConvertibleTo(i64T) { if reflect.TypeOf(val).ConvertibleTo(i64T) {
i64Val := reflect.ValueOf(val).Convert(i64T).Interface() i64Val := reflect.ValueOf(val).Convert(i64T).Interface()
return Make(i64Val) return TryMake(i64Val)
} }
panic( return nil, fmt.Errorf("%w: item %v of type %v",
fmt.Sprintf( errors.ErrUnsupported, val, reflect.TypeOf(val))
"invalid stack item type: %v (%v)",
val,
reflect.TypeOf(val),
),
)
} }
} }
// Make is like TryMake, but panics if conversion isn't possible.
func Make(v any) Item {
itm, err := TryMake(v)
if err != nil {
panic(err)
}
return itm
}
// ToString converts an Item to a string if it is a valid UTF-8. // ToString converts an Item to a string if it is a valid UTF-8.
func ToString(item Item) (string, error) { func ToString(item Item) (string, error) {
bs, err := item.TryBytes() bs, err := item.TryBytes()