Vom cleanups leftover from the transition to new coders.

This CL just moves and renames code and tests around into more
logical places.  No functionality has changed.

Change-Id: I1b58a4367eae8d91fc44dba202b1a3039fa74403
diff --git a/vdl/convert_test.go b/vdl/convert_test.go
index 07bd8dc..e95d85c 100644
--- a/vdl/convert_test.go
+++ b/vdl/convert_test.go
@@ -17,6 +17,7 @@
 	"testing"
 
 	"v.io/v23/vdl"
+	"v.io/v23/vdl/vdltest"
 	"v.io/v23/verror"
 )
 
@@ -1225,3 +1226,24 @@
 		t.Errorf("got %#v, want %#v", got, want)
 	}
 }
+
+func TestConvertNew(t *testing.T) {
+	for _, entry := range vdltest.AllPass() {
+		rvTargetPtr := reflect.New(entry.Target.Type())
+		if err := vdl.Convert(rvTargetPtr.Interface(), entry.Source.Interface()); err != nil {
+			t.Errorf("%s: Convert failed: %v", entry.Name(), err)
+		}
+		if got, want := rvTargetPtr.Elem(), entry.Target; !vdl.DeepEqualReflect(got, want) {
+			t.Errorf("%s\nGOT  %v\nWANT %v", entry.Name(), got, want)
+		}
+	}
+}
+
+func TestConvertFailNew(t *testing.T) {
+	for _, entry := range vdltest.AllFail() {
+		rvTargetPtr := reflect.New(entry.Target.Type())
+		if err := vdl.Convert(rvTargetPtr.Interface(), entry.Source.Interface()); err == nil {
+			t.Errorf("%s: Convert passed, wanted failure", entry.Name())
+		}
+	}
+}
diff --git a/vdl/new_convert_test.go b/vdl/new_convert_test.go
deleted file mode 100644
index 57573a5..0000000
--- a/vdl/new_convert_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2015 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.
-
-// +build newvdltests
-
-package vdl_test
-
-import (
-	"reflect"
-	"testing"
-
-	"v.io/v23/vdl"
-	"v.io/v23/vdl/vdltest"
-)
-
-func TestConvertNew(t *testing.T) {
-	for _, entry := range vdltest.AllPass() {
-		rvTargetPtr := reflect.New(entry.Target.Type())
-		if err := vdl.Convert(rvTargetPtr.Interface(), entry.Source.Interface()); err != nil {
-			t.Errorf("%s: Convert failed: %v", entry.Name(), err)
-		}
-		if got, want := rvTargetPtr.Elem(), entry.Target; !vdl.DeepEqualReflect(got, want) {
-			t.Errorf("%s\nGOT  %v\nWANT %v", entry.Name(), got, want)
-		}
-	}
-}
-
-func TestConvertFailNew(t *testing.T) {
-	for _, entry := range vdltest.AllFail() {
-		rvTargetPtr := reflect.New(entry.Target.Type())
-		if err := vdl.Convert(rvTargetPtr.Interface(), entry.Source.Interface()); err == nil {
-			t.Errorf("%s: Convert passed, wanted failure", entry.Name())
-		}
-	}
-}
diff --git a/vdl/new_value_reader_test.go b/vdl/new_value_reader_test.go
deleted file mode 100644
index fed2366..0000000
--- a/vdl/new_value_reader_test.go
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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.
-
-// +build newvdltests
-
-package vdl_test
-
-import (
-	"testing"
-
-	"v.io/v23/vdl"
-	"v.io/v23/vdl/vdltest"
-)
-
-func TestValueReader(t *testing.T) {
-	for _, entry := range vdltest.ToEntryValues(vdltest.AllPass()) {
-		out := vdl.ZeroValue(entry.Target.Type())
-		if err := out.VDLRead(entry.Source.Decoder()); err != nil {
-			t.Errorf("%s: VDLRead failed: %v", entry.Name(), err)
-			continue
-		}
-		if got, want := out, entry.Target; !vdl.EqualValue(got, want) {
-			t.Errorf("%s\nGOT  %v\nWANT %v", entry.Name(), got, want)
-		}
-	}
-}
diff --git a/vdl/value_reader_test.go b/vdl/value_reader_test.go
index 03bee7d..d21926c 100644
--- a/vdl/value_reader_test.go
+++ b/vdl/value_reader_test.go
@@ -8,18 +8,18 @@
 	"testing"
 
 	"v.io/v23/vdl"
-	"v.io/v23/vom/testdata/data81"
+	"v.io/v23/vdl/vdltest"
 )
 
-func TestValueRead(t *testing.T) {
-	for _, test := range data81.Tests {
-		out := vdl.ZeroValue(test.Value.Type())
-		if err := out.VDLRead(test.Value.Decoder()); err != nil {
-			t.Errorf("%s: error in ValueRead: %v", test.Name, err)
+func TestValueReader(t *testing.T) {
+	for _, entry := range vdltest.ToEntryValues(vdltest.AllPass()) {
+		out := vdl.ZeroValue(entry.Target.Type())
+		if err := out.VDLRead(entry.Source.Decoder()); err != nil {
+			t.Errorf("%s: VDLRead failed: %v", entry.Name(), err)
 			continue
 		}
-		if !vdl.EqualValue(test.Value, out) {
-			t.Errorf("%s: got %v, want %v", test.Name, out, test.Value)
+		if got, want := out, entry.Target; !vdl.EqualValue(got, want) {
+			t.Errorf("%s\nGOT  %v\nWANT %v", entry.Name(), got, want)
 		}
 	}
 }
diff --git a/vom/.api b/vom/.api
index 30322e3..f7c4048 100644
--- a/vom/.api
+++ b/vom/.api
@@ -59,7 +59,6 @@
 pkg vom, func RawBytesOf(interface{}) *RawBytes
 pkg vom, func VDLReadPrimitive(vdl.Decoder, *Primitive) error
 pkg vom, func VersionedEncode(Version, interface{}) ([]byte, error)
-pkg vom, func XRawBytesFromValue(interface{}) (*RawBytes, error)
 pkg vom, method (*ControlKind) Set(string) error
 pkg vom, method (*ControlKind) VDLRead(vdl.Decoder) error
 pkg vom, method (*Decoder) Decode(interface{}) error
diff --git a/vom/binary_util_test.go b/vom/binary_util_test.go
index 70ed50a..1d98ab1 100644
--- a/vom/binary_util_test.go
+++ b/vom/binary_util_test.go
@@ -11,14 +11,6 @@
 	"testing"
 )
 
-func hex2Bin(t *testing.T, hex string) []byte {
-	binStr, err := binFromHexPat(hex)
-	if err != nil {
-		t.Fatalf("error converting %q to binary: %v", hex, err)
-	}
-	return []byte(binStr)
-}
-
 func TestBinaryEncodeDecode(t *testing.T) {
 	tests := []struct {
 		v   interface{}
diff --git a/vom/convert_test.go b/vom/convert_test.go
index 06ffb52..f7c89e6 100644
--- a/vom/convert_test.go
+++ b/vom/convert_test.go
@@ -7,7 +7,6 @@
 import (
 	"bytes"
 	"fmt"
-	"io"
 	"reflect"
 	"strings"
 	"sync"
@@ -139,43 +138,3 @@
 	}
 	return nil
 }
-
-// In concurrent modes, one goroutine may try to read vom types before they are
-// actually sent by other goroutine. We use a simple buffered pipe to provide
-// blocking read since bytes.Buffer will return EOF in this case.
-type pipe struct {
-	b      bytes.Buffer
-	m      sync.Mutex
-	c      sync.Cond
-	closed bool
-}
-
-func newPipe() (io.ReadCloser, io.WriteCloser) {
-	p := &pipe{}
-	p.c.L = &p.m
-	return p, p
-}
-
-func (r *pipe) Read(p []byte) (n int, err error) {
-	r.m.Lock()
-	defer r.m.Unlock()
-	for r.b.Len() == 0 || r.closed {
-		r.c.Wait()
-	}
-	return r.b.Read(p)
-}
-
-func (p *pipe) Close() error {
-	p.m.Lock()
-	p.closed = true
-	p.c.Broadcast()
-	p.m.Unlock()
-	return nil
-}
-
-func (w *pipe) Write(p []byte) (n int, err error) {
-	w.m.Lock()
-	defer w.m.Unlock()
-	defer w.c.Signal()
-	return w.b.Write(p)
-}
diff --git a/vom/decoder.go b/vom/decoder.go
index 1515735..bcbb932 100644
--- a/vom/decoder.go
+++ b/vom/decoder.go
@@ -1,414 +1,800 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
+// 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"
 )
 
-// TODO(toddw): Merge this file with xdecoder.go
-
-var (
-	errDecodeZeroTypeID         = verror.Register(pkgPath+".errDecodeZeroTypeID", verror.NoRetry, "{1:}{2:} vom: zero type id{:_}")
-	errIndexOutOfRange          = verror.Register(pkgPath+".errIndexOutOfRange", verror.NoRetry, "{1:}{2:} vom: index out of range{:_}")
-	errLeftOverBytes            = verror.Register(pkgPath+".errLeftOverBytes", verror.NoRetry, "{1:}{2:} vom: {3} leftover bytes{:_}")
-	errUnexpectedControlByte    = verror.Register(pkgPath+".errUnexpectedControlByte", verror.NoRetry, "{1:}{2:} vom: unexpected control byte {3}{:_}")
-	errDecodeValueUnhandledType = verror.Register(pkgPath+".errDecodeValueUnhandledType", verror.NoRetry, "{1:}{2:} vom: decodeValue unhandled type {3}{:_}")
-	errIgnoreValueUnhandledType = verror.Register(pkgPath+".errIgnoreValueUnhandledType", verror.NoRetry, "{1:}{2:} vom: ignoreValue unhandled type {3}{:_}")
-	errInvalidTypeIdIndex       = verror.Register(pkgPath+".errInvalidTypeIdIndex", verror.NoRetry, "{1:}{2:} vom: value referenced invalid index into type id table {:_}")
-	errInvalidAnyIndex          = verror.Register(pkgPath+".errInvalidAnyIndex", verror.NoRetry, "{1:}{2:} vom: value referenced invalid index into anyLen table {:_}")
+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)
 )
 
-func (d *decoder81) decodeTypeDefs() error {
-	for {
-		typeNext, err := d.typeIsNext()
+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 !typeNext {
-			return nil
-		}
-		if err := d.typeDec.readSingleType(); err != nil {
+		if err := d.decodeRaw(tt, anyLen, raw); err != nil {
 			return err
 		}
+		return d.endMessage()
 	}
-}
-
-// peekValueByteLen returns the byte length of the next value.
-func (d *decoder81) peekValueByteLen(tt *vdl.Type) (int, error) {
-	if hasChunkLen(tt) {
-		// Use the explicit message length.
-		return d.buf.lim, nil
+	// 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
 	}
-	// No explicit message length, but the length can be computed.
-	switch {
-	case tt.Kind() == vdl.Array && tt.IsBytes():
-		// Byte arrays are exactly their length and encoded with 1-byte header.
-		return tt.Len() + 1, nil
-	case tt.Kind() == vdl.String || tt.IsBytes():
-		// Strings and byte lists are encoded with a length header.
-		strlen, bytelen, err := binaryPeekUint(d.buf)
-		switch {
-		case err != nil:
-			return 0, err
-		case strlen > maxBinaryMsgLen:
-			return 0, verror.New(errMsgLen, nil, maxBinaryMsgLen)
-		}
-		return int(strlen) + bytelen, nil
-	default:
-		// Must be a primitive, which is encoded as an underlying uint.
-		return binaryPeekUintByteLen(d.buf)
-	}
-}
-
-func (d *decoder81) decodeRaw(tt *vdl.Type, valLen int, raw *RawBytes) error {
-	raw.Version = d.buf.version
-	raw.Type = tt
-	raw.Data = make([]byte, valLen)
-	if err := d.buf.ReadIntoBuf(raw.Data); err != nil {
+	ttElem, anyLen, err := d.readAnyHeader()
+	if err != nil {
 		return err
 	}
-	refTypeLen := len(d.refTypes.tids)
-	if cap(raw.RefTypes) >= refTypeLen {
-		raw.RefTypes = raw.RefTypes[:refTypeLen]
-	} else {
-		raw.RefTypes = make([]*vdl.Type, refTypeLen)
+	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
 	}
-	for i, tid := range d.refTypes.tids {
-		var err error
-		if raw.RefTypes[i], err = d.typeDec.lookupType(tid); err != nil {
-			return err
-		}
+	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
 	}
-	raw.AnyLengths = d.refAnyLens.lens
+	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) readAnyHeader() (*vdl.Type, int, error) {
-	// Handle WireCtrlNil.
-	switch ok, err := binaryDecodeControlOnly(d.buf, WireCtrlNil); {
-	case err != nil:
-		return nil, 0, err
-	case ok:
-		return nil, 0, nil // nil any
-	}
-	// Read the index of the referenced type id.
-	typeIndex, err := binaryDecodeUint(d.buf)
-	if err != nil {
-		return nil, 0, err
-	}
-	var tid TypeId
-	if d.buf.version == Version80 {
-		tid = TypeId(typeIndex)
-	} else if tid, err = d.refTypes.ReferencedTypeId(typeIndex); err != nil {
-		return nil, 0, err
-	}
-	// Look up the referenced type id.
-	ttElem, err := d.typeDec.lookupType(tid)
-	if err != nil {
-		return nil, 0, err
-	}
-	var anyLen int
-	if d.buf.version != Version80 {
-		// Read and lookup the index of the any byte length.  Reference the any len,
-		// even if it isn't used, to report missing references.
-		lenIndex, err := binaryDecodeUint(d.buf)
-		if err != nil {
-			return nil, 0, err
-		}
-		if anyLen, err = d.refAnyLens.ReferencedAnyLen(lenIndex); err != nil {
-			return nil, 0, err
-		}
-	}
-	return ttElem, anyLen, nil
-}
-
-func (d *decoder81) skipValue(tt *vdl.Type) error {
-	if tt.IsBytes() {
-		len, err := binaryDecodeLenOrArrayLen(d.buf, tt)
-		if err != nil {
-			return err
-		}
-		return d.buf.Skip(len)
-	}
-	switch kind := tt.Kind(); kind {
-	case vdl.Bool:
-		return d.buf.Skip(1)
-	case vdl.Byte, vdl.Uint16, vdl.Uint32, vdl.Uint64, vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64, vdl.Float32, vdl.Float64, vdl.Enum, vdl.TypeObject:
-		// The underlying encoding of all these types is based on uint.
-		return binarySkipUint(d.buf)
-	case vdl.String:
-		return binarySkipString(d.buf)
-	case vdl.Array, vdl.List, vdl.Set, vdl.Map:
-		len, err := binaryDecodeLenOrArrayLen(d.buf, tt)
-		if err != nil {
-			return err
-		}
-		for ix := 0; ix < len; ix++ {
-			if kind == vdl.Set || kind == vdl.Map {
-				if err := d.skipValue(tt.Key()); err != nil {
-					return err
-				}
-			}
-			if kind == vdl.Array || kind == vdl.List || kind == vdl.Map {
-				if err := d.skipValue(tt.Elem()); err != nil {
-					return err
-				}
-			}
-		}
-		return nil
-	case vdl.Struct:
-		// Loop through decoding the 0-based field index and corresponding field.
-		for {
-			switch ok, err := binaryDecodeControlOnly(d.buf, WireCtrlEnd); {
-			case err != nil:
-				return err
-			case ok:
-				return nil // end of struct
-			}
-			switch index, err := binaryDecodeUint(d.buf); {
-			case err != nil:
-				return err
-			case index >= uint64(tt.NumField()):
-				return verror.New(errIndexOutOfRange, nil)
-			default:
-				ttfield := tt.Field(int(index))
-				if err := d.skipValue(ttfield.Type); err != nil {
-					return err
-				}
-			}
-		}
-	case vdl.Union:
-		switch index, err := binaryDecodeUint(d.buf); {
+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 err
-		case index >= uint64(tt.NumField()):
-			return verror.New(errIndexOutOfRange, nil)
-		default:
-			ttfield := tt.Field(int(index))
-			return d.skipValue(ttfield.Type)
+			return nil, 0, 0, err
+		case tt == nil:
+			tt = vdl.AnyType // nil any
 		}
-	case vdl.Optional:
+	}
+	// 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 err
+			return nil, 0, 0, err
 		case ctrl == WireCtrlNil:
 			d.buf.SkipAvailable(1) // nil optional
-			return nil
 		default:
-			return d.skipValue(tt.Elem()) // non-nil optional
+			tt = tt.Elem() // non-nil optional
 		}
-	case vdl.Any:
-		switch ok, err := binaryDecodeControlOnly(d.buf, WireCtrlNil); {
-		case err != nil:
-			return err
-		case ok:
-			return nil // nil any
-		}
-		switch index, err := binaryDecodeUint(d.buf); {
-		case err != nil:
-			return err
-		default:
-			tid, err := d.refTypes.ReferencedTypeId(index)
-			if err != nil {
-				return err
+	}
+	// 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)
+				}
 			}
-			ttElem, err := d.typeDec.lookupType(tid)
-			if err != nil {
-				return err
-			}
-			return d.skipValue(ttElem)
 		}
+	}
+	// 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:
-		return verror.New(errIgnoreValueUnhandledType, nil, tt)
+		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 (d *decoder81) nextMessage() (TypeId, error) {
-	if leftover := d.buf.RemoveLimit(); leftover > 0 {
-		return 0, verror.New(errLeftOverBytes, nil, leftover)
-	}
-	// Decode version byte, if not already decoded.
-	if d.buf.version == 0 {
-		version, err := d.buf.ReadByte()
-		if err != nil {
-			return 0, verror.New(errEndedBeforeVersionByte, nil, err)
-		}
-		d.buf.version = Version(version)
-		if !isAllowedVersion(d.buf.version) {
-			return 0, verror.New(errBadVersionByte, nil, d.buf.version)
-		}
-	}
-	// Decode the next message id.
-	incomplete, err := binaryDecodeControlOnly(d.buf, WireCtrlTypeIncomplete)
-	if err != nil {
-		return 0, err
-	}
-	mid, err := binaryDecodeInt(d.buf)
-	if err != nil {
-		return 0, err
-	}
-	if incomplete {
-		if mid >= 0 {
-			// TypeIncomplete must be followed with a type message.
-			return 0, verror.New(errInvalid, nil)
-		}
-		d.flag = d.flag.Set(decFlagTypeIncomplete)
-	} else if mid < 0 {
-		d.flag = d.flag.Clear(decFlagTypeIncomplete)
-	}
-	// TODO(toddw): Clean up the logic below.
-	var tid TypeId
-	var hasAny, hasTypeObject, hasLength bool
-	switch {
-	case mid < 0:
-		tid = TypeId(-mid)
-		hasLength = true
-		hasAny = false
-		hasTypeObject = false
-	case mid > 0:
-		tid = TypeId(mid)
-		t, err := d.typeDec.lookupType(tid)
-		if err != nil {
-			return 0, err
-		}
-		hasLength = hasChunkLen(t)
-		hasAny = containsAny(t)
-		hasTypeObject = containsTypeObject(t)
-	default:
-		return 0, verror.New(errDecodeZeroTypeID, nil)
-	}
-
-	if (hasAny || hasTypeObject) && d.buf.version != Version80 {
-		l, err := binaryDecodeUint(d.buf)
-		if err != nil {
-			return 0, err
-		}
-		for i := 0; i < int(l); i++ {
-			refId, err := binaryDecodeUint(d.buf)
-			if err != nil {
-				return 0, err
-			}
-			d.refTypes.AddTypeID(TypeId(refId))
-		}
-	}
-	if hasAny && d.buf.version != Version80 {
-		l, err := binaryDecodeUint(d.buf)
-		if err != nil {
-			return 0, err
-		}
-		for i := 0; i < int(l); i++ {
-			refAnyLen, err := binaryDecodeLen(d.buf)
-			if err != nil {
-				return 0, err
-			}
-			d.refAnyLens.AddAnyLen(refAnyLen)
-		}
-	}
-
-	if hasLength {
-		chunkLen, err := binaryDecodeUint(d.buf)
-		if err != nil {
-			return 0, err
-		}
-		d.buf.SetLimit(int(chunkLen))
-	}
-
-	return tid, nil
+func errIncompatibleDecode(tt *vdl.Type, want interface{}) error {
+	return fmt.Errorf("vom: incompatible decode from %v into %v", tt, want)
 }
 
-func (d *decoder81) typeIsNext() (bool, error) {
-	if d.buf.version == 0 {
-		version, err := d.buf.ReadByte()
-		if err != nil {
-			return false, verror.New(errEndedBeforeVersionByte, nil, err)
-		}
-		d.buf.version = Version(version)
-		if !isAllowedVersion(d.buf.version) {
-			return false, verror.New(errBadVersionByte, nil, d.buf.version)
-		}
+func (d *decoder81) FinishValue() error {
+	d.flag = d.flag.Clear(decFlagFinishValue)
+	stackTop := len(d.stack) - 1
+	if stackTop == -1 {
+		return errEmptyDecoderStack
 	}
-	switch ctrl, err := binaryPeekControl(d.buf); {
-	case err != nil:
-		return false, err
-	case ctrl == WireCtrlTypeIncomplete:
-		return true, nil
-	case ctrl != 0:
-		return false, verror.New(errBadControlCode, nil, ctrl)
-	}
-	mid, _, err := binaryPeekInt(d.buf)
-	if err != nil {
-		return false, err
-	}
-	return mid < 0, nil
-}
-
-func (d *decoder81) endMessage() error {
-	if leftover := d.buf.RemoveLimit(); leftover > 0 {
-		return verror.New(errLeftOverBytes, nil, leftover)
-	}
-	if err := d.refTypes.Reset(); err != nil {
-		return err
-	}
-	if err := d.refAnyLens.Reset(); err != nil {
-		return err
+	d.stack = d.stack[:stackTop]
+	if stackTop == 0 {
+		return d.endMessage()
 	}
 	return nil
 }
 
-type referencedTypes struct {
-	tids   []TypeId
-	marker int
-}
-
-func (refTypes *referencedTypes) Reset() (err error) {
-	refTypes.tids = refTypes.tids[:0]
-	refTypes.marker = 0
-	return
-}
-
-func (refTypes *referencedTypes) AddTypeID(tid TypeId) {
-	refTypes.tids = append(refTypes.tids, tid)
-}
-
-func (refTypes *referencedTypes) ReferencedTypeId(index uint64) (TypeId, error) {
-	if index >= uint64(len(refTypes.tids)) {
-		return 0, verror.New(errInvalidTypeIdIndex, nil)
+func (d *decoder81) top() *decStackEntry {
+	if stackTop := len(d.stack) - 1; stackTop >= 0 {
+		return &d.stack[stackTop]
 	}
-	return refTypes.tids[index], nil
+	return nil
 }
 
-func (refTypes *referencedTypes) Mark() {
-	refTypes.marker = len(refTypes.tids)
-}
-
-type referencedAnyLens struct {
-	lens   []int
-	marker int
-}
-
-func (refAnys *referencedAnyLens) Reset() (err error) {
-	refAnys.lens = refAnys.lens[:0]
-	return
-}
-
-func (refAnys *referencedAnyLens) AddAnyLen(len int) {
-	refAnys.lens = append(refAnys.lens, len)
-}
-
-func (refAnys *referencedAnyLens) ReferencedAnyLen(index uint64) (int, error) {
-	if index >= uint64(len(refAnys.lens)) {
-		return 0, verror.New(errInvalidAnyIndex, 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 refAnys.lens[index], nil
+	// 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 (refAnys *referencedAnyLens) Mark() {
-	refAnys.marker = len(refAnys.lens)
+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)
 }
diff --git a/vom/decoder_test.go b/vom/decoder_test.go
index 6d33e57..98317e4 100644
--- a/vom/decoder_test.go
+++ b/vom/decoder_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package vom
+package vom_test
 
 import (
 	"bytes"
@@ -16,172 +16,122 @@
 	"testing"
 
 	"v.io/v23/vdl"
-	"v.io/v23/vom/testdata/data81"
+	"v.io/v23/vom"
 	"v.io/v23/vom/testdata/types"
+	"v.io/v23/vom/vomtest"
+
+	// Import verror to ensure that interface tests result in *verror.E
+	_ "v.io/v23/verror"
+)
+
+var (
+	rtIface = reflect.TypeOf((*interface{})(nil)).Elem()
+	rtValue = reflect.TypeOf(vdl.Value{})
 )
 
 func TestDecoder(t *testing.T) {
-	for _, test := range data81.Tests {
-		// Decode hex patterns into binary data.
-		binversion, err := binFromHexPat(test.HexVersion)
-		if err != nil {
-			t.Errorf("%s: couldn't convert to binary from hexversion: %q", test.Name, test.HexVersion)
-			continue
-		}
-		bintype, err := binFromHexPat(test.HexType)
-		if err != nil {
-			t.Errorf("%s: couldn't convert to binary from hextype: %q", test.Name, test.HexType)
-			continue
-		}
-		binvalue, err := binFromHexPat(test.HexValue)
-		if err != nil {
-			t.Errorf("%s: couldn't convert to binary from hexvalue: %q", test.Name, test.HexValue)
-			continue
-		}
-
-		name := test.Name + " [vdl.Value]"
-		testDecodeVDL(t, name, binversion+bintype+binvalue, test.Value)
-		name = test.Name + " [vdl.Value] (with TypeDecoder)"
-		testDecodeVDLWithTypeDecoder(t, name, binversion, bintype, binvalue, test.Value)
-		name = test.Name + " [vdl.Any]"
-		testDecodeVDL(t, name, binversion+bintype+binvalue, vdl.AnyValue(test.Value))
-		name = test.Name + " [vdl.Any] (with TypeDecoder)"
-		testDecodeVDLWithTypeDecoder(t, name, binversion, bintype, binvalue, vdl.AnyValue(test.Value))
-
-		// Convert into Go value for the rest of our tests.
-		goValue, err := toGoValue(test.Value)
-		if err != nil {
-			t.Errorf("%s: %v", test.Name, err)
-			continue
-		}
-
-		name = test.Name + " [go value]"
-		testDecodeGo(t, name, binversion+bintype+binvalue, reflect.TypeOf(goValue), goValue)
-		name = test.Name + " [go value] (with TypeDecoder)"
-		testDecodeGoWithTypeDecoder(t, name, binversion, bintype, binvalue, reflect.TypeOf(goValue), goValue)
-
-		name = test.Name + " [go interface]"
-		testDecodeGo(t, name, binversion+bintype+binvalue, reflect.TypeOf((*interface{})(nil)).Elem(), goValue)
-		name = test.Name + " [go interface] (with TypeDecoder)"
-		testDecodeGoWithTypeDecoder(t, name, binversion, bintype, binvalue, reflect.TypeOf((*interface{})(nil)).Elem(), goValue)
+	// The decoder tests take a long time, so we run them concurrently.
+	var pending sync.WaitGroup
+	for _, test := range vomtest.AllPass() {
+		pending.Add(1)
+		go func(test vomtest.Entry) {
+			defer pending.Done()
+			testDecoder(t, "[go value]", test, rvPtrValue(test.Value))
+			testDecoder(t, "[go iface]", test, rvPtrIface(test.Value))
+			vv, err := vdl.ValueFromReflect(test.Value)
+			if err != nil {
+				t.Errorf("%s: ValueFromReflect failed: %v", test.Name(), err)
+				return
+			}
+			vvWant := reflect.ValueOf(vv)
+			testDecoder(t, "[new *vdl.Value]", test, vvWant)
+			testDecoderFunc(t, "[zero vdl.Value]", test, vvWant, func() reflect.Value {
+				return reflect.ValueOf(vdl.ZeroValue(vv.Type()))
+			})
+		}(test)
 	}
+	pending.Wait()
 }
 
-func testDecodeVDL(t *testing.T, name, bin string, value *vdl.Value) {
-	for _, mode := range AllReadModes {
-		head := fmt.Sprintf("%s (%s)", name, mode)
-		decoder := NewDecoder(mode.TestReader(strings.NewReader(bin)))
-		if value == nil {
-			value = vdl.ZeroValue(vdl.AnyType)
+func rvPtrValue(rv reflect.Value) reflect.Value {
+	result := reflect.New(rv.Type())
+	result.Elem().Set(rv)
+	return result
+}
+
+func rvPtrIface(rv reflect.Value) reflect.Value {
+	result := reflect.New(rtIface)
+	result.Elem().Set(rv)
+	return result
+}
+
+func testDecoder(t *testing.T, pre string, test vomtest.Entry, rvWant reflect.Value) {
+	testDecoderFunc(t, pre, test, rvWant, func() reflect.Value {
+		return reflect.New(rvWant.Type().Elem())
+	})
+	// TODO(toddw): Add tests that start with a randomly-set value.
+}
+
+func testDecoderFunc(t *testing.T, pre string, test vomtest.Entry, rvWant reflect.Value, rvNew func() reflect.Value) {
+	readEOF := make([]byte, 1)
+	for _, mode := range vom.AllReadModes {
+		// Test vom.NewDecoder.
+		{
+			name := fmt.Sprintf("%s (%s) %s", pre, mode, test.Name())
+			rvGot := rvNew()
+			reader := mode.TestReader(bytes.NewReader(test.Bytes()))
+			dec := vom.NewDecoder(reader)
+			if err := dec.Decode(rvGot.Interface()); err != nil {
+				t.Errorf("%s: Decode failed: %v", name, err)
+				return
+			}
+			if !vdl.DeepEqualReflect(rvGot, rvWant) {
+				t.Errorf("%s\nGOT  %v\nWANT %v", name, rvGot, rvWant)
+				return
+			}
+			if n, err := reader.Read(readEOF); n != 0 || err != io.EOF {
+				t.Errorf("%s: reader got (%d,%v), want (0,EOF)", name, n, err)
+			}
 		}
-		got := vdl.ZeroValue(value.Type())
-		if err := decoder.Decode(got); err != nil {
-			t.Errorf("%s: Decode failed: %v", head, err)
-			return
-		}
-		if want := value; !vdl.EqualValue(got, want) {
-			t.Errorf("%s: Decode mismatch\nGOT  %v\nWANT %v", head, got, want)
-			return
+		// Test vom.NewDecoderWithTypeDecoder
+		{
+			name := fmt.Sprintf("%s (%s with TypeDecoder) %s", pre, mode, test.Name())
+			rvGot := rvNew()
+			readerT := mode.TestReader(bytes.NewReader(test.TypeBytes()))
+			decT := vom.NewTypeDecoder(readerT)
+			decT.Start()
+			reader := mode.TestReader(bytes.NewReader(test.ValueBytes()))
+			dec := vom.NewDecoderWithTypeDecoder(reader, decT)
+			err := dec.Decode(rvGot.Interface())
+			decT.Stop()
+			if err != nil {
+				t.Errorf("%s: Decode failed: %v", name, err)
+				return
+			}
+			if !vdl.DeepEqualReflect(rvGot, rvWant) {
+				t.Errorf("%s\nGOT  %v\nWANT %v", name, rvGot, rvWant)
+				return
+			}
+			if n, err := reader.Read(readEOF); n != 0 || err != io.EOF {
+				t.Errorf("%s: reader got (%d,%v), want (0,EOF)", name, n, err)
+			}
+			if n, err := readerT.Read(readEOF); n != 0 || err != io.EOF {
+				t.Errorf("%s: readerT got (%d,%v), want (0,EOF)", name, n, err)
+			}
 		}
 	}
 	// Test single-shot vom.Decode twice, to ensure we test the cache hit case.
-	testDecodeVDLSingleShot(t, name, bin, value)
-	testDecodeVDLSingleShot(t, name, bin, value)
-}
-
-func testDecodeVDLSingleShot(t *testing.T, name, bin string, value *vdl.Value) {
-	// Test the single-shot vom.Decode.
-	head := fmt.Sprintf("%s (single-shot)", name)
-	got := vdl.ZeroValue(value.Type())
-	if err := Decode([]byte(bin), got); err != nil {
-		t.Errorf("%s: Decode failed: %v", head, err)
-		return
-	}
-	if want := value; !vdl.EqualValue(got, want) {
-		t.Errorf("%s: Decode mismatch\nGOT  %v\nWANT %v", head, got, want)
-		return
-	}
-}
-
-func testDecodeVDLWithTypeDecoder(t *testing.T, name, binversion, bintype, binvalue string, value *vdl.Value) {
-	for _, mode := range AllReadModes {
-		head := fmt.Sprintf("%s (%s)", name, mode)
-		typedec := NewTypeDecoder(mode.TestReader(strings.NewReader(binversion + bintype)))
-		typedec.Start()
-		decoder := NewDecoderWithTypeDecoder(mode.TestReader(strings.NewReader(binversion+binvalue)), typedec)
-		if value == nil {
-			value = vdl.ZeroValue(vdl.AnyType)
-		}
-		got := vdl.ZeroValue(value.Type())
-		if err := decoder.Decode(got); err != nil {
-			t.Errorf("%s: Decode failed: %v", head, err)
+	for i := 0; i < 2; i++ {
+		name := fmt.Sprintf("%s (single-shot %d) %s", pre, i, test.Name())
+		rvGot := rvNew()
+		if err := vom.Decode(test.Bytes(), rvGot.Interface()); err != nil {
+			t.Errorf("%s: Decode failed: %v", name, err)
 			return
 		}
-		if want := value; !vdl.EqualValue(got, want) {
-			t.Errorf("%s: Decode mismatch\nGOT  %v\nWANT %v", head, got, want)
+		if !vdl.DeepEqualReflect(rvGot, rvWant) {
+			t.Errorf("%s\nGOT  %v\nWANT %v", name, rvGot, rvWant)
 			return
 		}
-		typedec.Stop()
-	}
-}
-
-func testDecodeGo(t *testing.T, name, bin string, rt reflect.Type, want interface{}) {
-	for _, mode := range AllReadModes {
-		head := fmt.Sprintf("%s (%s)", name, mode)
-		decoder := NewDecoder(mode.TestReader(strings.NewReader(bin)))
-		var got interface{}
-		if rt != nil {
-			got = reflect.New(rt).Elem().Interface()
-		}
-		if err := decoder.Decode(&got); err != nil {
-			t.Errorf("%s: Decode failed: %v", head, err)
-			return
-		}
-		if !vdl.DeepEqual(got, want) {
-			t.Errorf("%s: Decode mismatch\nGOT  %T %+v\nWANT %T %+v", head, got, got, want, want)
-			return
-		}
-	}
-	// Test single-shot vom.Decode twice, to ensure we test the cache hit case.
-	testDecodeGoSingleShot(t, name, bin, rt, want)
-	testDecodeGoSingleShot(t, name, bin, rt, want)
-}
-
-func testDecodeGoSingleShot(t *testing.T, name, bin string, rt reflect.Type, want interface{}) {
-	head := fmt.Sprintf("%s (single-shot)", name)
-	var got interface{}
-	if rt != nil {
-		got = reflect.New(rt).Elem().Interface()
-	}
-	if err := Decode([]byte(bin), &got); err != nil {
-		t.Errorf("%s: Decode failed: %v", head, err)
-		return
-	}
-	if !vdl.DeepEqual(got, want) {
-		t.Errorf("%s: Decode mismatch\nGOT  %T %+v\nWANT %T %+v", head, got, got, want, want)
-		return
-	}
-}
-
-func testDecodeGoWithTypeDecoder(t *testing.T, name, binversion, bintype, binvalue string, rt reflect.Type, want interface{}) {
-	for _, mode := range AllReadModes {
-		head := fmt.Sprintf("%s (%s)", name, mode)
-		typedec := NewTypeDecoder(mode.TestReader(strings.NewReader(binversion + bintype)))
-		typedec.Start()
-		decoder := NewDecoderWithTypeDecoder(mode.TestReader(strings.NewReader(binversion+binvalue)), typedec)
-		var got interface{}
-		if rt != nil {
-			got = reflect.New(rt).Elem().Interface()
-		}
-		if err := decoder.Decode(&got); err != nil {
-			t.Errorf("%s: Decode failed: %v", head, err)
-			return
-		}
-		if !vdl.DeepEqual(got, want) {
-			t.Errorf("%s: Decode mismatch\nGOT  %T %+v\nWANT %T %+v", head, got, got, want, want)
-			return
-		}
-		typedec.Stop()
 	}
 }
 
@@ -253,13 +203,13 @@
 	}
 
 	var (
-		typeenc *TypeEncoder
-		typedec *TypeDecoder
+		typeenc *vom.TypeEncoder
+		typedec *vom.TypeDecoder
 	)
 	if withTypeEncoderDecoder {
 		r, w := newPipe()
-		typeenc = NewTypeEncoder(w)
-		typedec = NewTypeDecoder(r)
+		typeenc = vom.NewTypeEncoder(w)
+		typedec = vom.NewTypeDecoder(r)
 		typedec.Start()
 		defer typedec.Stop()
 	}
@@ -274,16 +224,16 @@
 				name := fmt.Sprintf("[%d]:%+v,%+v", n, test.In, test.Want)
 
 				var (
-					encoder *Encoder
-					decoder *Decoder
+					encoder *vom.Encoder
+					decoder *vom.Decoder
 					buf     bytes.Buffer
 				)
 				if withTypeEncoderDecoder {
-					encoder = NewEncoderWithTypeEncoder(&buf, typeenc)
-					decoder = NewDecoderWithTypeDecoder(&buf, typedec)
+					encoder = vom.NewEncoderWithTypeEncoder(&buf, typeenc)
+					decoder = vom.NewDecoderWithTypeDecoder(&buf, typedec)
 				} else {
-					encoder = NewEncoder(&buf)
-					decoder = NewDecoder(&buf)
+					encoder = vom.NewEncoder(&buf)
+					decoder = vom.NewDecoder(&buf)
 				}
 
 				if err := encoder.Encode(test.In); err != nil {
@@ -374,6 +324,14 @@
 	return err
 }
 
+func hex2Bin(t *testing.T, hex string) []byte {
+	var bin string
+	if _, err := fmt.Sscanf(hex, "%x", &bin); err != nil {
+		t.Fatalf("error converting %q to binary: %v", hex, err)
+	}
+	return []byte(bin)
+}
+
 // Test that no EOF is returned from Decode() if the type stream finished before the value stream.
 func TestTypeStreamEndsFirst(t *testing.T) {
 	hexversion := "81"
@@ -384,10 +342,10 @@
 	binvalue := string(hex2Bin(t, hexvalue))
 	// Ensure EOF isn't returned if the type decode stream ends first
 	tr := newExtractErrReader(strings.NewReader(binversion + bintype))
-	typedec := NewTypeDecoder(tr)
+	typedec := vom.NewTypeDecoder(tr)
 	typedec.Start()
 	wr := newWaitingReader(strings.NewReader(binversion + binvalue))
-	decoder := NewDecoderWithTypeDecoder(wr, typedec)
+	decoder := vom.NewDecoderWithTypeDecoder(wr, typedec)
 	var v interface{}
 	go func() {
 		if tr.WaitForError() == nil {
@@ -415,9 +373,9 @@
 	binversion := string(hex2Bin(t, hexversion))
 	binvalue := string(hex2Bin(t, hexvalue))
 	// Ensure EOF isn't returned if the type decode stream ends first
-	typedec := NewTypeDecoder(&errorReader{})
+	typedec := vom.NewTypeDecoder(&errorReader{})
 	typedec.Start()
-	decoder := NewDecoderWithTypeDecoder(strings.NewReader(binversion+binvalue), typedec)
+	decoder := vom.NewDecoderWithTypeDecoder(strings.NewReader(binversion+binvalue), typedec)
 	var v interface{}
 	if err := decoder.Decode(&v); err == nil {
 		t.Errorf("expected error in decode, but got none")
@@ -428,7 +386,7 @@
 // in a deadlock.
 func TestFuzzTypeDecodeDeadlock(t *testing.T) {
 	var v interface{}
-	d := NewDecoder(strings.NewReader("\x81\x30"))
+	d := vom.NewDecoder(strings.NewReader("\x81\x30"))
 	// Before the fix, this line caused a deadlock and panic.
 	d.Decode(&v)
 	return
@@ -438,7 +396,7 @@
 // panic over in package vdl.
 func TestFuzzVdlPanic(t *testing.T) {
 	var v interface{}
-	d := NewDecoder(strings.NewReader("\x81S*\x00\x00$000000000000000000000000000000000000\x01*\xe1U(\x05\x00 00000000000000000000000000000000\x01*\x02+\xe1"))
+	d := vom.NewDecoder(strings.NewReader("\x81S*\x00\x00$000000000000000000000000000000000000\x01*\xe1U(\x05\x00 00000000000000000000000000000000\x01*\x02+\xe1"))
 	// Before this fix this line caused a panic.
 	d.Decode(&v)
 	return
@@ -487,7 +445,7 @@
 // Test that input found by go-fuzz cannot cause a stack overflow.
 func TestFuzzDecodeOverflow(t *testing.T) {
 	var v interface{}
-	d := NewDecoder(strings.NewReader("\x81\x51\x04\x03\x01\x29\xe1"))
+	d := vom.NewDecoder(strings.NewReader("\x81\x51\x04\x03\x01\x29\xe1"))
 
 	// Before the fix, this line caused a stack overflow.  After the fix, we
 	// expect an error.
@@ -499,7 +457,7 @@
 // Test that input discovered by go-fuzz does not result in a hang anymore.
 func TestFuzzTypeDecodeHang(t *testing.T) {
 	var v interface{}
-	d := NewDecoder(strings.NewReader(
+	d := vom.NewDecoder(strings.NewReader(
 		"\x81W&\x03\x00 v.io/v23/vom/t" +
 			"estdata/types.Rec4\x01)" +
 			"\xe1U&\x03\x00 v.io/v23/vom/t" +
@@ -530,14 +488,14 @@
 		X []byte
 		B bar
 	}
-	encoded, err := Encode(foo{"hello", 42, 3.14159265359, []byte{1, 2, 3, 4, 5, 6}, bar{[]int64{0}}})
+	encoded, err := vom.Encode(foo{"hello", 42, 3.14159265359, []byte{1, 2, 3, 4, 5, 6}, bar{[]int64{0}}})
 	if err != nil {
 		t.Fatalf("Encode failed: %v", err)
 	}
 	for x := 0; x < len(encoded)-1; x++ {
 		var f interface{}
-		if err := Decode(encoded[:x], &f); err == nil {
-			t.Errorf("Encode did not fail with x=%d", x)
+		if err := vom.Decode(encoded[:x], &f); err == nil {
+			t.Errorf("Decode did not fail with x=%d", x)
 		}
 	}
 }
diff --git a/vom/decoder_util.go b/vom/decoder_util.go
new file mode 100644
index 0000000..01753a9
--- /dev/null
+++ b/vom/decoder_util.go
@@ -0,0 +1,412 @@
+// Copyright 2015 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 (
+	"v.io/v23/vdl"
+	"v.io/v23/verror"
+)
+
+var (
+	errDecodeZeroTypeID         = verror.Register(pkgPath+".errDecodeZeroTypeID", verror.NoRetry, "{1:}{2:} vom: zero type id{:_}")
+	errIndexOutOfRange          = verror.Register(pkgPath+".errIndexOutOfRange", verror.NoRetry, "{1:}{2:} vom: index out of range{:_}")
+	errLeftOverBytes            = verror.Register(pkgPath+".errLeftOverBytes", verror.NoRetry, "{1:}{2:} vom: {3} leftover bytes{:_}")
+	errUnexpectedControlByte    = verror.Register(pkgPath+".errUnexpectedControlByte", verror.NoRetry, "{1:}{2:} vom: unexpected control byte {3}{:_}")
+	errDecodeValueUnhandledType = verror.Register(pkgPath+".errDecodeValueUnhandledType", verror.NoRetry, "{1:}{2:} vom: decodeValue unhandled type {3}{:_}")
+	errIgnoreValueUnhandledType = verror.Register(pkgPath+".errIgnoreValueUnhandledType", verror.NoRetry, "{1:}{2:} vom: ignoreValue unhandled type {3}{:_}")
+	errInvalidTypeIdIndex       = verror.Register(pkgPath+".errInvalidTypeIdIndex", verror.NoRetry, "{1:}{2:} vom: value referenced invalid index into type id table {:_}")
+	errInvalidAnyIndex          = verror.Register(pkgPath+".errInvalidAnyIndex", verror.NoRetry, "{1:}{2:} vom: value referenced invalid index into anyLen table {:_}")
+)
+
+func (d *decoder81) decodeTypeDefs() error {
+	for {
+		typeNext, err := d.typeIsNext()
+		if err != nil {
+			return err
+		}
+		if !typeNext {
+			return nil
+		}
+		if err := d.typeDec.readSingleType(); err != nil {
+			return err
+		}
+	}
+}
+
+// peekValueByteLen returns the byte length of the next value.
+func (d *decoder81) peekValueByteLen(tt *vdl.Type) (int, error) {
+	if hasChunkLen(tt) {
+		// Use the explicit message length.
+		return d.buf.lim, nil
+	}
+	// No explicit message length, but the length can be computed.
+	switch {
+	case tt.Kind() == vdl.Array && tt.IsBytes():
+		// Byte arrays are exactly their length and encoded with 1-byte header.
+		return tt.Len() + 1, nil
+	case tt.Kind() == vdl.String || tt.IsBytes():
+		// Strings and byte lists are encoded with a length header.
+		strlen, bytelen, err := binaryPeekUint(d.buf)
+		switch {
+		case err != nil:
+			return 0, err
+		case strlen > maxBinaryMsgLen:
+			return 0, verror.New(errMsgLen, nil, maxBinaryMsgLen)
+		}
+		return int(strlen) + bytelen, nil
+	default:
+		// Must be a primitive, which is encoded as an underlying uint.
+		return binaryPeekUintByteLen(d.buf)
+	}
+}
+
+func (d *decoder81) decodeRaw(tt *vdl.Type, valLen int, raw *RawBytes) error {
+	raw.Version = d.buf.version
+	raw.Type = tt
+	raw.Data = make([]byte, valLen)
+	if err := d.buf.ReadIntoBuf(raw.Data); err != nil {
+		return err
+	}
+	refTypeLen := len(d.refTypes.tids)
+	if cap(raw.RefTypes) >= refTypeLen {
+		raw.RefTypes = raw.RefTypes[:refTypeLen]
+	} else {
+		raw.RefTypes = make([]*vdl.Type, refTypeLen)
+	}
+	for i, tid := range d.refTypes.tids {
+		var err error
+		if raw.RefTypes[i], err = d.typeDec.lookupType(tid); err != nil {
+			return err
+		}
+	}
+	raw.AnyLengths = d.refAnyLens.lens
+	return nil
+}
+
+func (d *decoder81) readAnyHeader() (*vdl.Type, int, error) {
+	// Handle WireCtrlNil.
+	switch ok, err := binaryDecodeControlOnly(d.buf, WireCtrlNil); {
+	case err != nil:
+		return nil, 0, err
+	case ok:
+		return nil, 0, nil // nil any
+	}
+	// Read the index of the referenced type id.
+	typeIndex, err := binaryDecodeUint(d.buf)
+	if err != nil {
+		return nil, 0, err
+	}
+	var tid TypeId
+	if d.buf.version == Version80 {
+		tid = TypeId(typeIndex)
+	} else if tid, err = d.refTypes.ReferencedTypeId(typeIndex); err != nil {
+		return nil, 0, err
+	}
+	// Look up the referenced type id.
+	ttElem, err := d.typeDec.lookupType(tid)
+	if err != nil {
+		return nil, 0, err
+	}
+	var anyLen int
+	if d.buf.version != Version80 {
+		// Read and lookup the index of the any byte length.  Reference the any len,
+		// even if it isn't used, to report missing references.
+		lenIndex, err := binaryDecodeUint(d.buf)
+		if err != nil {
+			return nil, 0, err
+		}
+		if anyLen, err = d.refAnyLens.ReferencedAnyLen(lenIndex); err != nil {
+			return nil, 0, err
+		}
+	}
+	return ttElem, anyLen, nil
+}
+
+func (d *decoder81) skipValue(tt *vdl.Type) error {
+	if tt.IsBytes() {
+		len, err := binaryDecodeLenOrArrayLen(d.buf, tt)
+		if err != nil {
+			return err
+		}
+		return d.buf.Skip(len)
+	}
+	switch kind := tt.Kind(); kind {
+	case vdl.Bool:
+		return d.buf.Skip(1)
+	case vdl.Byte, vdl.Uint16, vdl.Uint32, vdl.Uint64, vdl.Int8, vdl.Int16, vdl.Int32, vdl.Int64, vdl.Float32, vdl.Float64, vdl.Enum, vdl.TypeObject:
+		// The underlying encoding of all these types is based on uint.
+		return binarySkipUint(d.buf)
+	case vdl.String:
+		return binarySkipString(d.buf)
+	case vdl.Array, vdl.List, vdl.Set, vdl.Map:
+		len, err := binaryDecodeLenOrArrayLen(d.buf, tt)
+		if err != nil {
+			return err
+		}
+		for ix := 0; ix < len; ix++ {
+			if kind == vdl.Set || kind == vdl.Map {
+				if err := d.skipValue(tt.Key()); err != nil {
+					return err
+				}
+			}
+			if kind == vdl.Array || kind == vdl.List || kind == vdl.Map {
+				if err := d.skipValue(tt.Elem()); err != nil {
+					return err
+				}
+			}
+		}
+		return nil
+	case vdl.Struct:
+		// Loop through decoding the 0-based field index and corresponding field.
+		for {
+			switch ok, err := binaryDecodeControlOnly(d.buf, WireCtrlEnd); {
+			case err != nil:
+				return err
+			case ok:
+				return nil // end of struct
+			}
+			switch index, err := binaryDecodeUint(d.buf); {
+			case err != nil:
+				return err
+			case index >= uint64(tt.NumField()):
+				return verror.New(errIndexOutOfRange, nil)
+			default:
+				ttfield := tt.Field(int(index))
+				if err := d.skipValue(ttfield.Type); err != nil {
+					return err
+				}
+			}
+		}
+	case vdl.Union:
+		switch index, err := binaryDecodeUint(d.buf); {
+		case err != nil:
+			return err
+		case index >= uint64(tt.NumField()):
+			return verror.New(errIndexOutOfRange, nil)
+		default:
+			ttfield := tt.Field(int(index))
+			return d.skipValue(ttfield.Type)
+		}
+	case vdl.Optional:
+		// 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 err
+		case ctrl == WireCtrlNil:
+			d.buf.SkipAvailable(1) // nil optional
+			return nil
+		default:
+			return d.skipValue(tt.Elem()) // non-nil optional
+		}
+	case vdl.Any:
+		switch ok, err := binaryDecodeControlOnly(d.buf, WireCtrlNil); {
+		case err != nil:
+			return err
+		case ok:
+			return nil // nil any
+		}
+		switch index, err := binaryDecodeUint(d.buf); {
+		case err != nil:
+			return err
+		default:
+			tid, err := d.refTypes.ReferencedTypeId(index)
+			if err != nil {
+				return err
+			}
+			ttElem, err := d.typeDec.lookupType(tid)
+			if err != nil {
+				return err
+			}
+			return d.skipValue(ttElem)
+		}
+	default:
+		return verror.New(errIgnoreValueUnhandledType, nil, tt)
+	}
+}
+
+func (d *decoder81) nextMessage() (TypeId, error) {
+	if leftover := d.buf.RemoveLimit(); leftover > 0 {
+		return 0, verror.New(errLeftOverBytes, nil, leftover)
+	}
+	// Decode version byte, if not already decoded.
+	if d.buf.version == 0 {
+		version, err := d.buf.ReadByte()
+		if err != nil {
+			return 0, verror.New(errEndedBeforeVersionByte, nil, err)
+		}
+		d.buf.version = Version(version)
+		if !isAllowedVersion(d.buf.version) {
+			return 0, verror.New(errBadVersionByte, nil, d.buf.version)
+		}
+	}
+	// Decode the next message id.
+	incomplete, err := binaryDecodeControlOnly(d.buf, WireCtrlTypeIncomplete)
+	if err != nil {
+		return 0, err
+	}
+	mid, err := binaryDecodeInt(d.buf)
+	if err != nil {
+		return 0, err
+	}
+	if incomplete {
+		if mid >= 0 {
+			// TypeIncomplete must be followed with a type message.
+			return 0, verror.New(errInvalid, nil)
+		}
+		d.flag = d.flag.Set(decFlagTypeIncomplete)
+	} else if mid < 0 {
+		d.flag = d.flag.Clear(decFlagTypeIncomplete)
+	}
+	// TODO(toddw): Clean up the logic below.
+	var tid TypeId
+	var hasAny, hasTypeObject, hasLength bool
+	switch {
+	case mid < 0:
+		tid = TypeId(-mid)
+		hasLength = true
+		hasAny = false
+		hasTypeObject = false
+	case mid > 0:
+		tid = TypeId(mid)
+		t, err := d.typeDec.lookupType(tid)
+		if err != nil {
+			return 0, err
+		}
+		hasLength = hasChunkLen(t)
+		hasAny = containsAny(t)
+		hasTypeObject = containsTypeObject(t)
+	default:
+		return 0, verror.New(errDecodeZeroTypeID, nil)
+	}
+
+	if (hasAny || hasTypeObject) && d.buf.version != Version80 {
+		l, err := binaryDecodeUint(d.buf)
+		if err != nil {
+			return 0, err
+		}
+		for i := 0; i < int(l); i++ {
+			refId, err := binaryDecodeUint(d.buf)
+			if err != nil {
+				return 0, err
+			}
+			d.refTypes.AddTypeID(TypeId(refId))
+		}
+	}
+	if hasAny && d.buf.version != Version80 {
+		l, err := binaryDecodeUint(d.buf)
+		if err != nil {
+			return 0, err
+		}
+		for i := 0; i < int(l); i++ {
+			refAnyLen, err := binaryDecodeLen(d.buf)
+			if err != nil {
+				return 0, err
+			}
+			d.refAnyLens.AddAnyLen(refAnyLen)
+		}
+	}
+
+	if hasLength {
+		chunkLen, err := binaryDecodeUint(d.buf)
+		if err != nil {
+			return 0, err
+		}
+		d.buf.SetLimit(int(chunkLen))
+	}
+
+	return tid, nil
+}
+
+func (d *decoder81) typeIsNext() (bool, error) {
+	if d.buf.version == 0 {
+		version, err := d.buf.ReadByte()
+		if err != nil {
+			return false, verror.New(errEndedBeforeVersionByte, nil, err)
+		}
+		d.buf.version = Version(version)
+		if !isAllowedVersion(d.buf.version) {
+			return false, verror.New(errBadVersionByte, nil, d.buf.version)
+		}
+	}
+	switch ctrl, err := binaryPeekControl(d.buf); {
+	case err != nil:
+		return false, err
+	case ctrl == WireCtrlTypeIncomplete:
+		return true, nil
+	case ctrl != 0:
+		return false, verror.New(errBadControlCode, nil, ctrl)
+	}
+	mid, _, err := binaryPeekInt(d.buf)
+	if err != nil {
+		return false, err
+	}
+	return mid < 0, nil
+}
+
+func (d *decoder81) endMessage() error {
+	if leftover := d.buf.RemoveLimit(); leftover > 0 {
+		return verror.New(errLeftOverBytes, nil, leftover)
+	}
+	if err := d.refTypes.Reset(); err != nil {
+		return err
+	}
+	if err := d.refAnyLens.Reset(); err != nil {
+		return err
+	}
+	return nil
+}
+
+type referencedTypes struct {
+	tids   []TypeId
+	marker int
+}
+
+func (refTypes *referencedTypes) Reset() (err error) {
+	refTypes.tids = refTypes.tids[:0]
+	refTypes.marker = 0
+	return
+}
+
+func (refTypes *referencedTypes) AddTypeID(tid TypeId) {
+	refTypes.tids = append(refTypes.tids, tid)
+}
+
+func (refTypes *referencedTypes) ReferencedTypeId(index uint64) (TypeId, error) {
+	if index >= uint64(len(refTypes.tids)) {
+		return 0, verror.New(errInvalidTypeIdIndex, nil)
+	}
+	return refTypes.tids[index], nil
+}
+
+func (refTypes *referencedTypes) Mark() {
+	refTypes.marker = len(refTypes.tids)
+}
+
+type referencedAnyLens struct {
+	lens   []int
+	marker int
+}
+
+func (refAnys *referencedAnyLens) Reset() (err error) {
+	refAnys.lens = refAnys.lens[:0]
+	return
+}
+
+func (refAnys *referencedAnyLens) AddAnyLen(len int) {
+	refAnys.lens = append(refAnys.lens, len)
+}
+
+func (refAnys *referencedAnyLens) ReferencedAnyLen(index uint64) (int, error) {
+	if index >= uint64(len(refAnys.lens)) {
+		return 0, verror.New(errInvalidAnyIndex, nil)
+	}
+	return refAnys.lens[index], nil
+}
+
+func (refAnys *referencedAnyLens) Mark() {
+	refAnys.marker = len(refAnys.lens)
+}
diff --git a/vom/encoder.go b/vom/encoder.go
index 6af4f26..d3e3697 100644
--- a/vom/encoder.go
+++ b/vom/encoder.go
@@ -90,7 +90,7 @@
 	return e
 }
 
-func newXEncoderForRawBytes(w io.Writer) *encoder81 {
+func newEncoderForRawBytes(w io.Writer) *encoder81 {
 	// RawBytes doesn't need the types to be encoded, since it holds the in-memory
 	// representation.  We still need a type encoder to collect the unique types,
 	// but we give it a dummy encoder that doesn't have any state set up.
diff --git a/vom/encoder_test.go b/vom/encoder_test.go
index 9baaf9a..ea9e846 100644
--- a/vom/encoder_test.go
+++ b/vom/encoder_test.go
@@ -2,95 +2,75 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package vom
+package vom_test
 
 import (
 	"bytes"
 	"fmt"
 	"testing"
 
-	"v.io/v23/vom/testdata/data81"
-	"v.io/v23/vom/testdata/types"
+	"v.io/v23/vdl"
+	"v.io/v23/vom"
+	"v.io/v23/vom/vomtest"
 )
 
-func TestEncoder81(t *testing.T) {
-	testEncoder(t, Version81, data81.Tests)
-}
-
-func testEncoder(t *testing.T, version Version, tests []types.TestCase) {
-	for _, test := range tests {
-		name := test.Name + " [vdl.Value]"
-		testEncode(t, version, name, test.Value, test.HexVersion+test.HexType+test.HexValue)
-		name = test.Name + " [vdl.Value] (with TypeEncoder)"
-		testEncodeWithTypeEncoder(t, version, name, test.Value, test.HexVersion, test.HexType, test.HexValue)
-
-		// Convert into Go value for the rest of our tests.
-		goValue, err := toGoValue(test.Value)
+func TestEncoder(t *testing.T) {
+	for _, test := range vomtest.AllPass() {
+		testEncoder(t, "[go value]", test, test.Value.Interface())
+		vv, err := vdl.ValueFromReflect(test.Value)
 		if err != nil {
-			t.Errorf("%s: %v", name, err)
+			t.Errorf("%s: ValueFromReflect failed: %v", test.Name(), err)
 			continue
 		}
-
-		name = test.Name + " [go value]"
-		testEncode(t, version, name, goValue, test.HexVersion+test.HexType+test.HexValue)
-		name = test.Name + " [go value] (with TypeEncoder)"
-		testEncodeWithTypeEncoder(t, version, name, goValue, test.HexVersion, test.HexType, test.HexValue)
+		testEncoder(t, "[vdl.Value]", test, vv)
 	}
 }
 
-func testEncode(t *testing.T, version Version, name string, value interface{}, hex string) {
-	for _, singleShot := range []bool{false, true} {
-		var bin []byte
-		if !singleShot {
-			var buf bytes.Buffer
-			encoder := NewVersionedEncoder(version, &buf)
-			if err := encoder.Encode(value); err != nil {
-				t.Errorf("%s: Encode(%#v) failed: %v", name, value, err)
-				return
-			}
-			bin = buf.Bytes()
-		} else {
-			name += " (single-shot)"
-			var err error
-			bin, err = VersionedEncode(version, value)
-			if err != nil {
-				t.Errorf("%s: Encode(%#v) failed: %v", name, value, err)
-				return
-			}
+func testEncoder(t *testing.T, pre string, test vomtest.Entry, value interface{}) {
+	// Test vom.NewEncoder.
+	{
+		var buf bytes.Buffer
+		name := fmt.Sprintf("%s %s", pre, test.Name())
+		enc := vom.NewVersionedEncoder(test.Version, &buf)
+		if err := enc.Encode(value); err != nil {
+			t.Errorf("%s: Encode failed: %v", name, err)
+			return
 		}
-		got, want := fmt.Sprintf("%x", bin), hex
-		match, err := matchHexPat(got, want)
+		if got, want := buf.Bytes(), test.Bytes(); !bytes.Equal(got, want) {
+			t.Errorf("%s\nGOT  %x\nWANT %x", name, got, want)
+			return
+		}
+	}
+	// Test vom.NewEncoderWithTypeEncoder.
+	{
+		var buf, bufT bytes.Buffer
+		name := fmt.Sprintf("%s (with TypeEncoder) %s", pre, test.Name())
+		encT := vom.NewVersionedTypeEncoder(test.Version, &bufT)
+		enc := vom.NewVersionedEncoderWithTypeEncoder(test.Version, &buf, encT)
+		if err := enc.Encode(value); err != nil {
+			t.Errorf("%s: Encode failed: %v", name, err)
+			return
+		}
+		if got, want := bufT.Bytes(), test.TypeBytes(); !bytes.Equal(got, want) {
+			t.Errorf("%s TYPE\nGOT  %x\nWANT %x", name, got, want)
+			return
+		}
+		if got, want := buf.Bytes(), test.ValueBytes(); !bytes.Equal(got, want) {
+			t.Errorf("%s VALUE\nGOT  %x\nWANT %x", name, got, want)
+			return
+		}
+	}
+	// Test single-shot vom.Encode.
+	{
+		name := fmt.Sprintf("%s (single-shot) %s", pre, test.Name())
+		buf, err := vom.VersionedEncode(test.Version, value)
 		if err != nil {
-			t.Error(err)
+			t.Errorf("%s: Encode failed: %v", name, err)
+			return
 		}
-		if !match {
-			t.Errorf("%s: Encode(%#v)\nGOT  %s\nWANT %s", name, value, got, want)
+		if got, want := buf, test.Bytes(); !bytes.Equal(got, want) {
+			t.Errorf("%s\nGOT  %x\nWANT %x", name, got, want)
+			return
 		}
 	}
 }
-
-func testEncodeWithTypeEncoder(t *testing.T, version Version, name string, value interface{}, hexversion, hextype, hexvalue string) {
-	var buf, typebuf bytes.Buffer
-	typeenc := NewVersionedTypeEncoder(version, &typebuf)
-	encoder := NewVersionedEncoderWithTypeEncoder(version, &buf, typeenc)
-	if err := encoder.Encode(value); err != nil {
-		t.Errorf("%s: Encode(%#v) failed: %v", name, value, err)
-		return
-	}
-	got, want := fmt.Sprintf("%x", typebuf.Bytes()), hexversion+hextype
-	match, err := matchHexPat(got, want)
-	if err != nil {
-		t.Error(err)
-	}
-	if !match && len(hextype) > 0 {
-		t.Errorf("%s: EncodeType(%#v)\nGOT  %s\nWANT %s", name, value, got, want)
-	}
-	got, want = fmt.Sprintf("%x", buf.Bytes()), hexversion+hexvalue
-	match, err = matchHexPat(got, want)
-	if err != nil {
-		t.Error(err)
-	}
-	if !match {
-		t.Errorf("%s: Encode(%#v)\nGOT  %s\nWANT %s", name, value, got, want)
-	}
-}
diff --git a/vom/fuzzdump_test.go b/vom/fuzzdump_test.go
index 0cd9399..1b6e908 100644
--- a/vom/fuzzdump_test.go
+++ b/vom/fuzzdump_test.go
@@ -4,7 +4,7 @@
 
 // +build fuzzdump
 
-package vom
+package vom_test
 
 import (
 	"crypto/sha1"
@@ -13,8 +13,7 @@
 	"os"
 	"testing"
 
-	"v.io/v23/vom/testdata/data80"
-	"v.io/v23/vom/testdata/data81"
+	"v.io/v23/vom/vomtest"
 )
 
 // Add the vom tests as binary examples for the fuzzer.
@@ -27,34 +26,16 @@
 
 	seen := make(map[[sha1.Size]byte]bool)
 
-	tests := append(data80.Tests, data81.Tests...)
-
-	for _, test := range tests {
-		binversion, err := binFromHexPat(test.HexVersion)
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		bintype, err := binFromHexPat(test.HexType)
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		binvalue, err := binFromHexPat(test.HexValue)
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		data := []byte(binversion + bintype + binvalue)
+	for _, test := range vomtest.AllPass() {
+		data := test.Bytes()
 		hash := sha1.Sum(data)
-
 		if seen[hash] {
 			continue
 		}
 		seen[hash] = true
 
-		fn := fmt.Sprintf("fuzz-workdir/corpus/%x", hash)
-		if err := ioutil.WriteFile(fn, data, 0644); err != nil {
+		name := fmt.Sprintf("fuzz-workdir/corpus/%x", hash)
+		if err := ioutil.WriteFile(name, data, 0644); err != nil {
 			t.Fatal(err)
 		}
 	}
diff --git a/vom/new_raw_bytes_test.go b/vom/new_raw_bytes_test.go
deleted file mode 100644
index 3631218..0000000
--- a/vom/new_raw_bytes_test.go
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright 2015 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_test
-
-import (
-	"bytes"
-	"io"
-	"testing"
-
-	"v.io/v23/vdl"
-	"v.io/v23/vom"
-	"v.io/v23/vom/vomtest"
-)
-
-// TODO(toddw): Clean up these tests.
-
-func TestXRawBytesDecodeEncode(t *testing.T) {
-	for _, test := range vomtest.AllPass() {
-		// Interleaved
-		rb := vom.RawBytes{}
-		interleavedReader := bytes.NewReader(test.Bytes())
-		if err := vom.NewDecoder(interleavedReader).Decode(&rb); err != nil {
-			t.Errorf("%s: decode failed: %v", test.Name(), err)
-			continue
-		}
-		if _, err := interleavedReader.ReadByte(); err != io.EOF {
-			t.Errorf("%s: expected EOF, but got %v", test.Name(), err)
-			continue
-		}
-
-		var out bytes.Buffer
-		enc := vom.NewVersionedEncoder(test.Version, &out)
-		if err := enc.Encode(&rb); err != nil {
-			t.Errorf("%s: encode failed: %v\nRawBytes: %v", test.Name(), err, rb)
-			continue
-		}
-		if got, want := out.Bytes(), test.Bytes(); !bytes.Equal(got, want) {
-			t.Errorf("%s\nGOT  %x\nWANT %x", test.Name(), got, want)
-		}
-
-		// Split type and value stream.
-		rb = vom.RawBytes{}
-		typeReader := bytes.NewReader(test.TypeBytes())
-		typeDec := vom.NewTypeDecoder(typeReader)
-		typeDec.Start()
-		defer typeDec.Stop()
-		valueReader := bytes.NewReader(test.ValueBytes())
-		if err := vom.NewDecoderWithTypeDecoder(valueReader, typeDec).Decode(&rb); err != nil {
-			t.Errorf("%s: decode failed: %v", test.Name(), err)
-			continue
-		}
-		if _, err := typeReader.ReadByte(); err != io.EOF {
-			t.Errorf("%s: type reader got %v, want EOF", test.Name(), err)
-			continue
-		}
-		if _, err := valueReader.ReadByte(); err != io.EOF {
-			t.Errorf("%s: value reader got %v, want EOF", test.Name(), err)
-			continue
-		}
-
-		out.Reset()
-		var typeOut bytes.Buffer
-		typeEnc := vom.NewVersionedTypeEncoder(test.Version, &typeOut)
-		enc = vom.NewVersionedEncoderWithTypeEncoder(test.Version, &out, typeEnc)
-		if err := enc.Encode(&rb); err != nil {
-			t.Errorf("%s: encode failed: %v\nRawBytes: %v", test.Name(), err, rb)
-			continue
-		}
-		if got, want := typeOut.Bytes(), test.TypeBytes(); !bytes.Equal(got, want) {
-			t.Errorf("%s: type bytes\nGOT  %x\nWANT %x", test.Name(), got, want)
-		}
-		if got, want := out.Bytes(), test.ValueBytes(); !bytes.Equal(got, want) {
-			t.Errorf("%s: value bytes\nGOT  %x\nWANT %x", test.Name(), got, want)
-		}
-	}
-}
-
-func TestXRawBytesToFromValue(t *testing.T) {
-	for _, test := range vomtest.AllPass() {
-		rb, err := vom.XRawBytesFromValue(test.Value.Interface())
-		if err != nil {
-			t.Errorf("%v %s: XRawBytesFromValue failed: %v", test.Version, test.Name(), err)
-			continue
-		}
-		var vv *vdl.Value
-		if err := rb.ToValue(&vv); err != nil {
-			t.Errorf("%v %s: rb.ToValue failed: %v", test.Version, test.Name(), err)
-			continue
-		}
-		if got, want := vv, vdl.ValueOf(test.Value.Interface()); !vdl.EqualValue(got, want) {
-			t.Errorf("%v %s\nGOT  %v\nWANT %v", test.Version, test.Name(), got, want)
-		}
-	}
-}
-
-func TestXRawBytesDecoder(t *testing.T) {
-	for _, test := range vomtest.AllPass() {
-		tt, err := vdl.TypeFromReflect(test.Value.Type())
-		if err != nil {
-			t.Errorf("%s: TypeFromReflect failed: %v", test.Name(), err)
-			continue
-		}
-		in, err := vom.XRawBytesFromValue(test.Value.Interface())
-		if err != nil {
-			t.Errorf("%s: XRawBytesFromValue failed: %v", test.Name(), err)
-			continue
-		}
-		out := vdl.ZeroValue(tt)
-		if err := out.VDLRead(in.Decoder()); err != nil {
-			t.Errorf("%s: VDLRead failed: %v", test.Name(), err)
-			continue
-		}
-		if got, want := out, vdl.ValueOf(test.Value.Interface()); !vdl.EqualValue(got, want) {
-			t.Errorf("%s\nGOT  %v\nWANT %v", test.Name(), got, want)
-		}
-	}
-}
-
-func TestXRawBytesWriter(t *testing.T) {
-	for _, test := range vomtest.AllPass() {
-		var buf bytes.Buffer
-		enc := vom.NewEncoder(&buf)
-		rb, err := vom.XRawBytesFromValue(test.Value.Interface())
-		if err != nil {
-			t.Errorf("%s: XRawBytesFromValue failed: %v", test.Name(), err)
-			continue
-		}
-		if err := rb.VDLWrite(enc.Encoder()); err != nil {
-			t.Errorf("%s: VDLWrite failed: %v", test.Name(), err)
-			continue
-		}
-		if got, want := buf.Bytes(), test.Bytes(); !bytes.Equal(got, want) {
-			t.Errorf("%s\nGOT  %x\nWANT %x", test.Name(), got, want)
-		}
-	}
-}
diff --git a/vom/new_transcode_test.go b/vom/new_transcode_test.go
deleted file mode 100644
index 9c00e7d..0000000
--- a/vom/new_transcode_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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_test
-
-import (
-	"bytes"
-	"testing"
-
-	"v.io/v23/vdl"
-	"v.io/v23/vom"
-	"v.io/v23/vom/vomtest"
-)
-
-func TestTranscodeXDecoderToXEncoder(t *testing.T) {
-	for _, test := range vomtest.AllPass() {
-		var buf bytes.Buffer
-		enc := vom.NewVersionedEncoder(test.Version, &buf)
-		dec := vom.NewDecoder(bytes.NewReader(test.Bytes()))
-		if err := vdl.Transcode(enc.Encoder(), dec.Decoder()); err != nil {
-			t.Errorf("%s: Transcode failed: %v", test.Name(), err)
-			continue
-		}
-		if got, want := buf.Bytes(), test.Bytes(); !bytes.Equal(got, want) {
-			t.Errorf("%s\nGOT  %x\nWANT %x", test.Name(), got, want)
-		}
-	}
-}
-
-// TODO(bprosnitz) This is probably not the right place for this test.
-func TestTranscodeVDLValueToXEncoder(t *testing.T) {
-	for _, test := range vomtest.AllPass() {
-		var buf bytes.Buffer
-		enc := vom.NewEncoder(&buf)
-		if err := vdl.Write(enc.Encoder(), test.Value.Interface()); err != nil {
-			t.Errorf("%s: vdl.Write failed: %v", test.Name(), err)
-			continue
-		}
-		if got, want := buf.Bytes(), test.Bytes(); !bytes.Equal(got, want) {
-			t.Errorf("%s\nGOT  %x\nWANT %x", test.Name(), got, want)
-		}
-	}
-}
diff --git a/vom/raw_bytes.go b/vom/raw_bytes.go
index b0794e0..e611a90 100644
--- a/vom/raw_bytes.go
+++ b/vom/raw_bytes.go
@@ -46,23 +46,6 @@
 	return rb, nil
 }
 
-// XRawBytesFromValue is a mirror of RawBytesFromValue, but uses the new
-// XEncoder and XDecoder.  It's only exposed to allow for testing.
-//
-// TODO(toddw): Remove this function after we've switched to XEncoder and
-// XDecoder, and thus it's no longer needed.
-func XRawBytesFromValue(value interface{}) (*RawBytes, error) {
-	data, err := VersionedEncode(DefaultVersion, value)
-	if err != nil {
-		return nil, err
-	}
-	rb := new(RawBytes)
-	if err := Decode(data, rb); err != nil {
-		return nil, err
-	}
-	return rb, nil
-}
-
 // String outputs a string representation of RawBytes of the form
 // RawBytes{Version81, int8, RefTypes{bool, string}, AnyLengths{4}, fa0e9dcc}
 func (rb *RawBytes) String() string {
@@ -164,7 +147,7 @@
 	}
 	// Slowpath: the bytes are not available, we must encode new bytes.
 	var buf bytes.Buffer
-	enc := newXEncoderForRawBytes(&buf)
+	enc := newEncoderForRawBytes(&buf)
 	if err := vdl.Transcode(enc, dec); err != nil {
 		return err
 	}
diff --git a/vom/raw_bytes_test.go b/vom/raw_bytes_test.go
index 0bd4016..532a12d 100644
--- a/vom/raw_bytes_test.go
+++ b/vom/raw_bytes_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package vom
+package vom_test
 
 import (
 	"bytes"
@@ -11,8 +11,8 @@
 	"testing"
 
 	"v.io/v23/vdl"
-	"v.io/v23/vom/testdata/data81"
-	"v.io/v23/vom/testdata/types"
+	"v.io/v23/vom"
+	"v.io/v23/vom/vomtest"
 )
 
 type testUint64 uint64
@@ -22,27 +22,27 @@
 }
 
 type structAny struct {
-	X *RawBytes
+	X *vom.RawBytes
 }
 
 type structAnyAndTypes struct {
 	A *vdl.Type
-	B *RawBytes
+	B *vom.RawBytes
 	C *vdl.Type
-	D *RawBytes
+	D *vom.RawBytes
 }
 
 // Test various combinations of having/not having any and type object.
 var rawBytesTestCases = []struct {
 	name     string
 	goValue  interface{}
-	rawBytes RawBytes
+	rawBytes vom.RawBytes
 }{
 	{
 		name:    "testUint64(99)",
 		goValue: testUint64(99),
-		rawBytes: RawBytes{
-			Version: DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version: vom.DefaultVersion,
 			Type:    vdl.TypeOf(testUint64(0)),
 			Data:    []byte{0x63},
 		},
@@ -50,8 +50,8 @@
 	{
 		name:    "typeobject(int32)",
 		goValue: vdl.Int32Type,
-		rawBytes: RawBytes{
-			Version:  DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version:  vom.DefaultVersion,
 			Type:     vdl.TypeOf(vdl.Int32Type),
 			RefTypes: []*vdl.Type{vdl.Int32Type},
 			Data:     []byte{0x00},
@@ -60,31 +60,31 @@
 	{
 		name:    "structTypeObject{typeobject(int32)}",
 		goValue: structTypeObject{vdl.Int32Type},
-		rawBytes: RawBytes{
-			Version:  DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version:  vom.DefaultVersion,
 			Type:     vdl.TypeOf(structTypeObject{}),
 			RefTypes: []*vdl.Type{vdl.Int32Type},
-			Data:     []byte{0x00, 0x00, WireCtrlEnd},
+			Data:     []byte{0x00, 0x00, vom.WireCtrlEnd},
 		},
 	},
 	{
 		name: `structAnyAndTypes{typeobject(int32), true, typeobject(bool), "abc"}`,
 		goValue: structAnyAndTypes{
 			vdl.Int32Type,
-			&RawBytes{
-				Version: DefaultVersion,
+			&vom.RawBytes{
+				Version: vom.DefaultVersion,
 				Type:    vdl.BoolType,
 				Data:    []byte{0x01},
 			},
 			vdl.BoolType,
-			&RawBytes{
-				Version: DefaultVersion,
+			&vom.RawBytes{
+				Version: vom.DefaultVersion,
 				Type:    vdl.TypeOf(""),
 				Data:    []byte{0x03, 0x61, 0x62, 0x63},
 			},
 		},
-		rawBytes: RawBytes{
-			Version:    DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version:    vom.DefaultVersion,
 			Type:       vdl.TypeOf(structAnyAndTypes{}),
 			RefTypes:   []*vdl.Type{vdl.Int32Type, vdl.BoolType, vdl.StringType},
 			AnyLengths: []int{1, 4},
@@ -93,15 +93,15 @@
 				0x01, 0x01, 0x00, 0x01, // B
 				0x02, 0x01, // C
 				0x03, 0x02, 0x01, 0x03, 0x61, 0x62, 0x63, // D
-				WireCtrlEnd,
+				vom.WireCtrlEnd,
 			},
 		},
 	},
 	{
 		name:    "large message", // to test that multibyte length is encoded properly
 		goValue: makeLargeBytes(1000),
-		rawBytes: RawBytes{
-			Version: DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version: vom.DefaultVersion,
 			Type:    vdl.ListType(vdl.ByteType),
 			Data:    append([]byte{0xfe, 0x03, 0xe8}, makeLargeBytes(1000)...),
 		},
@@ -109,8 +109,8 @@
 	{
 		name:    "*vdl.Value",
 		goValue: vdl.ValueOf(uint16(5)),
-		rawBytes: RawBytes{
-			Version: DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version: vom.DefaultVersion,
 			Type:    vdl.Uint16Type,
 			Data:    []byte{0x05},
 		},
@@ -118,23 +118,23 @@
 	{
 		name:    "*vdl.Value - top level any",
 		goValue: vdl.ValueOf([]interface{}{uint16(5)}).Index(0),
-		rawBytes: RawBytes{
-			Version: DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version: vom.DefaultVersion,
 			Type:    vdl.Uint16Type,
 			Data:    []byte{0x05},
 		},
 	},
 	{
 		name: "any(nil)",
-		goValue: &RawBytes{
-			Version: DefaultVersion,
+		goValue: &vom.RawBytes{
+			Version: vom.DefaultVersion,
 			Type:    vdl.AnyType,
-			Data:    []byte{WireCtrlNil},
+			Data:    []byte{vom.WireCtrlNil},
 		},
-		rawBytes: RawBytes{
-			Version: DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version: vom.DefaultVersion,
 			Type:    vdl.AnyType,
-			Data:    []byte{WireCtrlNil},
+			Data:    []byte{vom.WireCtrlNil},
 		},
 	},
 }
@@ -149,13 +149,13 @@
 
 func TestDecodeToRawBytes(t *testing.T) {
 	for _, test := range rawBytesTestCases {
-		bytes, err := Encode(test.goValue)
+		bytes, err := vom.Encode(test.goValue)
 		if err != nil {
 			t.Errorf("%s: Encode failed: %v", test.name, err)
 			continue
 		}
-		var rb RawBytes
-		if err := Decode(bytes, &rb); err != nil {
+		var rb vom.RawBytes
+		if err := vom.Decode(bytes, &rb); err != nil {
 			t.Errorf("%s: Decode failed: %v", test.name, err)
 			continue
 		}
@@ -167,12 +167,12 @@
 
 func TestEncodeFromRawBytes(t *testing.T) {
 	for _, test := range rawBytesTestCases {
-		fullBytes, err := Encode(test.goValue)
+		fullBytes, err := vom.Encode(test.goValue)
 		if err != nil {
 			t.Errorf("%s: Encode goValue failed: %v", test.name, err)
 			continue
 		}
-		fullBytesFromRaw, err := Encode(&test.rawBytes)
+		fullBytesFromRaw, err := vom.Encode(&test.rawBytes)
 		if err != nil {
 			t.Errorf("%s: Encode RawBytes failed: %v", test.name, err)
 			continue
@@ -187,13 +187,13 @@
 var rawBytesWrappedTestCases = []struct {
 	name     string
 	goValue  interface{}
-	rawBytes RawBytes
+	rawBytes vom.RawBytes
 }{
 	{
 		name:    "testUint64(99)",
 		goValue: testUint64(99),
-		rawBytes: RawBytes{
-			Version:    DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version:    vom.DefaultVersion,
 			Type:       vdl.TypeOf(testUint64(0)),
 			RefTypes:   []*vdl.Type{vdl.TypeOf(testUint64(0))},
 			AnyLengths: []int{1},
@@ -203,8 +203,8 @@
 	{
 		name:    "typeobject(int32)",
 		goValue: vdl.Int32Type,
-		rawBytes: RawBytes{
-			Version:    DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version:    vom.DefaultVersion,
 			Type:       vdl.TypeOf(vdl.Int32Type),
 			RefTypes:   []*vdl.Type{vdl.TypeObjectType, vdl.Int32Type},
 			AnyLengths: []int{1},
@@ -214,8 +214,8 @@
 	{
 		name:    "structTypeObject{typeobject(int32)}",
 		goValue: structTypeObject{vdl.Int32Type},
-		rawBytes: RawBytes{
-			Version:    DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version:    vom.DefaultVersion,
 			Type:       vdl.TypeOf(structTypeObject{}),
 			RefTypes:   []*vdl.Type{vdl.TypeOf(structTypeObject{}), vdl.Int32Type},
 			AnyLengths: []int{3},
@@ -226,20 +226,20 @@
 		name: `structAnyAndTypes{typeobject(int32), true, typeobject(bool), "abc"}`,
 		goValue: structAnyAndTypes{
 			vdl.Int32Type,
-			&RawBytes{
-				Version: DefaultVersion,
+			&vom.RawBytes{
+				Version: vom.DefaultVersion,
 				Type:    vdl.BoolType,
 				Data:    []byte{0x01},
 			},
 			vdl.BoolType,
-			&RawBytes{
-				Version: DefaultVersion,
+			&vom.RawBytes{
+				Version: vom.DefaultVersion,
 				Type:    vdl.TypeOf(""),
 				Data:    []byte{0x03, 0x61, 0x62, 0x63},
 			},
 		},
-		rawBytes: RawBytes{
-			Version:    DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version:    vom.DefaultVersion,
 			Type:       vdl.TypeOf(structAnyAndTypes{}),
 			RefTypes:   []*vdl.Type{vdl.TypeOf(structAnyAndTypes{}), vdl.Int32Type, vdl.BoolType, vdl.StringType},
 			AnyLengths: []int{16, 1, 4},
@@ -255,8 +255,8 @@
 	{
 		name:    "large message", // to test that multibyte length is encoded properly
 		goValue: makeLargeBytes(1000),
-		rawBytes: RawBytes{
-			Version:    DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version:    vom.DefaultVersion,
 			Type:       vdl.ListType(vdl.ByteType),
 			RefTypes:   []*vdl.Type{vdl.ListType(vdl.ByteType)},
 			AnyLengths: []int{0x3eb},
@@ -266,8 +266,8 @@
 	{
 		name:    "*vdl.Value",
 		goValue: vdl.ValueOf(uint16(5)),
-		rawBytes: RawBytes{
-			Version:    DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version:    vom.DefaultVersion,
 			Type:       vdl.Uint16Type,
 			RefTypes:   []*vdl.Type{vdl.Uint16Type},
 			AnyLengths: []int{1},
@@ -277,8 +277,8 @@
 	{
 		name:    "*vdl.Value - top level any",
 		goValue: vdl.ValueOf([]interface{}{uint16(5)}).Index(0),
-		rawBytes: RawBytes{
-			Version:    DefaultVersion,
+		rawBytes: vom.RawBytes{
+			Version:    vom.DefaultVersion,
 			Type:       vdl.Uint16Type,
 			RefTypes:   []*vdl.Type{vdl.Uint16Type},
 			AnyLengths: []int{1},
@@ -290,13 +290,13 @@
 func TestWrappedRawBytes(t *testing.T) {
 	for i, test := range rawBytesWrappedTestCases {
 		unwrapped := rawBytesTestCases[i]
-		wrappedBytes, err := Encode(structAny{&unwrapped.rawBytes})
+		wrappedBytes, err := vom.Encode(structAny{&unwrapped.rawBytes})
 		if err != nil {
 			t.Errorf("%s: Encode failed: %v", test.name, err)
 			continue
 		}
 		var any structAny
-		if err := Decode(wrappedBytes, &any); err != nil {
+		if err := vom.Decode(wrappedBytes, &any); err != nil {
 			t.Errorf("%s: Decode failed: %v", test.name, err)
 			continue
 		}
@@ -308,11 +308,11 @@
 
 func TestEncodeNilRawBytes(t *testing.T) {
 	// Top-level
-	want, err := Encode(vdl.ZeroValue(vdl.AnyType))
+	want, err := vom.Encode(vdl.ZeroValue(vdl.AnyType))
 	if err != nil {
 		t.Fatal(err)
 	}
-	got, err := Encode((*RawBytes)(nil))
+	got, err := vom.Encode((*vom.RawBytes)(nil))
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -320,11 +320,11 @@
 		t.Errorf("top-level\nGOT  %x\nWANT %x", got, want)
 	}
 	// Within an object.
-	want, err = Encode([]*vdl.Value{vdl.ZeroValue(vdl.AnyType)})
+	want, err = vom.Encode([]*vdl.Value{vdl.ZeroValue(vdl.AnyType)})
 	if err != nil {
 		t.Fatal(err)
 	}
-	got, err = Encode([]*RawBytes{nil})
+	got, err = vom.Encode([]*vom.RawBytes{nil})
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -333,115 +333,8 @@
 	}
 }
 
-func TestRawBytesDecodeEncode(t *testing.T) {
-	versions := []struct {
-		Version Version
-		Tests   []types.TestCase
-	}{
-		{Version81, data81.Tests},
-	}
-	for _, testVersion := range versions {
-		for _, test := range testVersion.Tests {
-			// Interleaved
-			rb := RawBytes{}
-			interleavedReader := bytes.NewReader(hex2Bin(t, test.Hex))
-			if err := NewDecoder(interleavedReader).Decode(&rb); err != nil {
-				t.Errorf("unexpected error decoding %s: %v", test.Name, err)
-				continue
-			}
-			if _, err := interleavedReader.ReadByte(); err != io.EOF {
-				t.Errorf("expected EOF, but got %v", err)
-				continue
-			}
-
-			var out bytes.Buffer
-			enc := NewVersionedEncoder(testVersion.Version, &out)
-			if err := enc.Encode(&rb); err != nil {
-				t.Errorf("unexpected error encoding raw bytes %v in test %s: %v", rb, test.Name, err)
-				continue
-			}
-			if !bytes.Equal(out.Bytes(), hex2Bin(t, test.Hex)) {
-				t.Errorf("got bytes: %x but expected %s", out.Bytes(), test.Hex)
-			}
-
-			// Split type and value stream.
-			rb = RawBytes{}
-			typeReader := bytes.NewReader(hex2Bin(t, test.HexVersion+test.HexType))
-			typeDec := NewTypeDecoder(typeReader)
-			typeDec.Start()
-			defer typeDec.Stop()
-			valueReader := bytes.NewReader(hex2Bin(t, test.HexVersion+test.HexValue))
-			if err := NewDecoderWithTypeDecoder(valueReader, typeDec).Decode(&rb); err != nil {
-				t.Errorf("unexpected error decoding %s: %v", test.Name, err)
-				continue
-			}
-			if test.HexType != "" {
-				// If HexType is empty, then the type stream will just have the version byte that won't be read, so ignore
-				// that case.
-				if _, err := typeReader.ReadByte(); err != io.EOF {
-					t.Errorf("in type reader expected EOF, but got %v", err)
-					continue
-				}
-			}
-			if _, err := valueReader.ReadByte(); err != io.EOF {
-				t.Errorf("in value reader expected EOF, but got %v", err)
-				continue
-			}
-
-			out.Reset()
-			var typeOut bytes.Buffer
-			typeEnc := NewVersionedTypeEncoder(testVersion.Version, &typeOut)
-			enc = NewVersionedEncoderWithTypeEncoder(testVersion.Version, &out, typeEnc)
-			if err := enc.Encode(&rb); err != nil {
-				t.Errorf("unexpected error encoding raw value %v in test %s: %v", rb, test.Name, err)
-				continue
-			}
-			expectedType := test.HexVersion + test.HexType
-			if expectedType == "81" || expectedType == "82" {
-				expectedType = ""
-			}
-			if !bytes.Equal(typeOut.Bytes(), hex2Bin(t, expectedType)) {
-				t.Errorf("got type bytes: %x but expected %s", typeOut.Bytes(), expectedType)
-			}
-			if !bytes.Equal(out.Bytes(), hex2Bin(t, test.HexVersion+test.HexValue)) {
-				t.Errorf("got value bytes: %x but expected %s", out.Bytes(), test.HexVersion+test.HexValue)
-			}
-		}
-	}
-}
-
-func TestRawBytesToFromValue(t *testing.T) {
-	versions := []struct {
-		Version Version
-		Tests   []types.TestCase
-	}{
-		{Version81, data81.Tests},
-	}
-	for _, testVersion := range versions {
-		for _, test := range testVersion.Tests {
-			rb, err := RawBytesFromValue(test.Value)
-			if err != nil {
-				t.Fatalf("%v %s: error in RawBytesFromValue %v", testVersion.Version, test.Name, err)
-			}
-			var vv *vdl.Value
-			if err := rb.ToValue(&vv); err != nil {
-				t.Fatalf("%v %s: error in rb.ToValue %v", testVersion.Version, test.Name, err)
-			}
-			if test.Name == "any(nil)" {
-				// Skip any(nil)
-				// TODO(bprosnitz) any(nil) results in two different nil representations. This shouldn't be the case.
-				continue
-			}
-			if got, want := vv, test.Value; !vdl.EqualValue(got, want) {
-				t.Errorf("%v %s: error in converting to and from raw value. got %v, but want %v", testVersion.Version,
-					test.Name, got, want)
-			}
-		}
-	}
-}
-
 func TestVdlTypeOfRawBytes(t *testing.T) {
-	if got, want := vdl.TypeOf(&RawBytes{}), vdl.AnyType; got != want {
+	if got, want := vdl.TypeOf(&vom.RawBytes{}), vdl.AnyType; got != want {
 		t.Errorf("got %v, want %v", got, want)
 	}
 }
@@ -458,7 +351,7 @@
 
 func TestConvertRawBytes(t *testing.T) {
 	for _, test := range rawBytesTestCases {
-		var rb *RawBytes
+		var rb *vom.RawBytes
 		if err := vdl.Convert(&rb, test.goValue); err != nil {
 			t.Errorf("%s: Convert failed: %v", test.name, err)
 		}
@@ -490,7 +383,7 @@
 // are more ids in the encoder/decoder.
 func TestReusedDecoderEncoderRawBytes(t *testing.T) {
 	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
+	enc := vom.NewEncoder(&buf)
 	if err := enc.Encode(structAnyInterface{int64(4)}); err != nil {
 		t.Fatalf("error on encode: %v", err)
 	}
@@ -498,7 +391,7 @@
 		t.Fatalf("error on encode: %v", err)
 	}
 
-	dec := NewDecoder(bytes.NewReader(buf.Bytes()))
+	dec := vom.NewDecoder(bytes.NewReader(buf.Bytes()))
 	var x structAny
 	if err := dec.Decode(&x); err != nil {
 		t.Fatalf("error on decode: %v", err)
@@ -525,12 +418,12 @@
 
 func TestRawBytesString(t *testing.T) {
 	tests := []struct {
-		input    *RawBytes
+		input    *vom.RawBytes
 		expected string
 	}{
 		{
-			input: &RawBytes{
-				Version81,
+			input: &vom.RawBytes{
+				vom.Version81,
 				vdl.Int8Type,
 				[]*vdl.Type{vdl.BoolType, vdl.StringType},
 				[]int{4},
@@ -538,8 +431,8 @@
 			expected: "RawBytes{Version81, int8, RefTypes{bool, string}, AnyLengths{4}, fa0e9dcc}",
 		},
 		{
-			input: &RawBytes{
-				Version81,
+			input: &vom.RawBytes{
+				vom.Version81,
 				vdl.Int8Type,
 				[]*vdl.Type{vdl.BoolType},
 				[]int{},
@@ -547,8 +440,8 @@
 			expected: "RawBytes{Version81, int8, RefTypes{bool}, fa0e9dcc}",
 		},
 		{
-			input: &RawBytes{
-				Version81,
+			input: &vom.RawBytes{
+				vom.Version81,
 				vdl.Int8Type,
 				nil,
 				nil,
@@ -564,10 +457,10 @@
 }
 
 func TestRawBytesVDLType(t *testing.T) {
-	if got, want := vdl.TypeOf(RawBytes{}), vdl.AnyType; got != want {
+	if got, want := vdl.TypeOf(vom.RawBytes{}), vdl.AnyType; got != want {
 		t.Errorf("vom.RawBytes{} got %v, want %v", got, want)
 	}
-	if got, want := vdl.TypeOf((*RawBytes)(nil)), vdl.AnyType; got != want {
+	if got, want := vdl.TypeOf((*vom.RawBytes)(nil)), vdl.AnyType; got != want {
 		t.Errorf("vom.RawBytes{} got %v, want %v", got, want)
 	}
 }
@@ -586,20 +479,20 @@
 	// of dealing with the format for describing types with any in the
 	// value message header.
 	var typeBuf, buf bytes.Buffer
-	typeEnc := NewTypeEncoder(&typeBuf)
-	if err := NewEncoderWithTypeEncoder(&buf, typeEnc).Encode(simpleStruct{5}); err != nil {
+	typeEnc := vom.NewTypeEncoder(&typeBuf)
+	if err := vom.NewEncoderWithTypeEncoder(&buf, typeEnc).Encode(simpleStruct{5}); err != nil {
 		t.Fatalf("failure when preparing type message bytes: %v", t)
 	}
 	var inputMessage []byte = typeBuf.Bytes()
-	inputMessage = append(inputMessage, byte(WireIdFirstUserType*2)) // New value message tid
-	inputMessage = append(inputMessage, 8)                           // Message length
+	inputMessage = append(inputMessage, byte(vom.WireIdFirstUserType*2)) // New value message tid
+	inputMessage = append(inputMessage, 8)                               // Message length
 	// non-vom bytes (invalid because there is no struct field at index 10)
 	dataPortion := []byte{10, 20, 30, 40, 50, 60, 70, 80}
 	inputMessage = append(inputMessage, dataPortion...)
 
 	// Now ensure decoding into a RawBytes works correctly.
-	var rb *RawBytes
-	if err := Decode(inputMessage, &rb); err != nil {
+	var rb *vom.RawBytes
+	if err := vom.Decode(inputMessage, &rb); err != nil {
 		t.Fatalf("error decoding %x into a RawBytes: %v", inputMessage, err)
 	}
 	if got, want := rb.Type, vdl.TypeOf(simpleStruct{}); got != want {
@@ -610,7 +503,7 @@
 	}
 
 	// Now re-encode and ensure that we get the original bytes.
-	encoded, err := Encode(rb)
+	encoded, err := vom.Encode(rb)
 	if err != nil {
 		t.Fatalf("error encoding RawBytes %v: %v", rb, err)
 	}
@@ -619,40 +512,123 @@
 	}
 }
 
-func TestRawBytesDecoder(t *testing.T) {
-	regex := filterRegex(t)
-	for _, test := range data81.Tests {
-		if !regex.MatchString(test.Name) {
+func TestRawBytesDecodeEncode(t *testing.T) {
+	for _, test := range vomtest.AllPass() {
+		// Interleaved
+		rb := vom.RawBytes{}
+		interleavedReader := bytes.NewReader(test.Bytes())
+		if err := vom.NewDecoder(interleavedReader).Decode(&rb); err != nil {
+			t.Errorf("%s: decode failed: %v", test.Name(), err)
+			continue
+		}
+		if _, err := interleavedReader.ReadByte(); err != io.EOF {
+			t.Errorf("%s: expected EOF, but got %v", test.Name(), err)
 			continue
 		}
 
-		in := RawBytesOf(test.Value)
-		out := vdl.ZeroValue(test.Value.Type())
-		if err := out.VDLRead(in.Decoder()); err != nil {
-			t.Errorf("%s: error in ValueRead: %v", test.Name, err)
+		var out bytes.Buffer
+		enc := vom.NewVersionedEncoder(test.Version, &out)
+		if err := enc.Encode(&rb); err != nil {
+			t.Errorf("%s: encode failed: %v\nRawBytes: %v", test.Name(), err, rb)
 			continue
 		}
-		if !vdl.EqualValue(test.Value, out) {
-			t.Errorf("%s: got %v, want %v", test.Name, out, test.Value)
+		if got, want := out.Bytes(), test.Bytes(); !bytes.Equal(got, want) {
+			t.Errorf("%s\nGOT  %x\nWANT %x", test.Name(), got, want)
+		}
+
+		// Split type and value stream.
+		rb = vom.RawBytes{}
+		typeReader := bytes.NewReader(test.TypeBytes())
+		typeDec := vom.NewTypeDecoder(typeReader)
+		typeDec.Start()
+		defer typeDec.Stop()
+		valueReader := bytes.NewReader(test.ValueBytes())
+		if err := vom.NewDecoderWithTypeDecoder(valueReader, typeDec).Decode(&rb); err != nil {
+			t.Errorf("%s: decode failed: %v", test.Name(), err)
+			continue
+		}
+		if _, err := typeReader.ReadByte(); err != io.EOF {
+			t.Errorf("%s: type reader got %v, want EOF", test.Name(), err)
+			continue
+		}
+		if _, err := valueReader.ReadByte(); err != io.EOF {
+			t.Errorf("%s: value reader got %v, want EOF", test.Name(), err)
+			continue
+		}
+
+		out.Reset()
+		var typeOut bytes.Buffer
+		typeEnc := vom.NewVersionedTypeEncoder(test.Version, &typeOut)
+		enc = vom.NewVersionedEncoderWithTypeEncoder(test.Version, &out, typeEnc)
+		if err := enc.Encode(&rb); err != nil {
+			t.Errorf("%s: encode failed: %v\nRawBytes: %v", test.Name(), err, rb)
+			continue
+		}
+		if got, want := typeOut.Bytes(), test.TypeBytes(); !bytes.Equal(got, want) {
+			t.Errorf("%s: type bytes\nGOT  %x\nWANT %x", test.Name(), got, want)
+		}
+		if got, want := out.Bytes(), test.ValueBytes(); !bytes.Equal(got, want) {
+			t.Errorf("%s: value bytes\nGOT  %x\nWANT %x", test.Name(), got, want)
+		}
+	}
+}
+
+func TestRawBytesToFromValue(t *testing.T) {
+	for _, test := range vomtest.AllPass() {
+		rb, err := vom.RawBytesFromValue(test.Value.Interface())
+		if err != nil {
+			t.Errorf("%v %s: RawBytesFromValue failed: %v", test.Version, test.Name(), err)
+			continue
+		}
+		var vv *vdl.Value
+		if err := rb.ToValue(&vv); err != nil {
+			t.Errorf("%v %s: rb.ToValue failed: %v", test.Version, test.Name(), err)
+			continue
+		}
+		if got, want := vv, vdl.ValueOf(test.Value.Interface()); !vdl.EqualValue(got, want) {
+			t.Errorf("%v %s\nGOT  %v\nWANT %v", test.Version, test.Name(), got, want)
+		}
+	}
+}
+
+func TestRawBytesDecoder(t *testing.T) {
+	for _, test := range vomtest.AllPass() {
+		tt, err := vdl.TypeFromReflect(test.Value.Type())
+		if err != nil {
+			t.Errorf("%s: TypeFromReflect failed: %v", test.Name(), err)
+			continue
+		}
+		in, err := vom.RawBytesFromValue(test.Value.Interface())
+		if err != nil {
+			t.Errorf("%s: RawBytesFromValue failed: %v", test.Name(), err)
+			continue
+		}
+		out := vdl.ZeroValue(tt)
+		if err := out.VDLRead(in.Decoder()); err != nil {
+			t.Errorf("%s: VDLRead failed: %v", test.Name(), err)
+			continue
+		}
+		if got, want := out, vdl.ValueOf(test.Value.Interface()); !vdl.EqualValue(got, want) {
+			t.Errorf("%s\nGOT  %v\nWANT %v", test.Name(), got, want)
 		}
 	}
 }
 
 func TestRawBytesWriter(t *testing.T) {
-	regex := filterRegex(t)
-	for _, test := range data81.Tests {
-		if !regex.MatchString(test.Name) {
-			continue
-		}
-
+	for _, test := range vomtest.AllPass() {
 		var buf bytes.Buffer
-		enc := NewEncoder(&buf)
-		if err := RawBytesOf(test.Value).VDLWrite(enc.Encoder()); err != nil {
-			t.Errorf("%s: error in transcode: %v", test.Name, err)
+		enc := vom.NewEncoder(&buf)
+		rb, err := vom.RawBytesFromValue(test.Value.Interface())
+		if err != nil {
+			t.Errorf("%s: RawBytesFromValue failed: %v", test.Name(), err)
 			continue
 		}
-		if got, want := buf.Bytes(), hex2Bin(t, test.Hex); !bytes.Equal(got, want) {
-			t.Errorf("%s: got %x, want %x", test.Name, got, want)
+		if err := rb.VDLWrite(enc.Encoder()); err != nil {
+			t.Errorf("%s: VDLWrite failed: %v", test.Name(), err)
+			continue
+		}
+		if got, want := buf.Bytes(), test.Bytes(); !bytes.Equal(got, want) {
+			t.Errorf("%s\nGOT  %x\nWANT %x", test.Name(), got, want)
 		}
 	}
 }
diff --git a/vom/transcode_test.go b/vom/transcode_test.go
index a91bafb..aa00779 100644
--- a/vom/transcode_test.go
+++ b/vom/transcode_test.go
@@ -2,70 +2,43 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package vom
+package vom_test
 
 import (
 	"bytes"
-	"flag"
-	"regexp"
 	"testing"
 
 	"v.io/v23/vdl"
-	"v.io/v23/vom/testdata/data81"
+	"v.io/v23/vom"
+	"v.io/v23/vom/vomtest"
 )
 
-var filter *string = flag.String("testdata-filter", "", "regex for allowed testdata tests")
-
-func init() {
-	flag.Parse()
-}
-
-func filterRegex(t *testing.T) *regexp.Regexp {
-	pattern := ".*" + *filter + ".*"
-	regex, err := regexp.Compile(pattern)
-	if err != nil {
-		t.Fatalf("invalid regex filter %q", *filter)
-	}
-	return regex
-}
-
-func TestTranscodeXDecoderToXEncoder(t *testing.T) {
-	regex := filterRegex(t)
-	for _, test := range data81.Tests {
-		if !regex.MatchString(test.Name) {
-			continue
-		}
-
-		inBytes := hex2Bin(t, test.Hex)
+func TestTranscodeDecoderToEncoder(t *testing.T) {
+	for _, test := range vomtest.AllPass() {
 		var buf bytes.Buffer
-		enc := NewEncoder(&buf)
-		dec := NewDecoder(bytes.NewReader(inBytes))
+		enc := vom.NewVersionedEncoder(test.Version, &buf)
+		dec := vom.NewDecoder(bytes.NewReader(test.Bytes()))
 		if err := vdl.Transcode(enc.Encoder(), dec.Decoder()); err != nil {
-			t.Errorf("%s: error in transcode: %v", test.Name, err)
+			t.Errorf("%s: Transcode failed: %v", test.Name(), err)
 			continue
 		}
-		if got, want := buf.Bytes(), inBytes; !bytes.Equal(got, want) {
-			t.Errorf("%s: got %x, want %x", test.Name, got, want)
+		if got, want := buf.Bytes(), test.Bytes(); !bytes.Equal(got, want) {
+			t.Errorf("%s\nGOT  %x\nWANT %x", test.Name(), got, want)
 		}
 	}
 }
 
 // TODO(bprosnitz) This is probably not the right place for this test.
-func TestTranscodeVDLValueToXEncoder(t *testing.T) {
-	regex := filterRegex(t)
-	for _, test := range data81.Tests {
-		if !regex.MatchString(test.Name) {
-			continue
-		}
-
+func TestTranscodeVDLValueToEncoder(t *testing.T) {
+	for _, test := range vomtest.AllPass() {
 		var buf bytes.Buffer
-		enc := NewEncoder(&buf)
-		if err := test.Value.VDLWrite(enc.Encoder()); err != nil {
-			t.Errorf("%s: error in transcode: %v", test.Name, err)
+		enc := vom.NewEncoder(&buf)
+		if err := vdl.Write(enc.Encoder(), test.Value.Interface()); err != nil {
+			t.Errorf("%s: vdl.Write failed: %v", test.Name(), err)
 			continue
 		}
-		if got, want := buf.Bytes(), hex2Bin(t, test.Hex); !bytes.Equal(got, want) {
-			t.Errorf("%s: got %x, want %x", test.Name, got, want)
+		if got, want := buf.Bytes(), test.Bytes(); !bytes.Equal(got, want) {
+			t.Errorf("%s\nGOT  %x\nWANT %x", test.Name(), got, want)
 		}
 	}
 }
diff --git a/vom/xdecoder.go b/vom/xdecoder.go
deleted file mode 100644
index bcbb932..0000000
--- a/vom/xdecoder.go
+++ /dev/null
@@ -1,800 +0,0 @@
-// 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)
-}
diff --git a/vom/xdecoder_test.go b/vom/xdecoder_test.go
deleted file mode 100644
index 90fd789..0000000
--- a/vom/xdecoder_test.go
+++ /dev/null
@@ -1,134 +0,0 @@
-// Copyright 2015 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_test
-
-import (
-	"bytes"
-	"fmt"
-	"io"
-	"reflect"
-	"sync"
-	"testing"
-
-	"v.io/v23/vdl"
-	"v.io/v23/vom"
-	"v.io/v23/vom/vomtest"
-
-	// Import verror to ensure that interface tests result in *verror.E
-	_ "v.io/v23/verror"
-)
-
-// TODO(toddw): Add all useful tests from decoder_test.go
-
-var (
-	rtIface = reflect.TypeOf((*interface{})(nil)).Elem()
-	rtValue = reflect.TypeOf(vdl.Value{})
-)
-
-func TestXDecoder(t *testing.T) {
-	// The decoder tests take a long time, so we run them concurrently.
-	var pending sync.WaitGroup
-	for _, test := range vomtest.AllPass() {
-		pending.Add(1)
-		go func(test vomtest.Entry) {
-			defer pending.Done()
-			testXDecoder(t, "[go value]", test, rvPtrValue(test.Value))
-			testXDecoder(t, "[go iface]", test, rvPtrIface(test.Value))
-			vv, err := vdl.ValueFromReflect(test.Value)
-			if err != nil {
-				t.Errorf("%s: ValueFromReflect failed: %v", test.Name(), err)
-				return
-			}
-			vvWant := reflect.ValueOf(vv)
-			testXDecoder(t, "[new *vdl.Value]", test, vvWant)
-			testXDecoderFunc(t, "[zero vdl.Value]", test, vvWant, func() reflect.Value {
-				return reflect.ValueOf(vdl.ZeroValue(vv.Type()))
-			})
-		}(test)
-	}
-	pending.Wait()
-}
-
-func rvPtrValue(rv reflect.Value) reflect.Value {
-	result := reflect.New(rv.Type())
-	result.Elem().Set(rv)
-	return result
-}
-
-func rvPtrIface(rv reflect.Value) reflect.Value {
-	result := reflect.New(rtIface)
-	result.Elem().Set(rv)
-	return result
-}
-
-func testXDecoder(t *testing.T, pre string, test vomtest.Entry, rvWant reflect.Value) {
-	testXDecoderFunc(t, pre, test, rvWant, func() reflect.Value {
-		return reflect.New(rvWant.Type().Elem())
-	})
-	// TODO(toddw): Add tests that start with a randomly-set value.
-}
-
-func testXDecoderFunc(t *testing.T, pre string, test vomtest.Entry, rvWant reflect.Value, rvNew func() reflect.Value) {
-	readEOF := make([]byte, 1)
-	for _, mode := range vom.AllReadModes {
-		// Test vom.NewXDecoder.
-		{
-			name := fmt.Sprintf("%s (%s) %s", pre, mode, test.Name())
-			rvGot := rvNew()
-			reader := mode.TestReader(bytes.NewReader(test.Bytes()))
-			dec := vom.NewDecoder(reader)
-			if err := dec.Decode(rvGot.Interface()); err != nil {
-				t.Errorf("%s: Decode failed: %v", name, err)
-				return
-			}
-			if !vdl.DeepEqualReflect(rvGot, rvWant) {
-				t.Errorf("%s\nGOT  %v\nWANT %v", name, rvGot, rvWant)
-				return
-			}
-			if n, err := reader.Read(readEOF); n != 0 || err != io.EOF {
-				t.Errorf("%s: reader got (%d,%v), want (0,EOF)", name, n, err)
-			}
-		}
-		// Test vom.NewXDecoderWithTypeDecoder
-		{
-			name := fmt.Sprintf("%s (%s with TypeDecoder) %s", pre, mode, test.Name())
-			rvGot := rvNew()
-			readerT := mode.TestReader(bytes.NewReader(test.TypeBytes()))
-			decT := vom.NewTypeDecoder(readerT)
-			decT.Start()
-			reader := mode.TestReader(bytes.NewReader(test.ValueBytes()))
-			dec := vom.NewDecoderWithTypeDecoder(reader, decT)
-			err := dec.Decode(rvGot.Interface())
-			decT.Stop()
-			if err != nil {
-				t.Errorf("%s: Decode failed: %v", name, err)
-				return
-			}
-			if !vdl.DeepEqualReflect(rvGot, rvWant) {
-				t.Errorf("%s\nGOT  %v\nWANT %v", name, rvGot, rvWant)
-				return
-			}
-			if n, err := reader.Read(readEOF); n != 0 || err != io.EOF {
-				t.Errorf("%s: reader got (%d,%v), want (0,EOF)", name, n, err)
-			}
-			if n, err := readerT.Read(readEOF); n != 0 || err != io.EOF {
-				t.Errorf("%s: readerT got (%d,%v), want (0,EOF)", name, n, err)
-			}
-		}
-	}
-	// Test single-shot vom.Decode twice, to ensure we test the cache hit case.
-	for i := 0; i < 2; i++ {
-		name := fmt.Sprintf("%s (single-shot %d) %s", pre, i, test.Name())
-		rvGot := rvNew()
-		if err := vom.Decode(test.Bytes(), rvGot.Interface()); err != nil {
-			t.Errorf("%s: Decode failed: %v", name, err)
-			return
-		}
-		if !vdl.DeepEqualReflect(rvGot, rvWant) {
-			t.Errorf("%s\nGOT  %v\nWANT %v", name, rvGot, rvWant)
-			return
-		}
-	}
-}
diff --git a/vom/xencoder_test.go b/vom/xencoder_test.go
deleted file mode 100644
index 2b9d013..0000000
--- a/vom/xencoder_test.go
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2015 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_test
-
-import (
-	"bytes"
-	"fmt"
-	"testing"
-
-	"v.io/v23/vdl"
-	"v.io/v23/vom"
-	"v.io/v23/vom/vomtest"
-)
-
-func TestXEncoder(t *testing.T) {
-	for _, test := range vomtest.AllPass() {
-		testXEncoder(t, "[go value]", test, test.Value.Interface())
-		vv, err := vdl.ValueFromReflect(test.Value)
-		if err != nil {
-			t.Errorf("%s: ValueFromReflect failed: %v", test.Name(), err)
-			continue
-		}
-		testXEncoder(t, "[vdl.Value]", test, vv)
-	}
-}
-
-func testXEncoder(t *testing.T, pre string, test vomtest.Entry, value interface{}) {
-	// Test vom.NewXEncoder.
-	{
-		var buf bytes.Buffer
-		name := fmt.Sprintf("%s %s", pre, test.Name())
-		enc := vom.NewVersionedEncoder(test.Version, &buf)
-		if err := enc.Encode(value); err != nil {
-			t.Errorf("%s: Encode failed: %v", name, err)
-			return
-		}
-		if got, want := buf.Bytes(), test.Bytes(); !bytes.Equal(got, want) {
-			t.Errorf("%s\nGOT  %x\nWANT %x", name, got, want)
-			return
-		}
-	}
-	// Test vom.NewXEncoderWithTypeEncoder.
-	{
-		var buf, bufT bytes.Buffer
-		name := fmt.Sprintf("%s (with TypeEncoder) %s", pre, test.Name())
-		encT := vom.NewVersionedTypeEncoder(test.Version, &bufT)
-		enc := vom.NewVersionedEncoderWithTypeEncoder(test.Version, &buf, encT)
-		if err := enc.Encode(value); err != nil {
-			t.Errorf("%s: Encode failed: %v", name, err)
-			return
-		}
-		if got, want := bufT.Bytes(), test.TypeBytes(); !bytes.Equal(got, want) {
-			t.Errorf("%s TYPE\nGOT  %x\nWANT %x", name, got, want)
-			return
-		}
-		if got, want := buf.Bytes(), test.ValueBytes(); !bytes.Equal(got, want) {
-			t.Errorf("%s VALUE\nGOT  %x\nWANT %x", name, got, want)
-			return
-		}
-	}
-	// Test single-shot vom.XEncode.
-	{
-		name := fmt.Sprintf("%s (single-shot) %s", pre, test.Name())
-		buf, err := vom.VersionedEncode(test.Version, value)
-		if err != nil {
-			t.Errorf("%s: Encode failed: %v", name, err)
-			return
-		}
-		if got, want := buf, test.Bytes(); !bytes.Equal(got, want) {
-			t.Errorf("%s\nGOT  %x\nWANT %x", name, got, want)
-			return
-		}
-	}
-}