Files
chaisql/internal/encoding/array.go
2023-12-02 11:25:56 +04:00

111 lines
2.2 KiB
Go

package encoding
import (
"encoding/binary"
"github.com/chaisql/chai/internal/object"
"github.com/chaisql/chai/internal/types"
)
func EncodeArray(dst []byte, a types.Array) ([]byte, error) {
if a == nil {
dst = EncodeArrayLength(dst, 0)
return dst, nil
}
l, err := object.ArrayLength(a)
if err != nil {
return nil, err
}
if l == 0 {
return append(dst, byte(ArrayValue), 0), nil
}
dst = EncodeArrayLength(dst, l)
err = a.Iterate(func(i int, value types.Value) error {
dst, err = EncodeValue(dst, value, false)
return err
})
if err != nil {
return nil, err
}
return dst, nil
}
func EncodeArrayLength(dst []byte, l int) []byte {
// encode the length as a varint
buf := make([]byte, binary.MaxVarintLen64+1)
buf[0] = ArrayValue
n := binary.PutUvarint(buf[1:], uint64(l))
return append(dst, buf[:n+1]...)
}
func DecodeArray(b []byte, intAsDouble bool) types.Array {
return &EncodedArray{
enc: b[1:],
intAsDouble: intAsDouble,
}
}
// An EncodedArray implements the types.Array interface on top of an
// encoded representation of an array.
// It is useful for avoiding decoding the entire array when
// only a few values are needed.
type EncodedArray struct {
enc []byte
intAsDouble bool
}
// Iterate goes through all the values of the array and calls the
// given function by passing each one of them.
// If the given function returns an error, the iteration stops.
func (e *EncodedArray) Iterate(fn func(i int, value types.Value) error) error {
l, n := binary.Uvarint(e.enc)
if l == 0 {
return nil
}
b := e.enc[n:]
ll := int(l)
for i := 0; i < ll; i++ {
v, n := DecodeValue(b, e.intAsDouble)
b = b[n:]
err := fn(i, v)
if err != nil {
return err
}
}
return nil
}
// GetByIndex returns a value by index of the array.
func (e *EncodedArray) GetByIndex(idx int) (v types.Value, err error) {
l, n := binary.Uvarint(e.enc)
if l == 0 {
return nil, types.ErrValueNotFound
}
b := e.enc[n:]
ll := int(l)
for i := 0; i < ll; i++ {
if i == idx {
v, _ := DecodeValue(b, e.intAsDouble)
return v, nil
}
n = Skip(b)
b = b[n:]
}
err = types.ErrValueNotFound
return
}
func (e *EncodedArray) MarshalJSON() ([]byte, error) {
return object.MarshalJSONArray(e)
}