TBR Initial push

Change-Id: I32d6201074d407620b86c15cedde87e186090c6a
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..84e64f6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.jiri
diff --git a/go/src/v.io/mojo/client/client.go b/go/src/v.io/mojo/client/client.go
new file mode 100644
index 0000000..e05fd7b
--- /dev/null
+++ b/go/src/v.io/mojo/client/client.go
@@ -0,0 +1,15 @@
+package v23
+
+import (
+	"mojo/public/go/application"
+	"mojo/public/go/bindings"
+
+	"mojo/public/interfaces/bindings/v23proxy"
+)
+
+func ConnectToRemoteService(ctx application.Context, r application.ServiceRequest, v23Name string) {
+	v23r, v23p := v23proxy.CreateMessagePipeForV23()
+	ctx.ConnectToApplication("mojo:v23proxy").ConnectToService(&v23r)
+	prox := v23proxy.NewV23Proxy(v23p, bindings.GetAsyncWaiter())
+	prox.SetupProxy(v23Name, r.Type(), r.Desc(), r.Name(), r.PassMessagePipe())
+}
diff --git a/go/src/v.io/mojo/proxy/fake_service.go b/go/src/v.io/mojo/proxy/fake_service.go
new file mode 100644
index 0000000..a289776
--- /dev/null
+++ b/go/src/v.io/mojo/proxy/fake_service.go
@@ -0,0 +1,306 @@
+package main
+
+import (
+	"fmt"
+	"log"
+	"strings"
+
+	"v.io/v23/context"
+	"v.io/v23/rpc"
+
+	"mojo/public/go/application"
+	"mojo/public/go/bindings"
+	"mojo/public/go/mojovdl"
+	"mojo/public/go/system"
+
+	"v.io/v23/vdl"
+	"v.io/v23/vdlroot/signature"
+
+	"mojo/public/interfaces/bindings/mojom_types"
+	"mojo/public/interfaces/bindings/service_describer"
+)
+
+// As long as fakeService meets the Invoker interface, it is allowed to pass as
+// a universal v23 service.
+// See the function objectToInvoker in v.io/x/ref/runtime/internal/rpc/server.go
+type fakeService struct {
+	appctx application.Context
+	suffix string
+	router *bindings.Router
+	ids    bindings.Counter
+}
+
+// Prepare is used by the Fake Service to prepare the placeholders for the
+// input data.
+func (fs fakeService) Prepare(ctx *context.T, method string, numArgs int) (argptrs []interface{}, tags []*vdl.Value, _ error) {
+	inargs := make([]*vdl.Value, numArgs)
+	inptrs := make([]interface{}, len(inargs))
+	for i := range inargs {
+		inptrs[i] = &inargs[i]
+	}
+	return inptrs, nil, nil
+}
+
+// Wraps the interface request and the name of the requested mojo service.
+type v23ServiceRequest struct {
+	request bindings.InterfaceRequest
+	name    string
+}
+
+func (v *v23ServiceRequest) Name() string {
+	return v.name
+}
+
+func (v *v23ServiceRequest) Type() mojom_types.MojomInterface {
+	panic("not supported")
+}
+
+func (v *v23ServiceRequest) Desc() map[string]mojom_types.UserDefinedType {
+	panic("not supported")
+}
+
+func (v *v23ServiceRequest) PassMessagePipe() system.MessagePipeHandle {
+	return v.request.PassMessagePipe()
+}
+
+// Invoke calls the mojom service based on the suffix and converts the mojom
+// results (a struct) to Vanadium results (a slice of *vdl.Value).
+// Note: The argptrs from Prepare are reused here. The vom bytes should have
+// been decoded into these argptrs, so there are actual values inside now.
+func (fs fakeService) Invoke(ctx *context.T, call rpc.StreamServerCall, method string, argptrs []interface{}) (results []interface{}, _ error) {
+	// fs.suffix consists of the mojo url and the application/interface name.
+	// The last part should be the name; everything else is the url.
+	parts := strings.Split(fs.suffix, "/")
+	mojourl := strings.Join(parts[:len(parts)-1], "/") // e.g., mojo:go_remote_echo_server. May be defined in a BUILD.gn file.
+	mojoname := parts[len(parts)-1]                    // e.g., mojo::examples::RemoteEcho. Defined from the interface + module.
+
+	// Create the generic message pipe. r is a bindings.InterfaceRequest, and
+	// p is a bindings.InterfacePointer.
+	r, p := bindings.CreateMessagePipeForMojoInterface()
+	v := v23ServiceRequest{
+		request: r,
+		name:    mojoname,
+	} // v is an application.ServiceRequest with mojoname
+
+	// Connect to the mojourl.
+	fs.appctx.ConnectToApplication(mojourl).ConnectToService(&v)
+
+	// Then assign a new router the FakeService.
+	// This will never conflict because each FakeService is only invoked once.
+	fs.router = bindings.NewRouter(p.PassMessagePipe(), bindings.GetAsyncWaiter())
+	defer fs.Close_Proxy()
+
+	log.Printf("Fake Service Invoke (Remote Signature)")
+
+	// Vanadium relies on type information, so we will retrieve that first.
+	mojomInterface, desc, err := fs.callRemoteSignature(mojourl, mojoname)
+	if err != nil {
+		return nil, err
+	}
+
+	log.Printf("Fake Service Invoke Signature %v", mojomInterface)
+	log.Printf("Fake Service Invoke (Remote Method)")
+
+	// With the type information, we can make the method call to the remote interface.
+	methodResults, err := fs.callRemoteMethod(method, mojomInterface, desc, argptrs)
+	if err != nil {
+		return nil, err
+	}
+
+	log.Printf("Fake Service Invoke Results %v", methodResults)
+
+	// Convert methodResult to results.
+	results = make([]interface{}, len(methodResults))
+	for i := range methodResults {
+		results[i] = &methodResults[i]
+	}
+	return results, nil
+}
+
+func (fs fakeService) Close_Proxy() {
+	fs.router.Close()
+}
+
+// callRemoteSignature obtains type and header information from the remote
+// mojo service. Remote mojo interfaces all define a signature method.
+func (fs fakeService) callRemoteSignature(mojourl string, mojoname string) (mojomInterface mojom_types.MojomInterface, desc map[string]mojom_types.UserDefinedType, err error) {
+	/*log.Printf("callRemoteSignature: Prepare payload and header")
+
+	// Prepare the input for the mojo call.
+	// This consists of a payload and a header for the RemoteSignature.
+	payload := mojom_types.SignatureInput{}
+	header := bindings.MessageHeader{
+		Type:      0xffffffff,                          // Signature is always type 0xffffffff
+		Flags:     bindings.MessageExpectsResponseFlag, // It always has a response.
+		RequestId: fs.ids.Count(),
+	}
+
+	log.Printf("callRemoteSignature: Encode payload and header")
+
+	var message *bindings.Message
+	if message, err = bindings.EncodeMessage(header, &payload); err != nil {
+		return response, fmt.Errorf("can't encode request: %v", err.Error())
+	}
+
+	log.Printf("callRemoteSignature => callRemoteGeneric")
+
+	outMessage, err := fs.callRemoteGeneric(message)
+	if err != nil {
+		return response, err
+	}
+
+	log.Printf("callRemoteSignature: Decode response")
+
+	if err = outMessage.DecodePayload(&response); err != nil {
+		return
+	}
+
+	return response, nil*/
+
+	// TODO(afandria): The service_describer mojom file defines the constant, but
+	// it is not actually present in the generated code:
+	// https://github.com/domokit/mojo/issues/469
+	// serviceDescriberInterfaceName := "_ServiceDescriber"
+
+	r, p := service_describer.CreateMessagePipeForServiceDescriber()
+	fs.appctx.ConnectToApplication(mojourl).ConnectToService(&r)
+	sDescriber := service_describer.NewServiceDescriberProxy(p, bindings.GetAsyncWaiter())
+	defer sDescriber.Close_Proxy()
+
+	r2, p2 := service_describer.CreateMessagePipeForServiceDescription()
+	err = sDescriber.DescribeService(mojoname, r2)
+	if err != nil {
+		return
+	}
+	sDescription := service_describer.NewServiceDescriptionProxy(p2, bindings.GetAsyncWaiter())
+	defer sDescription.Close_Proxy()
+
+	mojomInterface, err = sDescription.GetTopLevelInterface()
+	if err != nil {
+		return
+	}
+	descPtr, err := sDescription.GetAllTypeDefinitions()
+	if err != nil {
+		return
+	}
+	return mojomInterface, *descPtr, nil
+}
+
+// A helper function that sends a remote message that expects a response.
+func (fs fakeService) callRemoteGeneric(message *bindings.Message) (outMessage *bindings.Message, err error) {
+	log.Printf("callRemoteGeneric: Send message along the router")
+
+	readResult := <-fs.router.AcceptWithResponse(message)
+	if err = readResult.Error; err != nil {
+		return
+	}
+
+	log.Printf("callRemoteGeneric: Audit response message header flag")
+	// The message flag we receive back must be a bindings.MessageIsResponseFlag
+	if readResult.Message.Header.Flags != bindings.MessageIsResponseFlag {
+		err = &bindings.ValidationError{bindings.MessageHeaderInvalidFlags,
+			fmt.Sprintf("invalid message header flag: %v", readResult.Message.Header.Flags),
+		}
+		return
+	}
+
+	log.Printf("callRemoteGeneric: Audit response message header type")
+	// While the mojo service we called into will return a header whose
+	// type must match our outgoing one.
+	if got, want := readResult.Message.Header.Type, message.Header.Type; got != want {
+		err = &bindings.ValidationError{bindings.MessageHeaderUnknownMethod,
+			fmt.Sprintf("invalid method in response: expected %v, got %v", want, got),
+		}
+		return
+	}
+
+	return readResult.Message, nil
+}
+
+// callRemoteMethod calls the method remotely in a generic way.
+// Produces []*vdl.Value at the end for the invoker to return.
+func (fs fakeService) callRemoteMethod(method string, mi mojom_types.MojomInterface, desc map[string]mojom_types.UserDefinedType, argptrs []interface{}) ([]*vdl.Value, error) {
+	// We need to parse the signature result to get the method relevant info out.
+	found := false
+	var ordinal uint32
+	for ord, mm := range mi.Methods {
+		if *mm.DeclData.ShortName == method {
+			ordinal = ord
+			found = true
+			break
+		}
+	}
+
+	if !found {
+		return nil, fmt.Errorf("callRemoteMethod: method %s does not exist", method)
+	}
+
+	mm := mi.Methods[ordinal]
+
+	// A void function must have request id of 0, whereas one with response params
+	// should  have a unique request id.
+	var rqId uint64
+	var flag uint32
+	if mm.ResponseParams != nil {
+		rqId = fs.ids.Count()
+		flag = bindings.MessageExpectsResponseFlag
+	} else {
+		flag = bindings.MessageNoFlag
+	}
+
+	header := bindings.MessageHeader{
+		Type:      ordinal,
+		Flags:     flag,
+		RequestId: rqId,
+	}
+
+	// Now produce the *bindings.Message that we will send to the other side.
+	inType := mojovdl.MojomStructToVDLType(mm.Parameters, desc)
+	message, err := encodeMessageFromVom(header, argptrs, inType)
+	if err != nil {
+		return nil, err
+	}
+
+	// Handle the 0 out-arg case first.
+	if mm.ResponseParams == nil {
+		if err = fs.router.Accept(message); err != nil {
+			return nil, err
+		}
+		return make([]*vdl.Value, 0), nil
+	}
+
+	// Otherwise, make a generic call with the message.
+	outMessage, err := fs.callRemoteGeneric(message)
+	if err != nil {
+		return nil, err
+	}
+
+	// Decode the *vdl.Value from the mojom bytes and mojom type.
+	outType := mojovdl.MojomStructToVDLType(*mm.ResponseParams, desc)
+	outVdlValue, err := mojovdl.DecodeValue(outMessage.Payload, outType)
+	if err != nil {
+		return nil, fmt.Errorf("mojovdl.DecodeValue failed: %v", err)
+	}
+
+	// Then split the *vdl.Value (struct) into []*vdl.Value
+	response := splitVdlValueByMojomType(outVdlValue, outType)
+	return response, nil
+}
+
+// The fake service has no signature.
+func (fs fakeService) Signature(ctx *context.T, call rpc.ServerCall) ([]signature.Interface, error) {
+	log.Printf("Fake Service Signature???")
+	return nil, nil
+}
+
+// The fake service knows nothing about method signatures.
+func (fs fakeService) MethodSignature(ctx *context.T, call rpc.ServerCall, method string) (signature.Method, error) {
+	log.Printf("Fake Service Method Signature???")
+	return signature.Method{}, nil
+}
+
+// The fake service will never need to glob.
+func (fs fakeService) Globber() *rpc.GlobState {
+	log.Printf("Fake Service Globber???")
+	return nil
+}
diff --git a/go/src/v.io/mojo/proxy/misc.go b/go/src/v.io/mojo/proxy/misc.go
new file mode 100644
index 0000000..d156b7f
--- /dev/null
+++ b/go/src/v.io/mojo/proxy/misc.go
@@ -0,0 +1,66 @@
+package main
+
+// Construct the proper *vdl.Value (as a struct) from the mojom type.
+import (
+	"fmt"
+
+	"mojo/public/go/bindings"
+	"mojo/public/go/mojovdl"
+
+	"v.io/v23/vdl"
+)
+
+// TODO(alexfandrianto): Since this function could panic, we should consider
+// handling that if it happens.
+func combineVdlValueByMojomType(values []*vdl.Value, t *vdl.Type) *vdl.Value {
+	outVdlValue := vdl.ZeroValue(t)
+	for i := 0; i < t.NumField(); i++ {
+		outVdlValue.StructField(i).Assign(values[i])
+	}
+	return outVdlValue
+}
+
+// Construct []*vdl.Value from a *vdl.Value (as a struct) via its mojom type.
+// TODO(alexfandrianto): Since this function could panic, we should consider
+// handling that if it happens.
+func splitVdlValueByMojomType(value *vdl.Value, t *vdl.Type) []*vdl.Value {
+	outVdlValues := make([]*vdl.Value, t.NumField())
+	for i := 0; i < t.NumField(); i++ {
+		outVdlValues[i] = value.StructField(i)
+	}
+	return outVdlValues
+}
+
+func encodeMessageFromVom(header bindings.MessageHeader, argptrs []interface{}, t *vdl.Type) (*bindings.Message, error) {
+	// Convert argptrs into their true form: []*vdl.Value
+	inargs := make([]*vdl.Value, len(argptrs))
+	for i := range argptrs {
+		inargs[i] = *argptrs[i].(**vdl.Value)
+	}
+
+	// Construct the proper *vdl.Value (as a struct) from the mojom type.
+	vdlValue := combineVdlValueByMojomType(inargs, t)
+
+	encoder := bindings.NewEncoder()
+	if err := header.Encode(encoder); err != nil {
+		return nil, err
+	}
+	if bytes, handles, err := encoder.Data(); err != nil {
+		return nil, err
+	} else {
+		// Encode here.
+		moreBytes, err := mojovdl.Encode(vdlValue)
+		if err != nil {
+			return nil, fmt.Errorf("mojovdl.Encode failed: %v", err)
+		}
+		// Append the encoded "payload" to the end of the slice.
+		bytes = append(bytes, moreBytes...)
+
+		return &bindings.Message{
+			Header:  header,
+			Bytes:   bytes,
+			Handles: handles,
+			Payload: moreBytes,
+		}, nil
+	}
+}
diff --git a/go/src/v.io/mojo/proxy/proxy.go b/go/src/v.io/mojo/proxy/proxy.go
new file mode 100644
index 0000000..26a9f64
--- /dev/null
+++ b/go/src/v.io/mojo/proxy/proxy.go
@@ -0,0 +1,269 @@
+package main
+
+import (
+	"flag"
+	"fmt"
+	"log"
+
+	"v.io/v23"
+	"v.io/v23/context"
+	"v.io/v23/options"
+	"v.io/v23/security"
+	"v.io/v23/vdl"
+
+	"mojo/public/go/application"
+	"mojo/public/go/bindings"
+	"mojo/public/go/mojovdl"
+	"mojo/public/go/system"
+	"mojo/public/interfaces/bindings/mojom_types"
+	"mojo/public/interfaces/bindings/v23proxy"
+
+	_ "v.io/x/ref/runtime/factories/static"
+)
+
+//#include "mojo/public/c/system/types.h"
+import "C"
+
+func init() {
+	flag.String("child-connection-id", "", "")
+	flag.String("mojo-platform-channel-handle", "", "")
+}
+
+type v23HeaderReceiver struct {
+	delegate    *V23ServerDelegate
+	v23Name     string
+	ifaceSig    mojom_types.MojomInterface
+	desc        map[string]mojom_types.UserDefinedType
+	serviceName string
+	handle      system.MessagePipeHandle
+}
+
+func (r *v23HeaderReceiver) SetupProxy(v23Name string, ifaceSig mojom_types.MojomInterface, desc map[string]mojom_types.UserDefinedType, serviceName string, handle system.MessagePipeHandle) (err error) {
+	log.Printf("[server] In SetupProxy(%s, %v, %v, %s, %v)\n", v23Name, ifaceSig, desc, serviceName, handle)
+	r.v23Name = v23Name
+	r.ifaceSig = ifaceSig
+	r.desc = desc
+	r.serviceName = serviceName
+	r.handle = handle
+
+	go func() {
+		connector := bindings.NewConnector(r.handle, bindings.GetAsyncWaiter())
+
+		// Read generic calls in a loop
+		stub := &genericStub{
+			header:    r,
+			ctx:       r.delegate.ctx,
+			connector: connector,
+		}
+		bindingStub := bindings.NewStub(connector, stub)
+		for {
+			if err := bindingStub.ServeRequest(); err != nil {
+				connectionError, ok := err.(*bindings.ConnectionError)
+				if !ok || !connectionError.Closed() {
+					log.Println(err)
+				}
+				break
+			}
+		}
+		r.delegate.stubs = append(r.delegate.stubs, bindingStub)
+	}()
+	return nil
+}
+
+type byteCopyingPayload []byte
+
+func (bcp byteCopyingPayload) Encode(encoder *bindings.Encoder) error {
+	encoder.WriteRawBytes(bcp)
+	return nil
+}
+
+func (bcp byteCopyingPayload) Decode(decoder *bindings.Decoder) error {
+	panic("not supported")
+}
+
+type genericStub struct {
+	header    *v23HeaderReceiver
+	ctx       *context.T
+	connector *bindings.Connector
+}
+
+func (s *genericStub) Accept(message *bindings.Message) (err error) {
+	/*if int(message.Header.Type) >= len(s.header.ifaceSig.Methods) {
+		return fmt.Errorf("Method had index %d, but interface only has %d methods",
+			message.Header.Type, len(s.header.ifaceSig.Methods))
+	}*/
+	if _, ok := s.header.ifaceSig.Methods[message.Header.Type]; !ok {
+		return fmt.Errorf("Method had index %d, but interface only has %d methods",
+			message.Header.Type, len(s.header.ifaceSig.Methods))
+	}
+
+	methodSig := s.header.ifaceSig.Methods[message.Header.Type]
+	methodName := *methodSig.DeclData.ShortName
+	// Should we perform validation of flags like generated methods?
+	// Does this handle 0-arg methods?
+
+	messageBytes := message.Payload
+
+	response, err := s.Call(s.header.v23Name, methodName, messageBytes, methodSig.Parameters, methodSig.ResponseParams)
+	if err != nil {
+		return err
+	}
+	responseHeader := bindings.MessageHeader{
+		Type:      message.Header.Type,
+		Flags:     bindings.MessageIsResponseFlag,
+		RequestId: message.Header.RequestId,
+	}
+	responseMessage, err := bindings.EncodeMessage(responseHeader, byteCopyingPayload(response))
+	if err != nil {
+		return err
+	}
+	return s.connector.WriteMessage(responseMessage)
+}
+
+func (s *genericStub) Call(name, method string, value []byte, inParamsType mojom_types.MojomStruct, outParamsType *mojom_types.MojomStruct) ([]byte, error) {
+	log.Printf("server: %s.%s: %#v", name, method, inParamsType)
+
+	inVType := mojovdl.MojomStructToVDLType(inParamsType, s.header.desc)
+	var outVType *vdl.Type
+	if outParamsType != nil {
+		outVType = mojovdl.MojomStructToVDLType(*outParamsType, s.header.desc)
+	}
+
+	// Decode the vdl.Value from the mojom bytes and mojom type.
+	inVdlValue, err := mojovdl.DecodeValue(value, inVType)
+	if err != nil {
+		return nil, fmt.Errorf("mojovdl.DecodeValue failed: %v", err)
+	}
+
+	// inVdlValue is a struct, but we need to send []interface.
+	inargs := splitVdlValueByMojomType(inVdlValue, inVType)
+	inargsIfc := make([]interface{}, len(inargs))
+	for i := range inargs {
+		inargsIfc[i] = inargs[i]
+	}
+
+	// We know that the v23proxy (on the other side) will give us back a bunch of
+	// data in []interface{}. so we'll want to decode them into *vdl.Value.
+	log.Printf("%s %v\n", method, outParamsType)
+	outargs := make([]*vdl.Value, len(outParamsType.Fields))
+	outptrs := make([]interface{}, len(outargs))
+	for i := range outargs {
+		outptrs[i] = &outargs[i]
+	}
+
+	// Now, run the call without any authorization.
+	if err := v23.GetClient(s.ctx).Call(s.ctx, name, method, inargsIfc, outptrs, options.SkipServerEndpointAuthorization{}); err != nil {
+		return nil, err
+	}
+
+	// Now convert the []interface{} into a *vdl.Value (struct).
+	outVdlValue := combineVdlValueByMojomType(outargs, outVType)
+
+	// Finally, encode this *vdl.Value (struct) into mojom bytes and send the response.
+	result, err := mojovdl.Encode(outVdlValue)
+	if err != nil {
+		return nil, fmt.Errorf("mojovdl.Encode failed: %v", err)
+	}
+	return result, nil
+}
+
+type V23ServerDelegate struct {
+	ctx      *context.T
+	stubs    []*bindings.Stub
+	shutdown v23.Shutdown
+}
+
+func (delegate *V23ServerDelegate) Initialize(context application.Context) {
+	log.Printf("V23ServerDelegate.Initialize...")
+
+	// Start up v23 whenever a v23proxy is begun.
+	// This is done regardless of whether we are initializing this v23proxy for use
+	// as a client or as a server.
+	ctx, shutdown := v23.Init()
+	delegate.ctx = ctx
+	delegate.shutdown = shutdown
+
+	// TODO(alexfandrianto): Does Mojo stop us from creating too many v23proxy?
+	// Is it 1 per shell? Ideally, each device will only serve 1 of these v23proxy,
+	// but it is not problematic to have extra.
+	/*s := MakeServer(ctx)
+	err := s.ServeDispatcher("", &V23ProxyDispatcher{
+		appctx: context,
+	})*/
+	_, s, err := v23.WithNewDispatchingServer(ctx, "", &V23ProxyDispatcher{
+		appctx: context,
+	})
+	if err != nil {
+		log.Panic("Error serving service: ", err)
+	}
+
+	endpoints := s.Status().Endpoints
+	fmt.Printf("Listening at: /%v\n", endpoints[0])
+}
+
+/*func MakeServer(ctx *context.T) rpc.Server {
+	s, err := v23.NewServer(ctx)
+	if err != nil {
+		log.Panic("Failure creating server: ", err)
+	}
+
+	endpoints, err := s.Listen(v23.GetListenSpec(ctx))
+	if err != nil {
+		log.Panic("Error listening to service: ", err)
+	}
+	fmt.Printf("Listening at: /%v\n", endpoints[0])
+	return s
+}*/
+
+type V23ProxyDispatcher struct {
+	appctx application.Context
+}
+
+func (v23pd *V23ProxyDispatcher) Lookup(ctx *context.T, suffix string) (interface{}, security.Authorizer, error) {
+	log.Printf("Dispatcher: %s", suffix)
+	return fakeService{
+		appctx: v23pd.appctx,
+		suffix: suffix,
+		ids:    bindings.NewCounter(),
+	}, security.AllowEveryone(), nil
+}
+
+func (delegate *V23ServerDelegate) Create(request v23proxy.V23_Request) {
+	headerReceiver := &v23HeaderReceiver{delegate: delegate}
+	v23Stub := v23proxy.NewV23Stub(request, headerReceiver, bindings.GetAsyncWaiter())
+	delegate.stubs = append(delegate.stubs, v23Stub)
+
+	go func() {
+		// Read header message
+		if err := v23Stub.ServeRequest(); err != nil {
+			connectionError, ok := err.(*bindings.ConnectionError)
+			if !ok || !connectionError.Closed() {
+				log.Println(err)
+			}
+			return
+		}
+	}()
+}
+
+func (delegate *V23ServerDelegate) AcceptConnection(connection *application.Connection) {
+	log.Printf("V23ServerDelegate.AcceptConnection...")
+	connection.ProvideServices(&v23proxy.V23_ServiceFactory{delegate})
+}
+
+func (delegate *V23ServerDelegate) Quit() {
+	log.Printf("V23ServerDelegate.Quit...")
+	for _, stub := range delegate.stubs {
+		stub.Close()
+	}
+
+	delegate.shutdown()
+}
+
+//export MojoMain
+func MojoMain(handle C.MojoHandle) C.MojoResult {
+	application.Run(&V23ServerDelegate{}, system.MojoHandle(handle))
+	return C.MOJO_RESULT_OK
+}
+
+func main() {
+}
diff --git a/go/src/v.io/mojo/transcoder/allocation_size.go b/go/src/v.io/mojo/transcoder/allocation_size.go
new file mode 100644
index 0000000..ff70e88
--- /dev/null
+++ b/go/src/v.io/mojo/transcoder/allocation_size.go
@@ -0,0 +1,37 @@
+package mojovdl
+
+import "v.io/v23/vdl"
+
+func neededStructAllocationSize(vt *vdl.Type) uint32 {
+	var totalBits uint32
+	for fi := 0; fi < vt.NumField(); fi++ {
+		field := vt.Field(fi)
+		totalBits += baseTypeSizeBits(field.Type)
+	}
+	return roundBitsTo64Alignment(totalBits)
+}
+
+func baseTypeSizeBits(vt *vdl.Type) uint32 {
+	switch vt.Kind() {
+	case vdl.Bool:
+		return 1
+	case vdl.Byte:
+		return 8
+	case vdl.Uint16, vdl.Int16:
+		return 16
+	case vdl.Uint32, vdl.Int32, vdl.Float32, vdl.Enum:
+		return 32
+	case vdl.Union:
+		return 128 // Header + value / pointer to inner union
+	default: // Either Uint64, Int64, Float64 or pointer.
+		return 64
+	}
+}
+
+// Round up to the nearest 8 byte length.
+func roundBitsTo64Alignment(numBits uint32) uint32 {
+	if numBits%64 == 0 {
+		return numBits / 8
+	}
+	return (numBits + (64 - numBits%64)) / 8
+}
diff --git a/go/src/v.io/mojo/transcoder/allocator.go b/go/src/v.io/mojo/transcoder/allocator.go
new file mode 100644
index 0000000..0f3be60
--- /dev/null
+++ b/go/src/v.io/mojo/transcoder/allocator.go
@@ -0,0 +1,75 @@
+package mojovdl
+
+import "encoding/binary"
+
+const HEADER_SIZE uint32 = 8
+
+// TODO(bprosnitz) maybe make an interface to support decode too
+type allocator struct {
+	// Buffer containing encoded data.
+	buf []byte
+
+	// Index of the first unclaimed byte in buf.
+	end uint32
+}
+
+func (a *allocator) makeRoom(size uint32) {
+	totalNeeded := a.end + size
+
+	allocationSize := uint32(1)
+	for allocationSize < totalNeeded {
+		allocationSize *= 2
+	}
+
+	if allocationSize != uint32(len(a.buf)) {
+		oldBuf := a.buf
+		a.buf = make([]byte, allocationSize)
+		copy(a.buf, oldBuf)
+	}
+}
+
+func (a *allocator) allocateBlock(size uint32, numElems uint32) (startIndex, endIndex uint32) {
+	size_with_header := size + HEADER_SIZE
+	size_with_header_rounded := size_with_header
+	if size_with_header%8 != 0 {
+		size_with_header_rounded = size_with_header + (8 - (size_with_header % 8))
+	}
+
+	a.makeRoom(size_with_header_rounded)
+	binary.LittleEndian.PutUint32(a.buf[a.end:a.end+4], size_with_header)
+	binary.LittleEndian.PutUint32(a.buf[a.end+4:a.end+8], numElems)
+
+	prevEnd := a.end
+	start := prevEnd + HEADER_SIZE
+	end := prevEnd + size_with_header
+	a.end = prevEnd + size_with_header_rounded
+	return start, end
+}
+
+func (a *allocator) Allocate(size uint32, numElems uint32) bytesRef {
+	begin, end := a.allocateBlock(size, numElems)
+	ref := bytesRef{
+		allocator:  a,
+		startIndex: begin,
+		endIndex:   end,
+		// zeros
+	}
+	return ref
+}
+
+func (a *allocator) AllocationFromPointer(absoluteIndex uint32) bytesRef {
+	headerPos := absoluteIndex - HEADER_SIZE
+	size := binary.LittleEndian.Uint32(a.buf[headerPos : headerPos+4])
+	return bytesRef{
+		allocator:  a,
+		startIndex: absoluteIndex,
+		endIndex:   absoluteIndex + size,
+	}
+}
+
+func (a *allocator) AllocatedBytes() []byte {
+	if a.buf == nil {
+		return []byte{}
+	}
+	return a.buf[:a.end]
+}
diff --git a/go/src/v.io/mojo/transcoder/decode.go b/go/src/v.io/mojo/transcoder/decode.go
new file mode 100644
index 0000000..b5b7142
--- /dev/null
+++ b/go/src/v.io/mojo/transcoder/decode.go
@@ -0,0 +1,370 @@
+package mojovdl
+
+import (
+	"fmt"
+	"reflect"
+
+	"mojo/public/go/bindings"
+
+	"v.io/v23/vdl"
+)
+
+// Decode decodes the mojom-encoded data into valptr, which must be a pointer to
+// the desired value.  The datatype describes the type of the encoded data.
+// Returns an error if the data cannot be decoded into valptr, based on the VDL
+// value conversion rules.
+func Decode(data []byte, datatype *vdl.Type, valptr interface{}) error {
+	target, err := vdl.ReflectTarget(reflect.ValueOf(valptr))
+	if err != nil {
+		return err
+	}
+	d := &decoder{dec: bindings.NewDecoder(data, nil)}
+	return d.decodeValue(datatype, target, true, false)
+}
+
+// DecodeValue is like Decode, but decodes mojom-encoded data into a vdl.Value.
+func DecodeValue(data []byte, datatype *vdl.Type) (*vdl.Value, error) {
+	v := new(vdl.Value)
+	if err := Decode(data, datatype, &v); err != nil {
+		return nil, err
+	}
+	return v, nil
+}
+
+type decoder struct {
+	dec       *bindings.Decoder
+	typeStack []*vdl.Type
+}
+
+func (d *decoder) decodeValue(vt *vdl.Type, target vdl.Target, isTopType, isNullable bool) error {
+	switch vt.Kind() {
+	case vdl.Bool:
+		value, err := d.dec.ReadBool()
+		if err != nil {
+			return err
+		}
+		return target.FromBool(value, vt)
+	case vdl.Int16:
+		value, err := d.dec.ReadInt16()
+		if err != nil {
+			return err
+		}
+		return target.FromInt(int64(value), vt)
+	case vdl.Int32:
+		value, err := d.dec.ReadInt32()
+		if err != nil {
+			return err
+		}
+		return target.FromInt(int64(value), vt)
+	case vdl.Int64:
+		value, err := d.dec.ReadInt64()
+		if err != nil {
+			return err
+		}
+		return target.FromInt(value, vt)
+	case vdl.Byte:
+		value, err := d.dec.ReadUint8()
+		if err != nil {
+			return err
+		}
+		return target.FromUint(uint64(value), vt)
+	case vdl.Uint16:
+		value, err := d.dec.ReadUint16()
+		if err != nil {
+			return err
+		}
+		return target.FromUint(uint64(value), vt)
+	case vdl.Uint32:
+		value, err := d.dec.ReadUint32()
+		if err != nil {
+			return err
+		}
+		return target.FromUint(uint64(value), vt)
+	case vdl.Uint64:
+		value, err := d.dec.ReadUint64()
+		if err != nil {
+			return err
+		}
+		return target.FromUint(value, vt)
+	case vdl.Float32:
+		value, err := d.dec.ReadFloat32()
+		if err != nil {
+			return err
+		}
+		return target.FromFloat(float64(value), vt)
+	case vdl.Float64:
+		value, err := d.dec.ReadFloat64()
+		if err != nil {
+			return err
+		}
+		return target.FromFloat(value, vt)
+	case vdl.String:
+		switch ptr, err := d.dec.ReadPointer(); {
+		case err != nil:
+			return err
+		case ptr == 0:
+			return fmt.Errorf("invalid null string pointer")
+		default:
+			value, err := d.dec.ReadString()
+			if err != nil {
+				return err
+			}
+			return target.FromString(value, vt)
+		}
+		return nil
+	case vdl.Enum:
+		index, err := d.dec.ReadInt32()
+		if err != nil {
+			return err
+		}
+		if int(index) >= vt.NumEnumLabel() || index < 0 {
+			return fmt.Errorf("enum label out of range")
+		}
+		target.FromEnumLabel(vt.EnumLabel(int(index)), vt)
+		return nil
+	case vdl.Complex64:
+		panic("unimplemented")
+	case vdl.Complex128:
+		panic("unimplemented")
+	case vdl.Array, vdl.List:
+		switch ptr, err := d.dec.ReadPointer(); {
+		case err != nil:
+			return err
+		case ptr == 0 && isNullable:
+			return target.FromNil(vdl.OptionalType(vt))
+		case ptr == 0 && !isNullable:
+			return fmt.Errorf("invalid null struct pointer")
+		}
+
+		if vt.IsBytes() {
+			str, err := d.dec.ReadString()
+			if err != nil {
+				return err
+			}
+			return target.FromBytes([]byte(str), vt)
+		} else {
+			elemBitSize := baseTypeSizeBits(vt.Elem())
+			numElems, err := d.dec.StartArray(elemBitSize)
+			if err != nil {
+				return err
+			}
+			listTarget, err := target.StartList(vt, int(numElems))
+			if err != nil {
+				return err
+			}
+			for i := 0; i < int(numElems); i++ {
+				elemTarget, err := listTarget.StartElem(i)
+				if err != nil {
+					return err
+				}
+				if err := d.decodeValue(vt.Elem(), elemTarget, false, false); err != nil {
+					return err
+				}
+				if err := listTarget.FinishElem(elemTarget); err != nil {
+					return err
+				}
+			}
+			if err := target.FinishList(listTarget); err != nil {
+				return err
+			}
+		}
+		return d.dec.Finish()
+	case vdl.Set:
+		panic("unimplemented")
+		/*switch ptr, err := d.dec.ReadPointer(); {
+		case err != nil:
+			return err
+		case ptr == 0 && isNullable:
+			return target.FromNil(vdl.OptionalType(vt))
+		case ptr == 0 && !isNullable:
+			return fmt.Errorf("invalid null struct pointer")
+		}
+		keyBitSize := baseTypeSizeBits(vt.Key())
+		numKeys, err := d.dec.StartArray(keyBitSize)
+		if err != nil {
+			return err
+		}
+		setTarget, err := target.StartSet(vt, int(numKeys))
+		if err != nil {
+			return err
+		}
+		for i := 0; i < int(numKeys); i++ {
+			keyTarget, err := setTarget.StartKey()
+			if err != nil {
+				return err
+			}
+			if err := d.decodeValue(mt.Key, keyTarget, false, false); err != nil {
+				return err
+			}
+			if err := setTarget.FinishKey(keyTarget); err != nil {
+				return err
+			}
+		}
+		if err := target.FinishSet(setTarget); err != nil {
+			return err
+		}
+		return d.dec.Finish()*/
+	case vdl.Map:
+		switch ptr, err := d.dec.ReadPointer(); {
+		case err != nil:
+			return err
+		case ptr == 0 && isNullable:
+			return target.FromNil(vdl.OptionalType(vt))
+		case ptr == 0 && !isNullable:
+			return fmt.Errorf("invalid null struct pointer")
+		}
+		if err := d.dec.StartMap(); err != nil {
+			return err
+		}
+		var keys, values []*vdl.Value
+		keysTarget, err := vdl.ReflectTarget(reflect.ValueOf(&keys))
+		if err != nil {
+			return err
+		}
+		keysListType := vdl.ListType(vt.Key())
+		if err := d.decodeValue(keysListType, keysTarget, false, false); err != nil {
+			return err
+		}
+		valuesTarget, err := vdl.ReflectTarget(reflect.ValueOf(&values))
+		if err != nil {
+			return err
+		}
+		valuesListType := vdl.ListType(vt.Elem())
+		if err := d.decodeValue(valuesListType, valuesTarget, false, false); err != nil {
+			return err
+		}
+
+		if len(keys) != len(values) {
+			return fmt.Errorf("values don't match keys")
+		}
+		mapTarget, err := target.StartMap(vt, len(keys))
+		if err != nil {
+			return err
+		}
+		for i, key := range keys {
+			value := values[i]
+
+			keyTarget, err := mapTarget.StartKey()
+			if err != nil {
+				return err
+			}
+			if err := vdl.FromValue(keyTarget, key); err != nil {
+				return err
+			}
+			fieldTarget, err := mapTarget.FinishKeyStartField(keyTarget)
+			if err != nil {
+				return err
+			}
+			if err := vdl.FromValue(fieldTarget, value); err != nil {
+				return err
+			}
+			if err := mapTarget.FinishField(keyTarget, fieldTarget); err != nil {
+				return err
+			}
+		}
+		if err := target.FinishMap(mapTarget); err != nil {
+			return err
+		}
+
+		return d.dec.Finish()
+	case vdl.Struct:
+		// TODO(toddw): See the comment in encoder.mojomStructSize; we rely on the
+		// fields to be presented in the canonical mojom field ordering.
+		if !isTopType {
+			switch ptr, err := d.dec.ReadPointer(); {
+			case err != nil:
+				return err
+			case ptr == 0 && isNullable:
+				return target.FromNil(vdl.OptionalType(vt))
+			case ptr == 0 && !isNullable:
+				return fmt.Errorf("invalid null struct pointer")
+			}
+		}
+		_, err := d.dec.StartStruct()
+		if err != nil {
+			return err
+		}
+		targetFields, err := target.StartFields(vt)
+		if err != nil {
+			return err
+		}
+		for i := 0; i < vt.NumField(); i++ {
+			mfield := vt.Field(i)
+			switch vkey, vfield, err := targetFields.StartField(mfield.Name); {
+			// TODO(toddw): Handle err == vdl.ErrFieldNoExist case?
+			case err != nil:
+				return err
+			default:
+				if err := d.decodeValue(mfield.Type, vfield, false, false); err != nil {
+					return err
+				}
+				if err := targetFields.FinishField(vkey, vfield); err != nil {
+					return err
+				}
+			}
+		}
+		// TODO(toddw): Fill in fields that weren't decoded with their zero value.
+		if err := target.FinishFields(targetFields); err != nil {
+			return err
+		}
+		return d.dec.Finish()
+	case vdl.Union:
+		size, tag, err := d.dec.ReadUnionHeader()
+		if err != nil {
+			return err
+		}
+		if size == 0 {
+			d.dec.SkipUnionValue()
+			return target.FromNil(vdl.OptionalType(vt))
+		}
+		if int(tag) >= vt.NumField() {
+			return fmt.Errorf("union tag out of bounds")
+		}
+		fld := vt.Field(int(tag))
+		targetFields, err := target.StartFields(vt)
+		if err != nil {
+			return err
+		}
+		vKey, vField, err := targetFields.StartField(fld.Name)
+		if err != nil {
+			return err
+		}
+		if fld.Type.Kind() == vdl.Union {
+			switch ptr, err := d.dec.ReadPointer(); {
+			case err != nil:
+				return err
+			case ptr == 0 && isNullable:
+				return target.FromNil(vdl.OptionalType(fld.Type))
+			case ptr == 0 && !isNullable:
+				return fmt.Errorf("invalid null union pointer")
+			}
+			if err := d.dec.StartNestedUnion(); err != nil {
+				return err
+			}
+		}
+		if err := d.decodeValue(fld.Type, vField, false, false); err != nil {
+			return err
+		}
+		if fld.Type.Kind() == vdl.Union {
+			if err := d.dec.Finish(); err != nil {
+				return err
+			}
+		}
+		if err := targetFields.FinishField(vKey, vField); err != nil {
+			return err
+		}
+		if err := target.FinishFields(targetFields); err != nil {
+			return err
+		}
+		d.dec.FinishReadingUnionValue()
+		return nil
+	case vdl.Optional:
+		return d.decodeValue(vt.Elem(), target, false, true)
+	case vdl.Any:
+		panic("unimplemented")
+	//case vdl.TypeObject:
+	//	panic("unimplemented")
+	default:
+		panic(fmt.Errorf("decodeValue unhandled vdl type: %v", vt))
+	}
+}
diff --git a/go/src/v.io/mojo/transcoder/encode.go b/go/src/v.io/mojo/transcoder/encode.go
new file mode 100644
index 0000000..b778e0e
--- /dev/null
+++ b/go/src/v.io/mojo/transcoder/encode.go
@@ -0,0 +1,94 @@
+package mojovdl
+
+import (
+	"reflect"
+
+	"v.io/v23/vdl"
+)
+
+func Encode(value interface{}) ([]byte, error) {
+	enc := &encoder{
+		allocator: &allocator{},
+	}
+	err := vdl.FromReflect(enc, reflect.ValueOf(value))
+	return enc.Bytes(), err
+}
+
+type encoder struct {
+	allocator *allocator
+}
+
+func (e *encoder) Bytes() []byte {
+	return e.allocator.AllocatedBytes()
+}
+
+func (e *encoder) FromBool(src bool, tt *vdl.Type) error {
+	panic("cannot encode top level bool")
+}
+func (e *encoder) FromUint(src uint64, tt *vdl.Type) error {
+	panic("cannot encode top level uint")
+}
+func (e *encoder) FromInt(src int64, tt *vdl.Type) error {
+	panic("cannot encode top level int")
+}
+func (e *encoder) FromFloat(src float64, tt *vdl.Type) error {
+	panic("cannot encode top level float")
+}
+func (e *encoder) FromComplex(src complex128, tt *vdl.Type) error {
+	panic("cannot encode top level complex")
+}
+func (e *encoder) FromBytes(src []byte, tt *vdl.Type) error {
+	panic("cannot encode top level bytes")
+}
+func (e *encoder) FromString(src string, tt *vdl.Type) error {
+	panic("cannot encode top level string")
+}
+func (e *encoder) FromEnumLabel(src string, tt *vdl.Type) error {
+	panic("cannot encode top level enum")
+}
+func (e *encoder) FromTypeObject(src *vdl.Type) error {
+	panic("cannot encode top level type object")
+}
+func (e *encoder) FromNil(tt *vdl.Type) error {
+	panic("cannot encode top level nil")
+}
+
+func (e *encoder) StartList(tt *vdl.Type, len int) (vdl.ListTarget, error) {
+	panic("UNIMPLEMENTED")
+	return nil, nil
+}
+func (e *encoder) FinishList(x vdl.ListTarget) error {
+	return nil
+}
+func (e *encoder) StartSet(tt *vdl.Type, len int) (vdl.SetTarget, error) {
+	panic("UNIMPLEMENTED")
+}
+func (e *encoder) FinishSet(x vdl.SetTarget) error {
+	panic("UNIMPLEMENTED")
+
+}
+func (e *encoder) StartMap(tt *vdl.Type, len int) (vdl.MapTarget, error) {
+	panic("UNIMPLEMENTED")
+
+}
+func (e *encoder) FinishMap(x vdl.MapTarget) error {
+	panic("UNIMPLEMENTED")
+
+}
+func (e *encoder) StartFields(tt *vdl.Type) (vdl.FieldsTarget, error) {
+	if tt.Kind() == vdl.Union {
+		panic("not yet supported")
+	}
+	if tt.Kind() == vdl.Optional {
+		tt = tt.Elem()
+	}
+	block := e.allocator.Allocate(neededStructAllocationSize(tt), 0)
+	return fieldsTarget{
+			vdlType: tt,
+			block:   block,
+		},
+		nil
+}
+func (e *encoder) FinishFields(x vdl.FieldsTarget) error {
+	return nil
+}
diff --git a/go/src/v.io/mojo/transcoder/ref.go b/go/src/v.io/mojo/transcoder/ref.go
new file mode 100644
index 0000000..9d53c75
--- /dev/null
+++ b/go/src/v.io/mojo/transcoder/ref.go
@@ -0,0 +1,35 @@
+package mojovdl
+
+type bytesRef struct {
+	allocator            *allocator
+	startIndex, endIndex uint32
+}
+
+func (b bytesRef) Slice(low, high uint32) bytesRef {
+	return bytesRef{
+		allocator:  b.allocator,
+		startIndex: b.startIndex + low,
+		endIndex:   b.startIndex + high,
+	}
+}
+
+// SignedSlice allows going backwards in the slice (temporary hack to include header in slice for unions)
+func (b bytesRef) SignedSlice(low, high int) bytesRef {
+	return bytesRef{
+		allocator:  b.allocator,
+		startIndex: uint32(int(b.startIndex) + low),
+		endIndex:   uint32(int(b.startIndex) + high),
+	}
+}
+
+func (b bytesRef) Bytes() []byte {
+	return b.allocator.buf[b.startIndex:b.endIndex]
+}
+
+func (b bytesRef) AsPointer(fromRefPos bytesRef) uint32 {
+	offset := b.startIndex - fromRefPos.startIndex
+	if offset <= 0 {
+		panic("invalid non-positive offset for pointer")
+	}
+	return offset - HEADER_SIZE
+}
diff --git a/go/src/v.io/mojo/transcoder/struct_offset.go b/go/src/v.io/mojo/transcoder/struct_offset.go
new file mode 100644
index 0000000..317a45b
--- /dev/null
+++ b/go/src/v.io/mojo/transcoder/struct_offset.go
@@ -0,0 +1,204 @@
+package mojovdl
+
+import (
+	"fmt"
+
+	"v.io/v23/vdl"
+)
+
+func offsetInStruct(index int, structVdlType *vdl.Type) (byteOffset uint32, bitOffset uint8) {
+	if index >= structVdlType.NumField() {
+		panic(fmt.Sprintf("index %v out of bounds for type %v", index, structVdlType))
+	}
+
+	offsetComputation := &structOffsetComputation{}
+	for i := 0; i < index; i++ {
+		bits := baseTypeSizeBits(structVdlType.Field(i).Type)
+		switch bits {
+		case 1:
+			offsetComputation.next1()
+		case 8:
+			offsetComputation.next8()
+		case 16:
+			offsetComputation.next16()
+		case 32:
+			offsetComputation.next32()
+		case 64:
+			offsetComputation.next64()
+		case 128:
+			offsetComputation.next64()
+			offsetComputation.next64()
+		default:
+			panic("unknown bit size")
+		}
+	}
+
+	switch baseTypeSizeBits(structVdlType.Field(index).Type) {
+	case 1:
+		return offsetComputation.index1, offsetComputation.bitOffset1
+	case 8:
+		return offsetComputation.index8, 0
+	case 16:
+		return offsetComputation.index16, 0
+	case 32:
+		return offsetComputation.index32, 0
+	case 64, 128:
+		return offsetComputation.index64, 0
+
+	default:
+		panic("unknown bit size")
+	}
+}
+
+type structOffsetComputation struct {
+	index8, index16, index32, index64 uint32
+	index1                            uint32
+	bitOffset1                        uint8
+}
+
+func (sa *structOffsetComputation) next1() {
+	newBitOffset1 := (sa.bitOffset1 + 1) % 8
+	var nextIndex uint32
+	if sa.index1 != sa.index8 {
+		nextIndex = sa.index8
+	} else {
+		nextIndex = sa.index1 + 1
+	}
+	if sa.bitOffset1 == 0 {
+		// bit offset == 0 means fetch a new byte
+		if sa.index8 == sa.index1 {
+			sa.index8 = nextIndex
+		}
+		if sa.index16 == sa.index1 {
+			if nextIndex&0x1 == 0 {
+				sa.index16 = nextIndex
+			} else {
+				sa.index16 = nextIndex + 1
+			}
+		}
+		if sa.index32 == sa.index1 {
+			if nextIndex&0x3 == 0 {
+				sa.index32 = nextIndex
+			} else {
+				sa.index32 = nextIndex + (4 - (nextIndex & 0x3))
+			}
+		}
+		if sa.index64 == sa.index1 {
+			if nextIndex&0x7 == 0 {
+				sa.index64 = nextIndex
+			} else {
+				sa.index64 = nextIndex + (8 - (nextIndex & 0x7))
+			}
+		}
+	}
+
+	if sa.bitOffset1 == 7 {
+		sa.index1 = nextIndex
+	}
+	sa.bitOffset1 = newBitOffset1
+}
+func (sa *structOffsetComputation) next8() {
+	var newIndex8 uint32
+	if sa.index8 != sa.index16 {
+		newIndex8 = sa.index16
+	} else {
+		newIndex8 = sa.index8 + 1
+	}
+
+	if sa.index1 == sa.index8 && sa.bitOffset1 == 0 {
+		sa.index1 = newIndex8
+	}
+	if sa.index16 == sa.index8 {
+		if newIndex8&0x1 == 0 {
+			sa.index16 = newIndex8
+		} else {
+			sa.index16 = newIndex8 + 1
+		}
+	}
+	if sa.index32 == sa.index8 {
+		if newIndex8&0x3 == 0 {
+			sa.index32 = newIndex8
+		} else {
+			sa.index32 = newIndex8 + (4 - (newIndex8 & 0x3))
+		}
+	}
+	if sa.index64 == sa.index8 {
+		if newIndex8&0x7 == 0 {
+			sa.index64 = newIndex8
+		} else {
+			sa.index64 = newIndex8 + (8 - (newIndex8 & 0x7))
+		}
+	}
+	sa.index8 = newIndex8
+}
+func (sa *structOffsetComputation) next16() {
+	var newIndex16 uint32
+	if sa.index16 != sa.index32 {
+		newIndex16 = sa.index32
+	} else {
+		newIndex16 = sa.index16 + 2
+	}
+	if sa.index1 == sa.index16 && sa.bitOffset1 == 0 {
+		sa.index1 = newIndex16
+	}
+	if sa.index8 == sa.index16 {
+		sa.index8 = newIndex16
+	}
+	if sa.index32 == sa.index16 {
+		if newIndex16&0x3 == 0 {
+			sa.index32 = newIndex16
+		} else {
+			sa.index32 = newIndex16 + (4 - (newIndex16 & 0x3))
+		}
+	}
+	if sa.index64 == sa.index16 {
+		if newIndex16&0x7 == 0 {
+			sa.index64 = newIndex16
+		} else {
+			sa.index64 = newIndex16 + (8 - (newIndex16 & 0x7))
+		}
+	}
+	sa.index16 = newIndex16
+}
+func (sa *structOffsetComputation) next32() {
+	var newIndex32 uint32
+	if sa.index32 != sa.index64 {
+		newIndex32 = sa.index64
+	} else {
+		newIndex32 = sa.index32 + 4
+	}
+	if sa.index1 == sa.index32 && sa.bitOffset1 == 0 {
+		sa.index1 = newIndex32
+	}
+	if sa.index8 == sa.index32 {
+		sa.index8 = newIndex32
+	}
+	if sa.index16 == sa.index32 {
+		sa.index16 = newIndex32
+	}
+	if sa.index64 == sa.index32 {
+		if newIndex32&0x7 == 0 {
+			sa.index64 = newIndex32
+		} else {
+			sa.index64 = newIndex32 + (8 - (newIndex32 & 0x7))
+		}
+	}
+	sa.index32 = newIndex32
+}
+func (sa *structOffsetComputation) next64() {
+	newIndex64 := sa.index64 + 8
+
+	if sa.index1 == sa.index64 && sa.bitOffset1 == 0 {
+		sa.index1 = newIndex64
+	}
+	if sa.index8 == sa.index64 {
+		sa.index8 = newIndex64
+	}
+	if sa.index16 == sa.index64 {
+		sa.index16 = newIndex64
+	}
+	if sa.index32 == sa.index64 {
+		sa.index32 = newIndex64
+	}
+	sa.index64 = newIndex64
+}
diff --git a/go/src/v.io/mojo/transcoder/target.go b/go/src/v.io/mojo/transcoder/target.go
new file mode 100644
index 0000000..cfb26f5
--- /dev/null
+++ b/go/src/v.io/mojo/transcoder/target.go
@@ -0,0 +1,213 @@
+package mojovdl
+
+import (
+	"encoding/binary"
+	"fmt"
+	"math"
+
+	"v.io/v23/vdl"
+)
+
+type target struct {
+	currentBitOffset uint8
+	current          bytesRef
+}
+
+func (t target) allocator() *allocator {
+	return t.current.allocator
+}
+
+func (t target) FromBool(src bool, tt *vdl.Type) error {
+	if src {
+		t.current.Bytes()[0] |= 1 << t.currentBitOffset
+	}
+	// shouldn't have to do anything for false
+	return nil
+}
+func (t target) FromUint(src uint64, tt *vdl.Type) error {
+	switch tt.Kind() {
+	case vdl.Byte:
+		t.current.Bytes()[0] = byte(src)
+	case vdl.Uint16:
+		binary.LittleEndian.PutUint16(t.current.Bytes(), uint16(src))
+	case vdl.Uint32:
+		binary.LittleEndian.PutUint32(t.current.Bytes(), uint32(src))
+	case vdl.Uint64:
+		binary.LittleEndian.PutUint64(t.current.Bytes(), src)
+	default:
+		return fmt.Errorf("invalid FromUint(%v, %v)", src, tt)
+	}
+	return nil
+}
+func (t target) FromInt(src int64, tt *vdl.Type) error {
+	switch tt.Kind() {
+	case vdl.Int16:
+		binary.LittleEndian.PutUint16(t.current.Bytes(), uint16(src))
+	case vdl.Int32:
+		binary.LittleEndian.PutUint32(t.current.Bytes(), uint32(src))
+	case vdl.Int64:
+		binary.LittleEndian.PutUint64(t.current.Bytes(), uint64(src))
+	default:
+		return fmt.Errorf("invalid FromInt(%v, %v)", src, tt)
+	}
+	return nil
+}
+func (t target) FromFloat(src float64, tt *vdl.Type) error {
+	switch tt.Kind() {
+	case vdl.Float32:
+		binary.LittleEndian.PutUint32(t.current.Bytes(), math.Float32bits(float32(src)))
+	case vdl.Float64:
+		binary.LittleEndian.PutUint64(t.current.Bytes(), math.Float64bits(src))
+	default:
+		return fmt.Errorf("invalid FromFloat(%v, %v)", src, tt)
+	}
+	return nil
+}
+func (t target) FromComplex(src complex128, tt *vdl.Type) error {
+	panic("UNIMPLEMENTED")
+}
+func (t target) writeBytes(src []byte) {
+	block := t.allocator().Allocate(uint32(len(src)), uint32(len(src)))
+	t.writePointer(block)
+	copy(block.Bytes(), src)
+}
+func (t target) FromBytes(src []byte, tt *vdl.Type) error {
+	t.writeBytes(src)
+	return nil
+}
+func (t target) FromString(src string, tt *vdl.Type) error {
+	t.writeBytes([]byte(src))
+	return nil
+}
+func (t target) FromEnumLabel(src string, tt *vdl.Type) error {
+	// enums in mojo are treated as an int32 on the wire (but have gaps in their values).
+	// This implementation assumes that we will use generated VDL values and not have gaps.
+	index := tt.EnumIndex(src)
+	binary.LittleEndian.PutUint32(t.current.Bytes(), uint32(index))
+	return nil
+}
+func (t target) FromTypeObject(src *vdl.Type) error {
+	panic("UNIMPLEMENTED")
+
+}
+func (t target) FromNil(tt *vdl.Type) error {
+	switch tt.Kind() {
+	case vdl.Optional:
+		elemType := tt.Elem()
+		switch elemType.Kind() {
+		case vdl.Union, vdl.Struct: // Array? String? Bytes? List? Set?
+			// Note: for union, this zeros 16 bytes, but for others it does just 8.
+			zeroBytes(t.current.Bytes())
+		default:
+			panic(fmt.Sprintf("Vdl type %v cannot be optional", tt))
+		}
+	case vdl.Any:
+		panic("Any rep not yet determined")
+	default:
+		panic("Type cannot be nil")
+	}
+	return nil
+}
+func zeroBytes(dat []byte) {
+	copy(dat, make([]byte, len(dat)))
+}
+
+func (t target) StartList(tt *vdl.Type, len int) (vdl.ListTarget, error) {
+	if tt.Kind() == vdl.Optional {
+		tt = tt.Elem()
+	}
+	bitsNeeded := baseTypeSizeBits(tt.Elem()) * uint32(len)
+	block := t.allocator().Allocate((bitsNeeded+7)/8, uint32(len))
+	t.writePointer(block)
+	if tt.Elem().Kind() == vdl.Bool {
+		return &bitListTarget{
+			block: block,
+		}, nil
+	} else {
+		return &listTarget{
+			incrementSize: baseTypeSizeBits(tt.Elem()) / 8,
+			block:         block,
+		}, nil
+	}
+}
+func (t target) FinishList(x vdl.ListTarget) error {
+	return nil
+}
+
+// TODO(bprosnitz) This uses list, should we use map instead?
+func (t target) StartSet(tt *vdl.Type, len int) (vdl.SetTarget, error) {
+	if tt.Kind() == vdl.Optional {
+		tt = tt.Elem()
+	}
+	bitsNeeded := baseTypeSizeBits(tt.Key()) * uint32(len)
+	block := t.allocator().Allocate((bitsNeeded+7)/8, uint32(len))
+	t.writePointer(block)
+	if tt.Key().Kind() == vdl.Bool {
+		return &bitListTarget{
+			block: block,
+		}, nil
+	} else {
+		return &listTarget{
+			incrementSize: baseTypeSizeBits(tt.Key()) / 8,
+			block:         block,
+		}, nil
+	}
+}
+func (t target) FinishSet(x vdl.SetTarget) error {
+	return nil
+}
+func (t target) StartMap(tt *vdl.Type, len int) (vdl.MapTarget, error) {
+	if tt.Kind() == vdl.Optional {
+		tt = tt.Elem()
+	}
+	pointerBlock := t.allocator().Allocate(16, 0)
+	t.writePointer(pointerBlock)
+
+	st := target{
+		current: pointerBlock.Slice(0, 8),
+	}
+	setTarget, err := st.StartSet(vdl.SetType(tt.Key()), len)
+	if err != nil {
+		return nil, err
+	}
+	lt := target{
+		current: pointerBlock.Slice(8, 16),
+	}
+	listTarget, err := lt.StartList(vdl.ListType(tt.Elem()), len)
+	if err != nil {
+		return nil, err
+	}
+	return &mapTarget{
+		setTarget:  setTarget,
+		listTarget: listTarget,
+	}, nil
+}
+func (t target) FinishMap(x vdl.MapTarget) error {
+	return nil
+}
+func (t target) StartFields(tt *vdl.Type) (vdl.FieldsTarget, error) {
+	if tt.Kind() == vdl.Optional {
+		tt = tt.Elem()
+	}
+	if tt.Kind() == vdl.Union {
+		return unionFieldsTarget{
+			vdlType: tt,
+			block:   t.current,
+		}, nil
+	}
+	block := t.allocator().Allocate(neededStructAllocationSize(tt), 0)
+	t.writePointer(block)
+	return fieldsTarget{
+			vdlType: tt,
+			block:   block,
+		},
+		nil
+}
+func (t target) FinishFields(x vdl.FieldsTarget) error {
+	return nil
+}
+
+func (t target) writePointer(alloc bytesRef) {
+	offset := alloc.AsPointer(t.current)
+	binary.LittleEndian.PutUint64(t.current.Bytes(), uint64(offset))
+}
diff --git a/go/src/v.io/mojo/transcoder/type.go b/go/src/v.io/mojo/transcoder/type.go
new file mode 100644
index 0000000..3fc7c35
--- /dev/null
+++ b/go/src/v.io/mojo/transcoder/type.go
@@ -0,0 +1,265 @@
+package mojovdl
+
+import (
+	"fmt"
+
+	"mojo/public/interfaces/bindings/mojom_types"
+
+	"v.io/v23/vdl"
+)
+
+/*// Given a descriptor mapping, produce 2 maps.
+// The former maps from mojom identifiers to VDL Type.
+// The latter maps from VDL Type string (hash cons) to the mojom identifier.
+// These maps are used to interconvert more easily.
+func AnalyzeMojomDescriptors(mp map[string]mojom_types.UserDefinedType) map[string]*vdl.Type {
+	m2V := make(map[string]*vdl.Type)
+	for s, udt := range mp {
+		m2V[s] = mojomToVDLTypeUDT(udt, mp)
+	}
+	return m2V
+}*/
+
+// Convert the known type reference to a vdl type.
+// Panics if the type reference was not known.
+/*func TypeReferenceToVDLType(tr mojom_types.TypeReference, mp map[string]mojom_types.UserDefinedType) *vdl.Type {
+	if udt, ok := mp[tr.TypeKey]; ok {
+		return mojomToVDLTypeUDT(udt, mp)
+	}
+	panic("Type Key %s was not present in the mapping", tr.typeKey)
+}*/
+
+func mojomToVDLTypeUDT(udt mojom_types.UserDefinedType, mp map[string]mojom_types.UserDefinedType) (vt *vdl.Type) {
+	u := interface{}(udt)
+	switch u := u.(type) { // To do the type switch, udt has to be converted to interface{}.
+	case *mojom_types.UserDefinedTypeEnumType: // enum
+		me := u.Value
+
+		// TODO: Assumes that the maximum enum index is len(me.Values) - 1.
+		labels := make([]string, len(me.Values))
+		for _, ev := range me.Values { // per EnumValue...
+			// EnumValue contains a ConstantOccurrence
+			// ConstantOccurrence contains a ConstantValue
+			// ConstantValue is a union that contains an EnumConstantValue
+			ecv := ev.Value.Value.(*mojom_types.ConstantValueEnumValue).Value
+
+			// EnumConstantValue contains the EnumValueName and IntValue
+			labels[int(ecv.IntValue)] = *ecv.EnumValueName
+		}
+
+		vt = vdl.NamedType(*me.DeclData.ShortName, vdl.EnumType(labels...))
+	case *mojom_types.UserDefinedTypeStructType: // struct
+		ms := u.Value
+
+		vt = MojomStructToVDLType(ms, mp)
+	case *mojom_types.UserDefinedTypeUnionType: // union
+		mu := u.Value
+
+		vfields := make([]vdl.Field, len(mu.Fields))
+		for ix, mfield := range mu.Fields {
+			vfields[ix] = vdl.Field{
+				Name: *mfield.DeclData.ShortName,
+				Type: MojomToVDLType(mfield.Type, mp),
+			}
+		}
+		vt = vdl.NamedType(*mu.DeclData.ShortName, vdl.UnionType(vfields...))
+	case *mojom_types.UserDefinedTypeInterfaceType: // interface
+		panic("interfaces don't exist in vdl")
+	default: // unknown
+		panic(fmt.Errorf("user defined type %#v with unknown tag %d", udt, udt.Tag()))
+	}
+	return vt
+}
+
+func MojomStructToVDLType(ms mojom_types.MojomStruct, mp map[string]mojom_types.UserDefinedType) (vt *vdl.Type) {
+	vfields := make([]vdl.Field, len(ms.Fields))
+	for ix, mfield := range ms.Fields {
+		vfields[ix] = vdl.Field{
+			Name: *mfield.DeclData.ShortName,
+			Type: MojomToVDLType(mfield.FieldType, mp),
+		}
+	}
+	vt = vdl.NamedType(*ms.DeclData.ShortName, vdl.StructType(vfields...))
+	return vt
+}
+
+// Given a mojom Type and the descriptor mapping, produce the corresponding vdltype.
+func MojomToVDLType(mojomtype mojom_types.Type, mp map[string]mojom_types.UserDefinedType) (vt *vdl.Type) {
+	// TODO(alexfandrianto): Cyclic types?
+	mt := interface{}(mojomtype)
+	switch mt := interface{}(mt).(type) { // To do the type switch, mt has to be converted to interface{}.
+	case *mojom_types.TypeSimpleType: // TypeSimpleType
+		switch mt.Value {
+		case mojom_types.SimpleType_Bool:
+			vt = vdl.BoolType
+		case mojom_types.SimpleType_Double:
+			vt = vdl.BoolType
+		case mojom_types.SimpleType_Float:
+			vt = vdl.BoolType
+		case mojom_types.SimpleType_InT8:
+			panic("int8 doesn't exist in vdl")
+		case mojom_types.SimpleType_InT16:
+			vt = vdl.Int16Type
+		case mojom_types.SimpleType_InT32:
+			vt = vdl.Int32Type
+		case mojom_types.SimpleType_InT64:
+			vt = vdl.Int64Type
+		case mojom_types.SimpleType_UinT8:
+			vt = vdl.ByteType
+		case mojom_types.SimpleType_UinT16:
+			vt = vdl.Uint16Type
+		case mojom_types.SimpleType_UinT32:
+			vt = vdl.Uint32Type
+		case mojom_types.SimpleType_UinT64:
+			vt = vdl.Uint64Type
+		}
+	case *mojom_types.TypeStringType: // TypeStringType
+		st := mt.Value
+		if st.Nullable {
+			panic("nullable strings don't exist in vdl")
+		}
+		vt = vdl.StringType
+	case *mojom_types.TypeArrayType: // TypeArrayType
+		at := mt.Value
+		if at.Nullable {
+			panic("nullable arrays don't exist in vdl")
+		}
+		if at.FixedLength > 0 {
+			vt = vdl.ArrayType(int(at.FixedLength), MojomToVDLType(at.ElementType, mp))
+		} else {
+			vt = vdl.ListType(MojomToVDLType(at.ElementType, mp))
+		}
+	case *mojom_types.TypeMapType: // TypeMapType
+		// Note that mojom doesn't have sets.
+		m := mt.Value
+		if m.Nullable {
+			panic("nullable maps don't exist in vdl")
+		}
+		vt = vdl.MapType(MojomToVDLType(m.KeyType, mp), MojomToVDLType(m.ValueType, mp))
+	case *mojom_types.TypeHandleType: // TypeHandleType
+		panic("handles don't exist in vdl")
+	case *mojom_types.TypeTypeReference: // TypeTypeReference
+		tr := mt.Value
+		if tr.IsInterfaceRequest {
+			panic("interface requests don't exist in vdl")
+		}
+		udt := mp[*tr.TypeKey]
+		if udt.Tag() != 1 && tr.Nullable {
+			panic("nullable non-struct type reference cannot be represented in vdl")
+		}
+		vt = mojomToVDLTypeUDT(udt, mp)
+	default:
+		panic(fmt.Errorf("%#v has unknown tag %d", mojomtype, mojomtype.Tag()))
+	}
+
+	return vt
+}
+
+/*func V2M(vt *vdl.Type, v2M map[string]string) mojom_types.Type {
+	if m, ok := v2M[vt.String()]; ok {
+		return mojom_types.TypeTypeReference{
+			Value: mojom_types.TypeReference{
+				Nullable:   nullable,
+				Identifier: m,
+				TypeKey:    m,
+			},
+		}
+	}
+	panic("vdl type %#v was not present in the mapping", vt)
+}
+
+// From the vdltype and the reverse mapping of the descriptor (hashcons vdltype string => typekey),
+// produce the corresponding mojom Type.
+func VDLToMojomType(vt *vdl.Type, v2M map[string]string) mojom_types.Type {
+	return vdlToMojomTypeImpl(vt, v2M, false)
+}
+
+func vdlToMojomTypeImpl(vt *vdl.Type, v2M map[string]string, bool nullable) mojom_types.Type {
+	if m, ok := v2M[vt.String()]; ok {
+		return mojom_types.TypeTypeReference{
+			Value: mojom_types.TypeReference{
+				Nullable:   nullable,
+				Identifier: m,
+				TypeKey:    m,
+			},
+		}
+	}
+
+	fmt.Println("Missed the vdl to mojom map")
+	// In the unlikely case where v2M was insufficient, we have the remaining logic.
+
+	switch vt.Kind() {
+	case vdl.Bool:
+		return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_Bool}
+	case vdl.Byte:
+		return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_UinT8}
+	case vdl.Uint16:
+		return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_UinT16}
+	case vdl.Uint32:
+		return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_UinT32}
+	case vdl.Uint64:
+		return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_UinT64}
+	case vdl.Int16:
+		return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_InT16}
+	case vdl.Int32:
+		return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_InT32}
+	case vdl.Int64:
+		return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_InT64}
+	case vdl.Float32:
+		return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_Float}
+	case vdl.Float64:
+		return mojom_types.TypeSimpleType{Value: mojom_types.SimpleType_Double}
+	case vdl.Complex64:
+		panic("complex float doesn't exist in mojom")
+	case vdl.Complex128:
+		panic("complex double doesn't exist in mojom")
+	case vdl.String:
+		return mojom_types.TypeStringType{Value: mojom_types.StringType{}}
+	case vdl.Array:
+		elemType := VDLToMojomType(vt.Elem(), v2M)
+		return mojom_types.TypeArrayType{
+			Value: mojom_types.ArrayType{
+				FixedLength: int64(vt.Len()),
+				ElementType: elemType,
+			},
+		}
+	case vdl.List:
+		elemType := VDLToMojomType(vt.Elem(), v2M)
+		return mojom_types.TypeArrayType{
+			Value: mojom_types.ArrayType{
+				FixedLength: -1,
+				ElementType: elemType,
+			},
+		}
+	case vdl.Set:
+		panic("set doesn't exist in mojom")
+	case vdl.Map:
+		keyType := VDLToMojomType(vt.Key(), v2M)
+		elemType := VDLToMojomType(vt.Elem(), v2M)
+		return mojom_types.TypeMapType{
+			Value: mojom_types.MapType{
+				KeyType:   &keyType,
+				ValueType: &elemType,
+			},
+		}
+	case vdl.Struct, vdl.Union, vdl.Enum:
+		mt := mojom_types.TypeTypeReference{
+			Value: mojom_types.TypeReference{
+				Nullable:   nullable,
+				Identifier: v2M[vt.String()],
+				TypeKey:    v2M[vt.String()],
+			},
+		}
+		return mt
+	case vdl.TypeObject:
+		panic("typeobject doesn't exist in mojom")
+	case vdl.Any:
+		panic("any doesn't exist in mojom")
+	case vdl.Optional:
+		// TODO(alexfandrianto): Unfortunately, without changing vdl, we can only
+		// manage optional (named) structs. This doesn't Nullify anything else.
+		return vdlToMojomTypeImpl(vt.Elem(), v2M, true)
+	}
+	panic(fmt.Errorf("%v can't be converted to MojomType", vt))
+}
+*/
diff --git a/go/src/v.io/mojo/transcoder/typed_targets.go b/go/src/v.io/mojo/transcoder/typed_targets.go
new file mode 100644
index 0000000..d09160e
--- /dev/null
+++ b/go/src/v.io/mojo/transcoder/typed_targets.go
@@ -0,0 +1,123 @@
+package mojovdl
+
+import (
+	"encoding/binary"
+
+	"v.io/v23/vdl"
+)
+
+// for struct
+type fieldsTarget struct {
+	vdlType *vdl.Type
+	block   bytesRef
+}
+
+func (fe fieldsTarget) StartField(name string) (key, field vdl.Target, _ error) {
+	fieldType, fieldIndex := fe.vdlType.FieldByName(name)
+	byteOffset, bitOffset := offsetInStruct(fieldIndex, fe.vdlType)
+	numBits := baseTypeSizeBits(fieldType.Type)
+	refSize := (numBits + 7) / 8
+	newRef := fe.block.Slice(byteOffset, byteOffset+refSize)
+	return nil, target{
+		currentBitOffset: bitOffset,
+		current:          newRef,
+	}, nil
+}
+func (fieldsTarget) FinishField(key, field vdl.Target) error {
+	return nil
+}
+
+type unionFieldsTarget struct {
+	vdlType *vdl.Type
+	block   bytesRef
+}
+
+func (ufe unionFieldsTarget) StartField(name string) (key, field vdl.Target, _ error) {
+	fld, index := ufe.vdlType.FieldByName(name)
+	binary.LittleEndian.PutUint32(ufe.block.Bytes(), 16)
+	binary.LittleEndian.PutUint32(ufe.block.Bytes()[4:], uint32(index))
+
+	valueSlice := ufe.block.Slice(8, 16)
+	if fld.Type.Kind() == vdl.Union {
+		// nested union, create a pointer to the body
+		nestedUnionBlock := ufe.block.allocator.Allocate(8, 0)
+		offset := nestedUnionBlock.AsPointer(valueSlice)
+		binary.LittleEndian.PutUint64(valueSlice.Bytes(), uint64(offset))
+		return nil, target{
+			currentBitOffset: 0,
+			current:          nestedUnionBlock.SignedSlice(-8, 8),
+		}, nil
+	}
+	return nil, target{
+		currentBitOffset: 0,
+		current:          valueSlice,
+	}, nil
+}
+func (unionFieldsTarget) FinishField(key, field vdl.Target) error {
+	return nil
+}
+
+// doubles as set target
+type listTarget struct {
+	incrementSize uint32
+	block         bytesRef
+	nextPosition  uint32
+}
+
+func (lt *listTarget) StartElem(index int) (elem vdl.Target, _ error) {
+	// TODO(bprosnitz) Index is ignored -- we should probably remove this from Target.
+	sliceBlock := lt.block.Slice(lt.nextPosition, lt.nextPosition+lt.incrementSize)
+	lt.nextPosition += lt.incrementSize
+	return target{
+		current: sliceBlock,
+	}, nil
+}
+func (lt *listTarget) StartKey() (key vdl.Target, _ error) {
+	return lt.StartElem(0)
+}
+func (listTarget) FinishElem(elem vdl.Target) error {
+	return nil
+}
+func (listTarget) FinishKey(key vdl.Target) error {
+	return nil
+}
+
+type bitListTarget struct {
+	block           bytesRef
+	nextBitPosition uint32
+}
+
+func (blt *bitListTarget) StartElem(index int) (elem vdl.Target, _ error) {
+	bitPos := blt.nextBitPosition
+	blt.nextBitPosition++
+	byteIndex := bitPos / 8
+	sliceBlock := blt.block.Slice(byteIndex, byteIndex+1)
+	return target{
+		currentBitOffset: uint8(bitPos % 8),
+		current:          sliceBlock,
+	}, nil
+}
+func (blt *bitListTarget) StartKey() (key vdl.Target, _ error) {
+	return blt.StartElem(0)
+}
+func (bitListTarget) FinishElem(elem vdl.Target) error {
+	return nil
+}
+func (bitListTarget) FinishKey(key vdl.Target) error {
+	return nil
+}
+
+type mapTarget struct {
+	listTarget vdl.ListTarget
+	setTarget  vdl.SetTarget
+}
+
+func (mt *mapTarget) StartKey() (key vdl.Target, _ error) {
+	return mt.setTarget.StartKey()
+}
+func (mt *mapTarget) FinishKeyStartField(key vdl.Target) (field vdl.Target, _ error) {
+	return mt.listTarget.StartElem(0)
+}
+func (mapTarget) FinishField(key, field vdl.Target) error {
+	return nil
+}