XEncoder test passes

Change-Id: I8d7744a59971daac8509f025bb29af7e78e6b9a1
diff --git a/vdl/pipe.go b/vdl/pipe.go
index 8f4df48..cebaa18 100644
--- a/vdl/pipe.go
+++ b/vdl/pipe.go
@@ -296,7 +296,7 @@
 	d.Enc.Mu.Lock()
 	defer d.Enc.Mu.Unlock()
 	if d.Enc.DecStarted && d.Enc.State != pipeStateDecoder {
-		return d.Close(errInvalidPipeState)
+		return d.Enc.closeLocked(errInvalidPipeState)
 	}
 	if d.IgnoringNextStartValue {
 		d.IgnoringNextStartValue = false
@@ -310,10 +310,10 @@
 	}
 	top := d.decTop()
 	if top == nil {
-		return d.Close(errEmptyPipeStack)
+		return d.Enc.closeLocked(errEmptyPipeStack)
 	}
 	if top.NextOp != pipeStartDec {
-		return d.Close(fmt.Errorf("vdl: pipe expected state %v, but got %v", pipeStartDec, top.NextOp))
+		return d.Enc.closeLocked(fmt.Errorf("vdl: pipe expected state %v, but got %v", pipeStartDec, top.NextOp))
 	}
 	top.NextOp = top.NextOp.Next()
 	return d.Enc.Err
@@ -653,7 +653,7 @@
 	case numberFloat:
 		x := d.Enc.ArgFloat
 		if bitlen <= 32 && (x < -math.MaxFloat32 || x > math.MaxFloat32) {
-			return 0, d.Close(fmt.Errorf(errFmt, "float", bitlen, x))
+			return 0, d.Enc.closeLocked(fmt.Errorf(errFmt, "float", bitlen, x))
 		}
 		return x, d.Enc.Err
 	}
@@ -672,10 +672,13 @@
 
 func (d *pipeDecoder) DecodeBytes(fixedLen int, b *[]byte) error {
 	if !d.Enc.IsBytes {
-		return d.Close(bytesVDLRead(fixedLen, b, d))
+		if err := bytesVDLRead(fixedLen, b, d); err != nil {
+			return d.Enc.closeLocked(err)
+		}
+		return nil
 	}
 	if fixedLen >= 0 && fixedLen != len(d.Enc.ArgBytes) {
-		return d.Close(fmt.Errorf("invalid byte len: got %v, want %v", len(d.Enc.ArgBytes), fixedLen))
+		return d.Enc.closeLocked(fmt.Errorf("invalid byte len: got %v, want %v", len(d.Enc.ArgBytes), fixedLen))
 	}
 	if len(*b) < len(d.Enc.ArgBytes) {
 		*b = make([]byte, len(d.Enc.ArgBytes))
diff --git a/vdl/target.go b/vdl/target.go
index 4e0acef..517ebb3 100644
--- a/vdl/target.go
+++ b/vdl/target.go
@@ -167,6 +167,10 @@
 		}
 		return result, nil
 	}
+	if !rv.IsValid() {
+		// TODO(bprosnitz) Is this the behavior we want?
+		return ZeroValue(AnyType), nil
+	}
 	var result *Value
 	err := convertPipe(&result, rv.Interface())
 	return result, err
diff --git a/vom/.api b/vom/.api
index e22048f..d8bff51 100644
--- a/vom/.api
+++ b/vom/.api
@@ -65,6 +65,8 @@
 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 VersionedXEncode(Version, interface{}) ([]byte, error)
+pkg vom, func XDecode([]byte, interface{}) error
 pkg vom, method (*ControlKind) FillVDLTarget(vdl.Target, *vdl.Type) error
 pkg vom, method (*ControlKind) MakeVDLTarget() vdl.Target
 pkg vom, method (*ControlKind) Set(string) error
diff --git a/vom/new_decoder_test.go b/vom/new_decoder_test.go
index 89e6e28..8fb1e2f 100644
--- a/vom/new_decoder_test.go
+++ b/vom/new_decoder_test.go
@@ -7,7 +7,9 @@
 package vom
 
 import (
+	"fmt"
 	"reflect"
+	"strings"
 	"testing"
 
 	"v.io/v23/vdl"
@@ -31,23 +33,141 @@
 
 		vdlValue := vdl.ValueOf(test.Value)
 		name := test.Name + " [vdl.Value]"
-		testDecodeVDL(t, name, binversion+bintype+binvalue, vdlValue)
+		testDecodeVDLNew(t, name, binversion+bintype+binvalue, vdlValue)
 		name = test.Name + " [vdl.Value] (with TypeDecoder)"
-		testDecodeVDLWithTypeDecoder(t, name, binversion, bintype, binvalue, vdlValue)
+		testDecodeVDLWithTypeDecoderNew(t, name, binversion, bintype, binvalue, vdlValue)
 		name = test.Name + " [vdl.Any]"
-		testDecodeVDL(t, name, binversion+bintype+binvalue, vdl.AnyValue(vdlValue))
+		testDecodeVDLNew(t, name, binversion+bintype+binvalue, vdl.AnyValue(vdlValue))
 		name = test.Name + " [vdl.Any] (with TypeDecoder)"
-		testDecodeVDLWithTypeDecoder(t, name, binversion, bintype, binvalue, vdl.AnyValue(vdlValue))
+		testDecodeVDLWithTypeDecoderNew(t, name, binversion, bintype, binvalue, vdl.AnyValue(vdlValue))
 
 		// Convert in
 		name = test.Name + " [go value]"
-		testDecodeGo(t, name, binversion+bintype+binvalue, reflect.TypeOf(test.Value), test.Value)
+		testDecodeGoNew(t, name, binversion+bintype+binvalue, reflect.TypeOf(test.Value), test.Value)
 		name = test.Name + " [go value] (with TypeDecoder)"
-		testDecodeGoWithTypeDecoder(t, name, binversion, bintype, binvalue, reflect.TypeOf(test.Value), test.Value)
+		testDecodeGoWithTypeDecoderNew(t, name, binversion, bintype, binvalue, reflect.TypeOf(test.Value), test.Value)
 
 		name = test.Name + " [go interface]"
-		testDecodeGo(t, name, binversion+bintype+binvalue, reflect.TypeOf((*interface{})(nil)).Elem(), test.Value)
+		testDecodeGoNew(t, name, binversion+bintype+binvalue, reflect.TypeOf((*interface{})(nil)).Elem(), test.Value)
 		name = test.Name + " [go interface] (with TypeDecoder)"
-		testDecodeGoWithTypeDecoder(t, name, binversion, bintype, binvalue, reflect.TypeOf((*interface{})(nil)).Elem(), test.Value)
+		testDecodeGoWithTypeDecoderNew(t, name, binversion, bintype, binvalue, reflect.TypeOf((*interface{})(nil)).Elem(), test.Value)
+	}
+}
+
+func testDecodeVDLNew(t *testing.T, name, bin string, value *vdl.Value) {
+	for _, mode := range allReadModes {
+		head := fmt.Sprintf("%s (%s)", name, mode)
+		decoder := NewXDecoder(mode.testReader(strings.NewReader(bin)))
+		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)
+			return
+		}
+		if want := value; !vdl.EqualValue(got, want) {
+			t.Errorf("%s: Decode mismatch\nGOT  %v\nWANT %v", head, got, want)
+			return
+		}
+	}
+	// Test single-shot vom.Decode twice, to ensure we test the cache hit case.
+	testDecodeVDLSingleShotNew(t, name, bin, value)
+	testDecodeVDLSingleShotNew(t, name, bin, value)
+}
+
+func testDecodeVDLSingleShotNew(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 := XDecode([]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 testDecodeVDLWithTypeDecoderNew(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 := NewXDecoderWithTypeDecoder(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)
+			return
+		}
+		if want := value; !vdl.EqualValue(got, want) {
+			t.Errorf("%s: Decode mismatch\nGOT  %v\nWANT %v", head, got, want)
+			return
+		}
+		typedec.Stop()
+	}
+}
+
+func testDecodeGoNew(t *testing.T, name, bin string, rt reflect.Type, want interface{}) {
+	for _, mode := range allReadModes {
+		head := fmt.Sprintf("%s (%s)", name, mode)
+		decoder := NewXDecoder(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.
+	testDecodeGoSingleShotNew(t, name, bin, rt, want)
+	testDecodeGoSingleShotNew(t, name, bin, rt, want)
+}
+
+func testDecodeGoSingleShotNew(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 := XDecode([]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 testDecodeGoWithTypeDecoderNew(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 := NewXDecoderWithTypeDecoder(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()
 	}
 }
diff --git a/vom/new_encoder_test.go b/vom/new_encoder_test.go
deleted file mode 100644
index 5e95227..0000000
--- a/vom/new_encoder_test.go
+++ /dev/null
@@ -1,31 +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 vom
-
-import (
-	"fmt"
-	"testing"
-	"v.io/v23/vdl"
-	"v.io/v23/vom/vomtest"
-)
-
-func TestEncoderNew(t *testing.T) {
-	for _, test := range vomtest.Data() {
-		version := Version(test.Version)
-		hexVersion := fmt.Sprintf("%x", test.Version)
-		vdlValue := vdl.ValueOf(test.Value)
-		name := test.Name + " [vdl.Value]"
-		testEncode(t, version, name, vdlValue, hexVersion+test.HexType+test.HexValue)
-		name = test.Name + " [vdl.Value] (with TypeEncoder)"
-		testEncodeWithTypeEncoder(t, version, name, vdlValue, hexVersion, test.HexType, test.HexValue)
-
-		name = test.Name + " [go value]"
-		testEncode(t, version, name, test.Value, hexVersion+test.HexType+test.HexValue)
-		name = test.Name + " [go value] (with TypeEncoder)"
-		testEncodeWithTypeEncoder(t, version, name, test.Value, hexVersion, test.HexType, test.HexValue)
-	}
-}
diff --git a/vom/single_shot.go b/vom/single_shot.go
index f3a1a08..090b960 100644
--- a/vom/single_shot.go
+++ b/vom/single_shot.go
@@ -30,6 +30,14 @@
 	return buf.Bytes(), nil
 }
 
+func VersionedXEncode(version Version, v interface{}) ([]byte, error) {
+	var buf bytes.Buffer
+	if err := NewVersionedXEncoder(version, &buf).Encode(v); err != nil {
+		return nil, err
+	}
+	return buf.Bytes(), nil
+}
+
 // Decode reads the value from the given data, and stores it in value v.  The
 // semantics of value decoding are described by Decoder.Decode.
 //
@@ -76,6 +84,51 @@
 	return nil
 }
 
+func XDecode(data []byte, v interface{}) error {
+	// The implementation below corresponds (logically) to the following:
+	//   return NewDecoder(bytes.NewReader(data)).Decode(valptr)
+	//
+	// However decoding type messages is expensive, so we cache typeDecoders to
+	// skip the decoding in the common case.
+	key, err := computeTypeDecoderCacheKey(data)
+	if err != nil {
+		return err
+	}
+	var buf *decbuf
+	typeDec := singleShotTypeDecoderCache.lookup(key)
+	cacheMiss := false
+	if typeDec == nil {
+		// Cache miss; start decoding at the beginning of all type messages with a
+		// new TypeDecoder.
+		cacheMiss = true
+		buf = newDecbufFromBytes(data)
+		typeDec = newTypeDecoderInternal(buf)
+	} else {
+		version := Version(data[0])
+		data = data[len(key):] // skip the already-read types
+		buf = newDecbufFromBytes(data)
+		buf.version = version
+		typeDec = newDerivedTypeDecoderInternal(buf, typeDec)
+	}
+	// Decode the value message.
+	decoder := &XDecoder{
+		xDecoder{
+			old: &Decoder{
+				buf:     buf,
+				typeDec: typeDec,
+			},
+		},
+	}
+	if err := decoder.Decode(v); err != nil {
+		return err
+	}
+	// Populate the typeDecoder cache for future re-use.
+	if cacheMiss {
+		singleShotTypeDecoderCache.insert(key, typeDec)
+	}
+	return nil
+}
+
 // singleShotTypeDecoderCache is a global cache of TypeDecoders keyed by the
 // bytes of the sequence of type messages before the value message.  A sequence
 // of type messages that is byte-equal doesn't guarantee the same types in the
diff --git a/vom/xencoder.go b/vom/xencoder.go
index f3a6b86..c936132 100644
--- a/vom/xencoder.go
+++ b/vom/xencoder.go
@@ -144,7 +144,7 @@
 
 	nextValueIsAny := e.top().nextValueIsAny()
 	var anyRef anyStartRef
-	if nextValueIsAny {
+	if nextValueIsAny && tt.Kind() == vdl.Optional {
 		tid, err := e.typeEnc.encode(tt)
 		if err != nil {
 			return err
@@ -154,7 +154,7 @@
 		binaryEncodeUint(e.buf, uint64(anyRef.index))
 	}
 	binaryEncodeControl(e.buf, WireCtrlNil)
-	if nextValueIsAny {
+	if nextValueIsAny && tt.Kind() == vdl.Optional {
 		e.anyLens.FinishAny(anyRef, e.buf.Len())
 	}
 
diff --git a/vom/xencoder_test.go b/vom/xencoder_test.go
new file mode 100644
index 0000000..a1a721f
--- /dev/null
+++ b/vom/xencoder_test.go
@@ -0,0 +1,90 @@
+// 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 vom
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+
+	"v.io/v23/vdl"
+	"v.io/v23/vom/vomtest"
+)
+
+func TestXEncoder(t *testing.T) {
+	for _, test := range vomtest.Data() {
+		version := Version(test.Version)
+		hexVersion := fmt.Sprintf("%x", test.Version)
+		vdlValue := vdl.ValueOf(test.Value)
+		name := test.Name + " [vdl.Value]"
+		testXEncode(t, version, name, vdlValue, hexVersion+test.HexType+test.HexValue)
+		name = test.Name + " [vdl.Value] (with TypeEncoder)"
+		testXEncodeWithTypeEncoder(t, version, name, vdlValue, hexVersion, test.HexType, test.HexValue)
+
+		name = test.Name + " [go value]"
+		testXEncode(t, version, name, test.Value, hexVersion+test.HexType+test.HexValue)
+		name = test.Name + " [go value] (with TypeEncoder)"
+		testXEncodeWithTypeEncoder(t, version, name, test.Value, hexVersion, test.HexType, test.HexValue)
+	}
+}
+
+func testXEncode(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 := NewVersionedXEncoder(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 = VersionedXEncode(version, value)
+			if err != nil {
+				t.Errorf("%s: Encode(%#v) failed: %v", name, value, err)
+				return
+			}
+		}
+		got, want := fmt.Sprintf("%x", bin), hex
+		match, err := matchHexPat(got, want)
+		if err != nil {
+			t.Error(err)
+		}
+		if !match {
+			t.Errorf("%s: Encode(%#v)\n GOT %s\nWANT %s", name, value, got, want)
+		}
+	}
+}
+
+func testXEncodeWithTypeEncoder(t *testing.T, version Version, name string, value interface{}, hexversion, hextype, hexvalue string) {
+	var buf, typebuf bytes.Buffer
+	typeenc := NewVersionedTypeEncoder(version, &typebuf)
+	encoder := NewVersionedXEncoderWithTypeEncoder(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)
+	}
+}