core: adjust System.Enumerator.Create interop

Part of #1201.

It should be able to create enumerator from primitive byte-array-like
stack items too.
This commit is contained in:
Anna Shaleva 2020-07-20 16:30:19 +03:00
parent d6342ab68c
commit 459ac34839
4 changed files with 47 additions and 10 deletions

View file

@ -10,7 +10,7 @@ func Concat(_ *interop.Context, v *vm.VM) error {
return vm.EnumeratorConcat(v) return vm.EnumeratorConcat(v)
} }
// Create creates an enumerator from an array-like stack item. // Create creates an enumerator from an array-like or bytearray-like stack item.
func Create(_ *interop.Context, v *vm.VM) error { func Create(_ *interop.Context, v *vm.VM) error {
return vm.EnumeratorCreate(v) return vm.EnumeratorCreate(v)
} }

View file

@ -9,11 +9,11 @@ package enumerator
// or structures that have values with no explicit keys. // or structures that have values with no explicit keys.
type Enumerator struct{} type Enumerator struct{}
// Create creates a new enumerator from the given items (slice or structure). // Create creates a new enumerator from the given items (slice, structure, byte
// New enumerator points at index -1 of its items, so the user of it has to // array and integer or boolean converted to byte array). New enumerator points
// advance it first with Next. This function uses `System.Enumerator.Create` // at index -1 of its items, so the user of it has to advance it first with Next.
// syscall. // This function uses `System.Enumerator.Create` syscall.
func Create(items []interface{}) Enumerator { func Create(items interface{}) Enumerator {
return Enumerator{} return Enumerator{}
} }

View file

@ -126,12 +126,25 @@ func init() {
// EnumeratorCreate handles syscall System.Enumerator.Create. // EnumeratorCreate handles syscall System.Enumerator.Create.
func EnumeratorCreate(v *VM) error { func EnumeratorCreate(v *VM) error {
data := v.Estack().Pop().Array() var interop interface{}
v.Estack().Push(&Element{ switch t := v.Estack().Pop().value.(type) {
value: stackitem.NewInterop(&arrayWrapper{ case *stackitem.Array, *stackitem.Struct:
interop = &arrayWrapper{
index: -1,
value: t.Value().([]stackitem.Item),
}
default:
data, err := t.TryBytes()
if err != nil {
return fmt.Errorf("can not create enumerator from type %s: %v", t.Type(), err)
}
interop = &byteArrayWrapper{
index: -1, index: -1,
value: data, value: data,
}), }
}
v.Estack().Push(&Element{
value: stackitem.NewInterop(interop),
}) })
return nil return nil

View file

@ -1,6 +1,8 @@
package vm package vm
import ( import (
"math/big"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
@ -15,6 +17,11 @@ type (
value []stackitem.Item value []stackitem.Item
} }
byteArrayWrapper struct {
index int
value []byte
}
concatEnum struct { concatEnum struct {
current enumerator current enumerator
second enumerator second enumerator
@ -63,6 +70,23 @@ func (a *arrayWrapper) Key() stackitem.Item {
return stackitem.Make(a.index) return stackitem.Make(a.index)
} }
func (a *byteArrayWrapper) Next() bool {
if next := a.index + 1; next < len(a.value) {
a.index = next
return true
}
return false
}
func (a *byteArrayWrapper) Value() stackitem.Item {
return stackitem.NewBigInteger(big.NewInt(int64(a.value[a.index])))
}
func (a *byteArrayWrapper) Key() stackitem.Item {
return stackitem.Make(a.index)
}
func (c *concatEnum) Next() bool { func (c *concatEnum) Next() bool {
if c.current.Next() { if c.current.Next() {
return true return true