vm: allow to emit any based on its type

No functional changes, just moved a part of emit.Array to a separate
exported method. It may be useful for contract-based witness invocation
scripts construction and not only. Ref.
https://github.com/nspcc-dev/neo-go/pull/3233#discussion_r1407786333.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
Anna Shaleva 2023-11-28 16:54:36 +03:00
parent 2f9b4a2dbf
commit b637048122

View file

@ -98,7 +98,21 @@ func bigInt(w *io.BinWriter, n *big.Int, trySmall bool) {
w.WriteBytes(padRight(1<<padSize, buf)) w.WriteBytes(padRight(1<<padSize, buf))
} }
// Array emits an array of elements to the given buffer. It accepts elements of the following types: // Array emits an array of elements to the given buffer. It accepts everything that
// Any accepts.
func Array(w *io.BinWriter, es ...any) {
if len(es) == 0 {
Opcodes(w, opcode.NEWARRAY0)
return
}
for i := len(es) - 1; i >= 0; i-- {
Any(w, es[i])
}
Int(w, int64(len(es)))
Opcodes(w, opcode.PACK)
}
// Any emits element if supported. It accepts elements of the following types:
// - int8, int16, int32, int64, int // - int8, int16, int32, int64, int
// - uint8, uint16, uint32, uint64, uint // - uint8, uint16, uint32, uint64, uint
// - *big.Int // - *big.Int
@ -108,73 +122,65 @@ func bigInt(w *io.BinWriter, n *big.Int, trySmall bool) {
// - stackitem.Convertible, stackitem.Item // - stackitem.Convertible, stackitem.Item
// - nil // - nil
// - []any // - []any
func Array(w *io.BinWriter, es ...any) { func Any(w *io.BinWriter, something any) {
if len(es) == 0 { switch e := something.(type) {
Opcodes(w, opcode.NEWARRAY0) case []any:
return Array(w, e...)
} case int64:
for i := len(es) - 1; i >= 0; i-- { Int(w, e)
switch e := es[i].(type) { case uint64:
case []any: BigInt(w, new(big.Int).SetUint64(e))
Array(w, e...) case int32:
case int64: Int(w, int64(e))
Int(w, e) case uint32:
case uint64: Int(w, int64(e))
BigInt(w, new(big.Int).SetUint64(e)) case int16:
case int32: Int(w, int64(e))
Int(w, int64(e)) case uint16:
case uint32: Int(w, int64(e))
Int(w, int64(e)) case int8:
case int16: Int(w, int64(e))
Int(w, int64(e)) case uint8:
case uint16: Int(w, int64(e))
Int(w, int64(e)) case int:
case int8: Int(w, int64(e))
Int(w, int64(e)) case uint:
case uint8: BigInt(w, new(big.Int).SetUint64(uint64(e)))
Int(w, int64(e)) case *big.Int:
case int: BigInt(w, e)
Int(w, int64(e)) case string:
case uint: String(w, e)
BigInt(w, new(big.Int).SetUint64(uint64(e))) case util.Uint160:
case *big.Int: Bytes(w, e.BytesBE())
BigInt(w, e) case util.Uint256:
case string: Bytes(w, e.BytesBE())
String(w, e) case *util.Uint160:
case util.Uint160: if e == nil {
Bytes(w, e.BytesBE())
case util.Uint256:
Bytes(w, e.BytesBE())
case *util.Uint160:
if e == nil {
Opcodes(w, opcode.PUSHNULL)
} else {
Bytes(w, e.BytesBE())
}
case *util.Uint256:
if e == nil {
Opcodes(w, opcode.PUSHNULL)
} else {
Bytes(w, e.BytesBE())
}
case []byte:
Bytes(w, e)
case bool:
Bool(w, e)
case stackitem.Convertible:
Convertible(w, e)
case stackitem.Item:
StackItem(w, e)
default:
if es[i] != nil {
w.Err = fmt.Errorf("unsupported type: %T", e)
return
}
Opcodes(w, opcode.PUSHNULL) Opcodes(w, opcode.PUSHNULL)
} else {
Bytes(w, e.BytesBE())
} }
case *util.Uint256:
if e == nil {
Opcodes(w, opcode.PUSHNULL)
} else {
Bytes(w, e.BytesBE())
}
case []byte:
Bytes(w, e)
case bool:
Bool(w, e)
case stackitem.Convertible:
Convertible(w, e)
case stackitem.Item:
StackItem(w, e)
default:
if something != nil {
w.Err = fmt.Errorf("unsupported type: %T", e)
return
}
Opcodes(w, opcode.PUSHNULL)
} }
Int(w, int64(len(es)))
Opcodes(w, opcode.PACK)
} }
// Convertible converts provided stackitem.Convertible to the stackitem.Item and // Convertible converts provided stackitem.Convertible to the stackitem.Item and