blob: f8e06deb55264dd174718848e52adf59cb9e1a38 [file] [log] [blame]
// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package vdl
import "fmt"
// Reader is the interface that wraps the VDLRead method.
//
// VDLRead fills in the the receiver that implements this method from the
// Decoder. This method is auto-generated for all types defined in vdl. It may
// be implemented for regular Go types not defined in vdl, to customize the
// decoding.
type Reader interface {
VDLRead(dec Decoder) error
}
// Writer is the interface that wraps the VDLWrite method.
//
// VDLWrite writes out the receiver that implements this method to the Encoder.
// This method is auto-generated for all types defined in vdl. It may be
// implemented for regular Go types not defined in vdl, to customize the
// encoding.
type Writer interface {
VDLWrite(enc Encoder) error
}
// ReadWriter is the interface that groups the VDLRead and VDLWrite methods.
type ReadWriter interface {
Reader
Writer
}
// Decoder defines the interface for a decoder of vdl values. The Decoder is
// passed as the argument to VDLRead. An example of an implementation of this
// interface is vom.Decoder.
//
// The Decoder provides an API to read vdl values of all types in depth-first
// order. The ordering is based on the type of the value being read.
// E.g. given the following value:
// type MyStruct struct {
// A []string
// B map[int64]bool
// C any
// }
// value := MyStruct{
// A: {"abc", "def"},
// B: {123: true, 456: false},
// C: float32(1.5),
// }
// The values will be read in the following order:
// "abc"
// "def"
// (123, true)
// (456, false)
// 1.5
type Decoder interface {
// StartValue must be called before decoding each value, for both scalar and
// composite values. The want type is the type of value being decoded into,
// used to check compatibility with the value in the decoder; use AnyType if
// you don't know, or want to decode any type of value. Each call pushes the
// type of the next value on to the stack.
StartValue(want *Type) error
// FinishValue must be called after decoding each value, for both scalar and
// composite values. Each call pops the type of the top value off of the
// stack.
FinishValue() error
// SkipValue skips the next value; logically it behaves as if a full sequence
// of StartValue / ...Decode*... / FinishValue were called. It enables
// optimizations when the caller doesn't care about the next value.
SkipValue() error
// IgnoreNextStartValue instructs the Decoder to ignore the next call to
// StartValue. It is used to simplify implementations of VDLRead; e.g. a
// caller might call StartValue to check for nil values, and subsequently call
// StartValue again to read non-nil values. IgnoreNextStartValue is used to
// ignore the second StartValue call.
IgnoreNextStartValue()
// NextEntry instructs the Decoder to move to the next element of an Array or
// List, the next key of a Set, or the next (key,elem) pair of a Map. Returns
// done=true when there are no remaining entries.
NextEntry() (done bool, _ error)
// NextField instructs the Decoder to move to the next field of a Struct or
// Union. Returns the index of the next field, or -1 when there are no
// remaining fields. You may call Decoder.Type().Field(index).Name to
// retrieve the name of the struct or union field.
NextField() (index int, _ error)
// Type returns the type of the top value on the stack. Returns nil when the
// stack is empty. The returned type is only Any or Optional iff the value is
// nil; non-nil values are "auto-dereferenced" to their underlying elem value.
Type() *Type
// IsAny returns true iff the type of the top value on the stack was Any,
// despite the "auto-dereference" behavior of non-nil values.
IsAny() bool
// IsOptional returns true iff the type of the top value on the stack was
// Optional, despite the "auto-dereference" behavior of non-nil values.
IsOptional() bool
// IsNil returns true iff the top value on the stack is nil. It is equivalent
// to Type() == AnyType || Type().Kind() == Optional.
IsNil() bool
// Index returns the index of the current entry or field of the top value on
// the stack. Returns -1 if the top value is a scalar, or if NextEntry /
// NextField has not been called.
Index() int
// LenHint returns the length of the top value on the stack, if it is
// available. Returns -1 if the top value is a scalar, or if the length is
// not available.
LenHint() int
// DecodeBool returns the top value on the stack as a bool.
DecodeBool() (bool, error)
// DecodeString returns the top value on the stack as a string.
DecodeString() (string, error)
// DecodeUint returns the top value on the stack as a uint, where the result
// has bitlen bits. Errors are returned on loss of precision.
DecodeUint(bitlen int) (uint64, error)
// DecodeInt returns the top value on the stack as an int, where the result
// has bitlen bits. Errors are returned on loss of precision.
DecodeInt(bitlen int) (int64, error)
// DecodeFloat returns the top value on the stack as a float, where the result
// has bitlen bits. Errors are returned on loss of precision.
DecodeFloat(bitlen int) (float64, error)
// DecodeTypeObject returns the top value on the stack as a type.
DecodeTypeObject() (*Type, error)
// DecodeBytes decodes the top value on the stack as bytes, into x. If
// fixedLen >= 0 the decoded bytes must be exactly that length, otherwise
// there is no restriction on the number of decoded bytes. If cap(*x) is not
// large enough to fit the decoded bytes, a new byte slice is assigned to *x.
DecodeBytes(fixedLen int, x *[]byte) error
// ReadValueBool behaves as if StartValue, DecodeBool, FinishValue were
// called in sequence. Some decoders optimize this codepath.
ReadValueBool() (bool, error)
// ReadValueString behaves as if StartValue, DecodeString, FinishValue were
// called in sequence. Some decoders optimize this codepath.
ReadValueString() (string, error)
// ReadValueUint behaves as if StartValue, DecodeUint, FinishValue were called
// in sequence. Some decoders optimize this codepath.
ReadValueUint(bitlen int) (uint64, error)
// ReadValueInt behaves as if StartValue, DecodeInt, FinishValue were called
// in sequence. Some decoders optimize this codepath.
ReadValueInt(bitlen int) (int64, error)
// ReadValueFloat behaves as if StartValue, DecodeFloat, FinishValue were
// called in sequence. Some decoders optimize this codepath.
ReadValueFloat(bitlen int) (float64, error)
// ReadValueTypeObject behaves as if StartValue, DecodeTypeObject, FinishValue
// were called in sequence. Some decoders optimize this codepath.
ReadValueTypeObject() (*Type, error)
// ReadValueBytes behaves as if StartValue, DecodeBytes, FinishValue were
// called in sequence. Some decoders optimize this codepath.
ReadValueBytes(fixedLen int, x *[]byte) error
// NextEntryValueBool behaves as if NextEntry, StartValue, DecodeBool,
// FinishValue were called in sequence. Some decoders optimize this codepath.
NextEntryValueBool() (done bool, _ bool, _ error)
// NextEntryValueString behaves as if NextEntry, StartValue, DecodeString,
// FinishValue were called in sequence. Some decoders optimize this codepath.
NextEntryValueString() (done bool, _ string, _ error)
// NextEntryValueUint behaves as if NextEntry, StartValue, DecodeUint,
// FinishValue were called in sequence. Some decoders optimize this codepath.
NextEntryValueUint(bitlen int) (done bool, _ uint64, _ error)
// NextEntryValueInt behaves as if NextEntry, StartValue, DecodeInt,
// FinishValue were called in sequence. Some decoders optimize this codepath.
NextEntryValueInt(bitlen int) (done bool, _ int64, _ error)
// NextEntryValueFloat behaves as if NextEntry, StartValue, DecodeFloat,
// FinishValue were called in sequence. Some decoders optimize this codepath.
NextEntryValueFloat(bitlen int) (done bool, _ float64, _ error)
// NextEntryValueTypeObject behaves as if NextEntry, StartValue,
// DecodeTypeObject, FinishValue were called in sequence. Some decoders
// optimize this codepath.
NextEntryValueTypeObject() (done bool, _ *Type, _ error)
}
// Encoder defines the interface for an encoder of vdl values. The Encoder is
// passed as the argument to VDLWrite. An example of an implementation of this
// interface is vom.Encoder.
//
// The Encoder provides an API to write vdl values of all types in depth-first
// order. The ordering is based on the type of the value being written; see
// Decoder for examples.
type Encoder interface {
// StartValue must be called before encoding each non-nil value, for both
// scalar and composite values. The tt type cannot be Any or Optional; use
// NilValue to encode nil values.
StartValue(tt *Type) error
// FinishValue must be called after encoding each non-nil value, for both
// scalar and composite values.
FinishValue() error
// NilValue encodes a nil value. The tt type must be Any or Optional.
NilValue(tt *Type) error
// SetNextStartValueIsOptional instructs the encoder that the next call to
// StartValue represents a value with an Optional type.
SetNextStartValueIsOptional()
// NextEntry instructs the Encoder to move to the next element of an Array or
// List, the next key of a Set, or the next (key,elem) pair of a Map. Set
// done=true when there are no remaining entries.
NextEntry(done bool) error
// NextField instructs the Encoder to move to the next field of a Struct or
// Union. Set index to the index of the next field, or -1 when there are no
// remaining fields.
NextField(index int) error
// SetLenHint sets the length of the List, Set or Map value. It may only be
// called immediately after StartValue, before NextEntry has been called. Do
// not call this method if the length is not known.
SetLenHint(lenHint int) error
// EncodeBool encodes a bool value.
EncodeBool(value bool) error
// EncodeString encodes a string value.
EncodeString(value string) error
// EncodeUint encodes a uint value.
EncodeUint(value uint64) error
// EncodeInt encodes an int value.
EncodeInt(value int64) error
// EncodeFloat encodes a float value.
EncodeFloat(value float64) error
// EncodeTypeObject encodes a type.
EncodeTypeObject(value *Type) error
// EncodeBytes encodes a bytes value; either an array or list of bytes.
EncodeBytes(value []byte) error
// WriteValueBool behaves as if StartValue, EncodeBool, FinishValue were
// called in sequence. Some encoders optimize this codepath.
WriteValueBool(tt *Type, value bool) error
// WriteValueString behaves as if StartValue, EncodeString, FinishValue were
// called in sequence. Some encoders optimize this codepath.
WriteValueString(tt *Type, value string) error
// WriteValueUint behaves as if StartValue, EncodeUint, FinishValue were
// called in sequence. Some encoders optimize this codepath.
WriteValueUint(tt *Type, value uint64) error
// WriteValueInt behaves as if StartValue, EncodeInt, FinishValue were called
// in sequence. Some encoders optimize this codepath.
WriteValueInt(tt *Type, value int64) error
// WriteValueFloat behaves as if StartValue, EncodeFloat, FinishValue were
// called in sequence. Some encoders optimize this codepath.
WriteValueFloat(tt *Type, value float64) error
// WriteValueTypeObject behaves as if StartValue, EncodeTypeObject,
// FinishValue were called in sequence. Some encoders optimize this codepath.
WriteValueTypeObject(value *Type) error
// WriteValueBytes behaves as if StartValue, EncodeBytes, FinishValue were
// called in sequence. Some encoders optimize this codepath.
WriteValueBytes(tt *Type, value []byte) error
// NextEntryValueBool behaves as if NextEntry, StartValue, EncodeBool,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextEntryValueBool(tt *Type, value bool) error
// NextEntryValueString behaves as if NextEntry, StartValue, EncodeString,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextEntryValueString(tt *Type, value string) error
// NextEntryValueUint behaves as if NextEntry, StartValue, EncodeUint,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextEntryValueUint(tt *Type, value uint64) error
// NextEntryValueInt behaves as if NextEntry, StartValue, EncodeInt,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextEntryValueInt(tt *Type, value int64) error
// NextEntryValueFloat behaves as if NextEntry, StartValue, EncodeFloat,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextEntryValueFloat(tt *Type, value float64) error
// NextEntryValueTypeObject behaves as if NextEntry, StartValue,
// EncodeTypeObject, FinishValue were called in sequence. Some encoders
// optimize this codepath.
NextEntryValueTypeObject(value *Type) error
// NextEntryValueBytes behaves as if NextEntry, StartValue, EncodeBytes,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextEntryValueBytes(tt *Type, value []byte) error
// NextFieldValueBool behaves as if NextEntry, StartValue, EncodeBool,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextFieldValueBool(index int, tt *Type, value bool) error
// NextFieldValueString behaves as if NextEntry, StartValue, EncodeString,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextFieldValueString(index int, tt *Type, value string) error
// NextFieldValueUint behaves as if NextEntry, StartValue, EncodeUint,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextFieldValueUint(index int, tt *Type, value uint64) error
// NextFieldValueInt behaves as if NextEntry, StartValue, EncodeInt,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextFieldValueInt(index int, tt *Type, value int64) error
// NextFieldValueFloat behaves as if NextEntry, StartValue, EncodeFloat,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextFieldValueFloat(index int, tt *Type, value float64) error
// NextFieldValueTypeObject behaves as if NextEntry, StartValue,
// EncodeTypeObject, FinishValue were called in sequence. Some encoders
// optimize this codepath.
NextFieldValueTypeObject(index int, value *Type) error
// NextFieldValueBytes behaves as if NextEntry, StartValue, EncodeBytes,
// FinishValue were called in sequence. Some encoders optimize this codepath.
NextFieldValueBytes(index int, tt *Type, value []byte) error
}
// DecodeConvertedBytes is a helper function for implementations of
// Decoder.DecodeBytes, to deal with cases where the decoder value is
// convertible to []byte. E.g. if the decoder value is []float64, we need to
// decode each element as a uint8, performing conversion checks.
//
// Since this is meant to be used in the implementation of DecodeBytes, there is
// no outer call to StartValue/FinishValue.
func DecodeConvertedBytes(dec Decoder, fixedLen int, buf *[]byte) error {
// Only re-use the existing buffer if we're filling in an array. This
// sacrifices some performance, but also avoids bugs when repeatedly decoding
// into the same value.
switch len := dec.LenHint(); {
case fixedLen >= 0:
*buf = (*buf)[:0]
case len > 0:
*buf = make([]byte, 0, len)
default:
*buf = nil
}
index := 0
for {
switch done, elem, err := dec.NextEntryValueUint(8); {
case err != nil:
return err
case fixedLen >= 0 && done != (index >= fixedLen):
return fmt.Errorf("array len mismatch, done:%v index:%d len:%d", done, index, fixedLen)
case done:
return nil
default:
*buf = append(*buf, byte(elem))
}
index++
}
}