blob: bcbb932250f98aaa9cae20d13da873add9c2f98c [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 vom
import (
"errors"
"fmt"
"io"
"math"
"os"
"v.io/v23/vdl"
"v.io/v23/verror"
)
const (
// IEEE 754 represents float64 using 52 bits to represent the mantissa, with
// an extra implied leading bit. That gives us 53 bits to store integers
// without overflow - i.e. [0, (2^53)-1]. And since 2^53 is a small power of
// two, it can also be stored without loss via mantissa=1 exponent=53. Thus
// we have our max and min values. Ditto for float32, which uses 23 bits with
// an extra implied leading bit.
float64MaxInt = (1 << 53)
float64MinInt = -(1 << 53)
float32MaxInt = (1 << 24)
float32MinInt = -(1 << 24)
)
var (
errEmptyDecoderStack = errors.New("vom: empty decoder stack")
errReadRawBytesAlreadyStarted = errors.New("vom: read into vom.RawBytes after StartValue called")
errReadRawBytesFromNonAny = errors.New("vom: read into vom.RawBytes only supported on any values")
)
// This is only used for debugging; add this as the first line of NewDecoder to
// dump formatted vom bytes to stdout:
// r = teeDump(r)
func teeDump(r io.Reader) io.Reader {
return io.TeeReader(r, NewDumper(NewDumpWriter(os.Stdout)))
}
// Decoder manages the receipt and unmarshalling of typed values from the other
// side of a connection.
type Decoder struct {
dec decoder81
}
type decoder81 struct {
buf *decbuf
flag decFlag
stack []decStackEntry
refTypes referencedTypes
refAnyLens referencedAnyLens
typeDec *TypeDecoder
}
type decStackEntry struct {
Type *vdl.Type // Type of the value that we're decoding.
Index int // Index of the key, elem or field.
LenHint int // Length of the value, or -1 for unknown.
NextEntryType *vdl.Type // type for NextEntryValue* methods
Flag decStackFlag // properties of this stack entry
NextEntryData nextEntryData // properties of the next entry
}
// decFlag holds properties of the decoder.
type decFlag uint
const (
decFlagIgnoreNextStartValue decFlag = 0x1 // ignore the next call to StartValue
decFlagIsParentBytes decFlag = 0x2 // parent type is []byte or [N]byte
decFlagTypeIncomplete decFlag = 0x4 // type has dependencies on unsent types
decFlagSeparateTypeDec decFlag = 0x8 // type decoder is separate
// In FinishValue we need to clear both of these bits.
decFlagFinishValue decFlag = decFlagIgnoreNextStartValue | decFlagIsParentBytes
)
func (f decFlag) Set(bits decFlag) decFlag { return f | bits }
func (f decFlag) Clear(bits decFlag) decFlag { return f &^ bits }
func (f decFlag) IgnoreNextStartValue() bool { return f&decFlagIgnoreNextStartValue != 0 }
func (f decFlag) IsParentBytes() bool { return f&decFlagIsParentBytes != 0 }
func (f decFlag) TypeIncomplete() bool { return f&decFlagTypeIncomplete != 0 }
func (f decFlag) SeparateTypeDec() bool { return f&decFlagSeparateTypeDec != 0 }
// decStackFlag holds type or value properties of the stack entry.
type decStackFlag uint
const (
decStackFlagIsMapKey decStackFlag = 0x1 // key or elem for dfsNextType
decStackFlagIsAny decStackFlag = 0x2 // the static type is Any
decStackFlagIsOptional decStackFlag = 0x4 // the static type is Optional
decStackFlagFastRead decStackFlag = 0x8 // subtypes use ReadValue fastpath
)
func (f decStackFlag) FlipIsMapKey() decStackFlag { return f ^ decStackFlagIsMapKey }
func (f decStackFlag) IsMapKey() bool { return f&decStackFlagIsMapKey != 0 }
func (f decStackFlag) IsAny() bool { return f&decStackFlagIsAny != 0 }
func (f decStackFlag) IsOptional() bool { return f&decStackFlagIsOptional != 0 }
func (f decStackFlag) FastRead() bool { return f&decStackFlagFastRead != 0 }
// NewDecoder returns a new Decoder that reads from the given reader. The
// Decoder understands all formats generated by the Encoder.
func NewDecoder(r io.Reader) *Decoder {
buf := newDecbuf(r)
typeDec := newTypeDecoderInternal(buf)
return &Decoder{decoder81{
buf: buf,
typeDec: typeDec,
}}
}
// NewDecoderWithTypeDecoder returns a new Decoder that reads from the given
// reader. Types are decoded separately through the typeDec.
func NewDecoderWithTypeDecoder(r io.Reader, typeDec *TypeDecoder) *Decoder {
return &Decoder{decoder81{
buf: newDecbuf(r),
typeDec: typeDec,
flag: decFlagSeparateTypeDec,
}}
}
// Decoder returns d as a vdl.Decoder.
func (d *Decoder) Decoder() vdl.Decoder {
return &d.dec
}
// Decode reads the next value and stores it in value v. The type of v need not
// exactly match the type of the originally encoded value; decoding succeeds as
// long as the values are convertible.
func (d *Decoder) Decode(v interface{}) error {
return vdl.Read(&d.dec, v)
}
func (d *decoder81) IgnoreNextStartValue() {
d.flag = d.flag.Set(decFlagIgnoreNextStartValue)
}
func (d *decoder81) decodeWireType(wt *wireType) (TypeId, error) {
// Type messages are just a regularly encoded wireType, which is a union. To
// decode we pre-populate the stack with an entry for the wire type, and run
// the code-generated __VDLRead_wireType method.
tid, err := d.nextMessage()
if err != nil {
return 0, err
}
d.stack = append(d.stack, decStackEntry{
Type: wireTypeType,
Index: -1,
LenHint: 1, // wireType is a union
})
d.flag = d.flag.Set(decFlagIgnoreNextStartValue)
if err := __VDLRead_wireType(d, wt); err != nil {
return 0, err
}
return tid, nil
}
// readRawBytes fills in raw with the next value. It can be called for both
// top-level and internal values.
func (d *decoder81) readRawBytes(raw *RawBytes) error {
if d.flag.IgnoreNextStartValue() {
// If the user has already called StartValue on the decoder, it's harder to
// capture all the raw bytes, since the optional flag and length hints have
// already been decoded. So we simply disallow this from happening.
return errReadRawBytesAlreadyStarted
}
tt, err := d.dfsNextType()
if err != nil {
return err
}
// Handle top-level values. All types of values are supported, since we can
// simply copy the message bytes.
if len(d.stack) == 0 {
anyLen, err := d.peekValueByteLen(tt)
if err != nil {
return err
}
if err := d.decodeRaw(tt, anyLen, raw); err != nil {
return err
}
return d.endMessage()
}
// Handle internal values. Only any values are supported at the moment, since
// they come with a header that tells us the exact length to read.
//
// TODO(toddw): Handle other types, either by reading and skipping bytes based
// on the type, or by falling back to a decode / re-encode slowpath.
if tt.Kind() != vdl.Any {
return errReadRawBytesFromNonAny
}
ttElem, anyLen, err := d.readAnyHeader()
if err != nil {
return err
}
if ttElem == nil {
// This is a nil any value, which has already been read by readAnyHeader.
// We simply fill in RawBytes with the single WireCtrlNil byte.
raw.Version = d.buf.version
raw.Type = vdl.AnyType
raw.RefTypes = nil
raw.AnyLengths = nil
raw.Data = []byte{WireCtrlNil}
return nil
}
return d.decodeRaw(ttElem, anyLen, raw)
}
func (d *decoder81) StartValue(want *vdl.Type) error {
if d.flag.IgnoreNextStartValue() {
d.flag = d.flag.Clear(decFlagIgnoreNextStartValue)
return nil
}
tt, err := d.dfsNextType()
if err != nil {
return err
}
tt, lenHint, flag, err := d.setupType(tt, want)
if err != nil {
return err
}
d.stack = append(d.stack, decStackEntry{
Type: tt,
Index: -1,
LenHint: lenHint,
Flag: flag,
})
return nil
}
func (d *decoder81) setupType(tt, want *vdl.Type) (_ *vdl.Type, lenHint int, flag decStackFlag, _ error) {
// Handle any, which may be nil. We "dereference" non-nil any to the inner
// type. If that happens to be an optional, it's handled below.
if tt.Kind() == vdl.Any {
flag |= decStackFlagIsAny
var err error
switch tt, _, err = d.readAnyHeader(); {
case err != nil:
return nil, 0, 0, err
case tt == nil:
tt = vdl.AnyType // nil any
}
}
// Handle optional, which may be nil. Similar to any, we "dereference"
// non-nil optional to the inner type, which is never allowed to be another
// optional or any type.
if tt.Kind() == vdl.Optional {
flag |= decStackFlagIsOptional
// Read the WireCtrlNil code, but if it's not WireCtrlNil we need to keep
// the buffer as-is, since it's the first byte of the value, which may
// itself be another control code.
switch ctrl, err := binaryPeekControl(d.buf); {
case err != nil:
return nil, 0, 0, err
case ctrl == WireCtrlNil:
d.buf.SkipAvailable(1) // nil optional
default:
tt = tt.Elem() // non-nil optional
}
}
// Check compatibility between the actual type and the want type. Since
// compatibility applies to the entire static type, we only need to perform
// this check for top-level decoded values, and subsequently for decoded any
// values. We skip checking non-composite want types, since those will be
// naturally caught by the Decode* calls anyways.
if want != nil && (len(d.stack) == 0 || flag.IsAny()) {
switch want.Kind() {
case vdl.Optional, vdl.Array, vdl.List, vdl.Set, vdl.Map, vdl.Struct, vdl.Union:
if tt == want {
// Set FastRead flag, which will let us use the fastpath for ReadValue*
// in common cases. We can only use this fastpath if tt and want are
// identical, which ensures we don't need to perform any conversions.
if !flag.IsAny() && isFastReadParent(tt) {
flag |= decStackFlagFastRead
}
// Regardless of whether we can use the fastpath, there's no need to
// check compatibility if tt and want are identical.
} else {
if !vdl.Compatible(tt, want) {
return nil, 0, 0, errIncompatibleDecode(tt, want)
}
}
}
}
// Initialize LenHint for composite types.
switch tt.Kind() {
case vdl.Array, vdl.List, vdl.Set, vdl.Map:
// TODO(toddw): Handle sentry-terminated collections without a length hint.
len, err := binaryDecodeLenOrArrayLen(d.buf, tt)
if err != nil {
return nil, 0, 0, err
}
lenHint = len
case vdl.Union:
// Union shouldn't have a LenHint, but we abuse it in NextField as a
// convenience for detecting when fields are done, so we initialize it here.
// It has to be at least 1, since 0 will cause NextField to think that the
// union field has already been decoded.
lenHint = 1
case vdl.Struct:
// Struct shouldn't have a LenHint, but we abuse it in NextField as a
// convenience for detecting when fields are done, so we initialize it here.
lenHint = tt.NumField()
default:
lenHint = -1
}
if top := d.top(); top != nil && top.Type.IsBytes() {
d.flag = d.flag.Set(decFlagIsParentBytes)
} else {
d.flag = d.flag.Clear(decFlagIsParentBytes)
}
return tt, lenHint, flag, nil
}
func errIncompatibleDecode(tt *vdl.Type, want interface{}) error {
return fmt.Errorf("vom: incompatible decode from %v into %v", tt, want)
}
func (d *decoder81) FinishValue() error {
d.flag = d.flag.Clear(decFlagFinishValue)
stackTop := len(d.stack) - 1
if stackTop == -1 {
return errEmptyDecoderStack
}
d.stack = d.stack[:stackTop]
if stackTop == 0 {
return d.endMessage()
}
return nil
}
func (d *decoder81) top() *decStackEntry {
if stackTop := len(d.stack) - 1; stackTop >= 0 {
return &d.stack[stackTop]
}
return nil
}
// dfsNextType determines the type of the next value that we will decode, by
// walking the static type in DFS order. To bootstrap we retrieve the top-level
// type from the VOM value message.
func (d *decoder81) dfsNextType() (*vdl.Type, error) {
top := d.top()
if top == nil {
// Bootstrap: start decoding a new top-level value.
if !d.flag.SeparateTypeDec() {
if err := d.decodeTypeDefs(); err != nil {
return nil, err
}
}
tid, err := d.nextMessage()
if err != nil {
return nil, err
}
return d.typeDec.lookupType(tid)
}
// Return the next type from our composite types.
tt := top.Type
switch tt.Kind() {
case vdl.Array, vdl.List:
return tt.Elem(), nil
case vdl.Set:
return tt.Key(), nil
case vdl.Map:
top.Flag = top.Flag.FlipIsMapKey()
if top.Flag.IsMapKey() {
return tt.Key(), nil
} else {
return tt.Elem(), nil
}
case vdl.Union, vdl.Struct:
return tt.Field(top.Index).Type, nil
}
return nil, fmt.Errorf("vom: can't StartValue on %v", tt)
}
func (d *decoder81) NextEntry() (bool, error) {
// Our strategy is to increment top.Index until it reaches top.LenHint.
// Currently the LenHint is always set, so it's stronger than a hint.
//
// TODO(toddw): Handle sentry-terminated collections without a LenHint.
top := d.top()
if top == nil {
return false, errEmptyDecoderStack
}
// Increment index and check errors.
top.Index++
switch top.Type.Kind() {
case vdl.Array, vdl.List, vdl.Set, vdl.Map:
if top.Index > top.LenHint && top.LenHint >= 0 {
return false, fmt.Errorf("vom: NextEntry called after done, stack: %+v", d.stack)
}
default:
return false, fmt.Errorf("vom: NextEntry called on invalid type, stack: %+v", d.stack)
}
return top.Index == top.LenHint, nil
}
func (d *decoder81) NextField() (int, error) {
top := d.top()
if top == nil {
return -1, errEmptyDecoderStack
}
// Increment index and check errors. Note that the actual top.Index is
// decoded from the buf data stream; we use top.LenHint to help detect when
// the fields are done, and to detect invalid calls after we're done.
top.Index++
switch top.Type.Kind() {
case vdl.Union, vdl.Struct:
if top.Index > top.LenHint {
return -1, fmt.Errorf("vom: NextField called after done, stack: %+v", d.stack)
}
default:
return -1, fmt.Errorf("vom: NextField called on invalid type, stack: %+v", d.stack)
}
var field int
switch top.Type.Kind() {
case vdl.Union:
if top.Index == top.LenHint {
// We know we're done since we set LenHint=Index+1 the first time around,
// and we incremented the index above.
return -1, nil
}
// Decode the union field index.
switch index, err := binaryDecodeUint(d.buf); {
case err != nil:
return -1, err
case index >= uint64(top.Type.NumField()):
return -1, verror.New(errIndexOutOfRange, nil)
default:
// Set LenHint=Index+1 so that we'll know we're done next time around.
field = int(index)
top.Index = field
top.LenHint = field + 1
}
case vdl.Struct:
// Handle the end-of-struct sentry.
switch ok, err := binaryDecodeControlOnly(d.buf, WireCtrlEnd); {
case err != nil:
return -1, err
case ok:
// Set Index=LenHint to ensure repeated calls will fail.
top.Index = top.LenHint
return -1, nil
}
// Decode the struct field index.
switch index, err := binaryDecodeUint(d.buf); {
case err != nil:
return -1, err
case index >= uint64(top.Type.NumField()):
return -1, verror.New(errIndexOutOfRange, nil)
default:
field = int(index)
top.Index = field
}
}
return field, nil
}
func (d *decoder81) Type() *vdl.Type {
if top := d.top(); top != nil {
return top.Type
}
return nil
}
func (d *decoder81) IsAny() bool {
if top := d.top(); top != nil {
return top.Flag.IsAny()
}
return false
}
func (d *decoder81) IsOptional() bool {
if top := d.top(); top != nil {
return top.Flag.IsOptional()
}
return false
}
func (d *decoder81) IsNil() bool {
if top := d.top(); top != nil {
// Becuase of the "dereferencing" we do, the only time the type is any or
// optional is when it's nil.
return top.Type == vdl.AnyType || top.Type.Kind() == vdl.Optional
}
return false
}
func (d *decoder81) Index() int {
if top := d.top(); top != nil {
return top.Index
}
return -1
}
func (d *decoder81) LenHint() int {
if top := d.top(); top != nil {
// Note that union and struct shouldn't have a LenHint, but we abuse it in
// NextField as a convenience for detecting when fields are done, so an
// "arbitrary" value is returned here. Users shouldn't be looking at it for
// union and struct anyways.
return top.LenHint
}
return -1
}
func (d *decoder81) DecodeBool() (bool, error) {
tt := d.Type()
if tt == nil {
return false, errEmptyDecoderStack
}
if tt.Kind() == vdl.Bool {
return binaryDecodeBool(d.buf)
}
return false, errIncompatibleDecode(tt, "bool")
}
func (d *decoder81) DecodeString() (string, error) {
tt := d.Type()
if tt == nil {
return "", errEmptyDecoderStack
}
switch tt.Kind() {
case vdl.String:
return binaryDecodeString(d.buf)
case vdl.Enum:
return d.binaryDecodeEnum(tt)
}
return "", errIncompatibleDecode(tt, "string")
}
func (d *decoder81) binaryDecodeEnum(tt *vdl.Type) (string, error) {
index, err := binaryDecodeUint(d.buf)
switch {
case err != nil:
return "", err
case index >= uint64(tt.NumEnumLabel()):
return "", fmt.Errorf("vom: enum index %d out of range, %v", index, tt)
}
return tt.EnumLabel(int(index)), nil
}
func (d *decoder81) binaryDecodeByte() (byte, error) {
// Handle a special-case where normally single bytes are written out as
// variable sized numbers, which use 2 bytes to encode bytes > 127. But each
// byte contained in a list or array is written out as one byte. E.g.
// byte(0x81) -> 0xFF81 : single byte with variable-size
// []byte("\x81\x82") -> 0x028182 : each elem byte encoded as one byte
if d.flag.IsParentBytes() {
return d.buf.ReadByte()
}
x, err := binaryDecodeUint(d.buf)
return byte(x), err
}
func (d *decoder81) DecodeUint(bitlen int) (uint64, error) {
tt := d.Type()
if tt == nil {
return 0, errEmptyDecoderStack
}
return d.decodeUint(tt, uint(bitlen))
}
func (d *decoder81) decodeUint(tt *vdl.Type, ubitlen uint) (uint64, error) {
const errFmt = "vom: conversion from %v into uint%d loses precision: %v"
switch tt.Kind() {
case vdl.Byte:
x, err := d.binaryDecodeByte()
if err != nil {
return 0, err
}
return uint64(x), err
case vdl.Uint16, vdl.Uint32, vdl.Uint64:
x, err := binaryDecodeUint(d.buf)
if err != nil {
return 0, err
}
if shift := 64 - ubitlen; x != (x<<shift)>>shift {
return 0, fmt.Errorf(errFmt, tt, ubitlen, x)
}
return x, nil
case vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64:
x, err := binaryDecodeInt(d.buf)
if err != nil {
return 0, err
}
ux := uint64(x)
if shift := 64 - ubitlen; x < 0 || ux != (ux<<shift)>>shift {
return 0, fmt.Errorf(errFmt, tt, ubitlen, x)
}
return ux, nil
case vdl.Float32, vdl.Float64:
x, err := binaryDecodeFloat(d.buf)
if err != nil {
return 0, err
}
ux := uint64(x)
if shift := 64 - ubitlen; x != float64(ux) || ux != (ux<<shift)>>shift {
return 0, fmt.Errorf(errFmt, tt, ubitlen, x)
}
return ux, nil
}
return 0, errIncompatibleDecode(tt, fmt.Sprintf("uint%d", ubitlen))
}
func (d *decoder81) DecodeInt(bitlen int) (int64, error) {
tt := d.Type()
if tt == nil {
return 0, errEmptyDecoderStack
}
return d.decodeInt(tt, uint(bitlen))
}
func (d *decoder81) decodeInt(tt *vdl.Type, ubitlen uint) (int64, error) {
const errFmt = "vom: conversion from %v into int%d loses precision: %v"
switch tt.Kind() {
case vdl.Byte:
x, err := d.binaryDecodeByte()
if err != nil {
return 0, err
}
// The only case that fails is if we're converting byte(x) to int8, and x
// uses more than 7 bits (i.e. is greater than 127).
if ubitlen <= 8 && x > 0x7f {
return 0, fmt.Errorf(errFmt, tt, ubitlen, x)
}
return int64(x), nil
case vdl.Uint16, vdl.Uint32, vdl.Uint64:
x, err := binaryDecodeUint(d.buf)
if err != nil {
return 0, err
}
ix := int64(x)
// The shift uses 65 since the topmost bit is the sign bit. I.e. 32 bit
// numbers should be shifted by 33 rather than 32.
if shift := 65 - ubitlen; ix < 0 || x != (x<<shift)>>shift {
return 0, fmt.Errorf(errFmt, tt, ubitlen, x)
}
return ix, nil
case vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64:
x, err := binaryDecodeInt(d.buf)
if err != nil {
return 0, err
}
if shift := 64 - ubitlen; x != (x<<shift)>>shift {
return 0, fmt.Errorf(errFmt, tt, ubitlen, x)
}
return x, nil
case vdl.Float32, vdl.Float64:
x, err := binaryDecodeFloat(d.buf)
if err != nil {
return 0, err
}
ix := int64(x)
if shift := 64 - ubitlen; x != float64(ix) || ix != (ix<<shift)>>shift {
return 0, fmt.Errorf(errFmt, tt, ubitlen, x)
}
return ix, nil
}
return 0, errIncompatibleDecode(tt, fmt.Sprintf("int%d", ubitlen))
}
func (d *decoder81) DecodeFloat(bitlen int) (float64, error) {
tt := d.Type()
if tt == nil {
return 0, errEmptyDecoderStack
}
return d.decodeFloat(tt, uint(bitlen))
}
func (d *decoder81) decodeFloat(tt *vdl.Type, ubitlen uint) (float64, error) {
const errFmt = "vom: conversion from %v into float%d loses precision: %v"
switch tt.Kind() {
case vdl.Byte:
x, err := d.binaryDecodeByte()
if err != nil {
return 0, err
}
return float64(x), nil
case vdl.Uint16, vdl.Uint32, vdl.Uint64:
x, err := binaryDecodeUint(d.buf)
if err != nil {
return 0, err
}
var max uint64
if ubitlen > 32 {
max = float64MaxInt
} else {
max = float32MaxInt
}
if x > max {
return 0, fmt.Errorf(errFmt, tt, ubitlen, x)
}
return float64(x), nil
case vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64:
x, err := binaryDecodeInt(d.buf)
if err != nil {
return 0, err
}
var min, max int64
if ubitlen > 32 {
min, max = float64MinInt, float64MaxInt
} else {
min, max = float32MinInt, float32MaxInt
}
if x < min || x > max {
return 0, fmt.Errorf(errFmt, tt, ubitlen, x)
}
return float64(x), nil
case vdl.Float32, vdl.Float64:
x, err := binaryDecodeFloat(d.buf)
if err != nil {
return 0, err
}
if ubitlen <= 32 && (x < -math.MaxFloat32 || x > math.MaxFloat32) {
return 0, fmt.Errorf(errFmt, tt, ubitlen, x)
}
return x, nil
}
return 0, errIncompatibleDecode(tt, fmt.Sprintf("float%d", ubitlen))
}
func (d *decoder81) DecodeBytes(fixedLen int, v *[]byte) error {
top := d.top()
if top == nil {
return errEmptyDecoderStack
}
tt := top.Type
if !tt.IsBytes() {
return vdl.DecodeConvertedBytes(d, fixedLen, v)
}
return d.decodeBytes(tt, top.LenHint, fixedLen, v)
}
func (d *decoder81) decodeBytes(tt *vdl.Type, lenHint, fixedLen int, v *[]byte) error {
switch {
case lenHint == -1:
return fmt.Errorf("vom: LenHint is currently required, %v", tt)
case fixedLen >= 0 && fixedLen != lenHint:
return fmt.Errorf("vom: got %d bytes, want fixed len %d, %v", lenHint, fixedLen, tt)
case lenHint == 0:
*v = nil
return nil
case fixedLen >= 0:
// 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.
*v = (*v)[:lenHint]
default:
*v = make([]byte, lenHint)
}
return d.buf.ReadIntoBuf(*v)
}
func (d *decoder81) DecodeTypeObject() (*vdl.Type, error) {
tt := d.Type()
if tt == nil {
return nil, errEmptyDecoderStack
}
if tt != vdl.TypeObjectType {
return nil, errIncompatibleDecode(tt, "typeobject")
}
return d.binaryDecodeType()
}
func (d *decoder81) binaryDecodeType() (*vdl.Type, error) {
typeIndex, err := binaryDecodeUint(d.buf)
if err != nil {
return nil, err
}
tid, err := d.refTypes.ReferencedTypeId(typeIndex)
if err != nil {
return nil, err
}
return d.typeDec.lookupType(tid)
}
func (d *decoder81) SkipValue() error {
tt, err := d.dfsNextType()
if err != nil {
return err
}
if len(d.stack) == 0 {
// Handle top-level values. It's easy to determine the byte length of the
// value, so we can just skip the bytes.
valueLen, err := d.peekValueByteLen(tt)
if err != nil {
return err
}
if err := d.buf.Skip(valueLen); err != nil {
return err
}
return d.endMessage()
}
return d.skipValue(tt)
}