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)
}
// 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 {
return vm.EnumeratorCreate(v)
}

View file

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

View file

@ -126,12 +126,25 @@ func init() {
// EnumeratorCreate handles syscall System.Enumerator.Create.
func EnumeratorCreate(v *VM) error {
data := v.Estack().Pop().Array()
v.Estack().Push(&Element{
value: stackitem.NewInterop(&arrayWrapper{
var interop interface{}
switch t := v.Estack().Pop().value.(type) {
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,
value: data,
}),
}
}
v.Estack().Push(&Element{
value: stackitem.NewInterop(interop),
})
return nil

View file

@ -1,6 +1,8 @@
package vm
import (
"math/big"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
@ -15,6 +17,11 @@ type (
value []stackitem.Item
}
byteArrayWrapper struct {
index int
value []byte
}
concatEnum struct {
current enumerator
second enumerator
@ -63,6 +70,23 @@ func (a *arrayWrapper) Key() stackitem.Item {
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 {
if c.current.Next() {
return true