blob: db90b98f894a8fd69087e42f2f1faeab032f8c8c [file] [log] [blame]
package vom
import (
"errors"
"fmt"
"io"
"os"
"reflect"
"v.io/v23/vdl"
)
var (
errDecodeNil = errors.New("invalid decode into nil interface{}")
errDecodeNilRawValue = errors.New("invalid decode into nil *RawValue")
)
// Decoder manages the receipt and unmarshaling of typed values from the other
// side of a connection.
type Decoder struct {
dec decoder
}
type decoder interface {
Decode(target vdl.Target) error
DecodeRaw(raw *RawValue) error
Ignore() error
}
// 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)))
}
// 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, error) {
buf, types := newDecbuf(r), newDecoderTypes()
magic, err := buf.PeekByte()
if err != nil {
return nil, fmt.Errorf("error reading magic byte %v", err)
}
if magic != binaryMagicByte {
return nil, fmt.Errorf("bad magic byte, got %x, want %x", magic, binaryMagicByte)
}
buf.Skip(1)
return &Decoder{newBinaryDecoder(buf, types)}, nil
}
// Decode reads the next value from the reader 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 compatible.
//
// Types that are special-cased, only for v:
// *RawValue - Store raw (uninterpreted) bytes in v.
//
// Types that are special-cased, recursively throughout v:
// *vdl.Value - Decode into v.
// reflect.Value - Decode into v, which must be settable.
//
// Decoding into a RawValue captures the value in a raw form, which may be
// subsequently passed to an Encoder for transcoding.
//
// Decode(nil) always returns an error. Use Ignore() to ignore the next value.
func (d *Decoder) Decode(v interface{}) error {
switch tv := v.(type) {
case nil:
return errDecodeNil
case *RawValue:
if tv == nil {
return errDecodeNilRawValue
}
return d.dec.DecodeRaw(tv)
}
target, err := vdl.ReflectTarget(reflect.ValueOf(v))
if err != nil {
return err
}
return d.dec.Decode(target)
}
// Ignore ignores the next value from the reader.
func (d *Decoder) Ignore() error {
return d.dec.Ignore()
}