Go support for protocol buffers.

Consists of a compiler plugin and the support library, all written in Go.

This is a complete implementation except for:
  - Extensions in the plugin
    - coming soon
    - support is already in the library
  - Services (RPC)
    - needs an external definition to honor before supporting.
  - Insertion points in the plugin
    - may come

R=rsc, dsymonds1, ken2
CC=golang-dev
http://codereview.appspot.com/676041
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
new file mode 100644
index 0000000..c4a2e3c
--- /dev/null
+++ b/CONTRIBUTORS
@@ -0,0 +1,11 @@
+# This is a list of contributors to the Go protobuf repository.
+
+# Names should be added to this file like so:
+#     Name <email address>
+
+# Please keep the list sorted.
+
+
+David Symonds <dsymonds@golang.org>
+Ken Thompson <ken@golang.org>
+Rob Pike <r@golang.org>
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..ae3664f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,31 @@
+Go support for Protocol Buffers - Google's data interchange format
+
+Copyright 2010 Google Inc.  All rights reserved.
+http://code.google.com/p/goprotobuf/
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+    * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/Make.protobuf b/Make.protobuf
new file mode 100644
index 0000000..d307aa0
--- /dev/null
+++ b/Make.protobuf
@@ -0,0 +1,46 @@
+# Go support for Protocol Buffers - Google's data interchange format
+#
+# Copyright 2010 Google Inc.  All rights reserved.
+# http://code.google.com/p/goprotobuf/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# Includable Makefile to add a rule for generating .pb.go files from .proto files
+# (Google protocol buffer descriptions).
+# Typical use if myproto.proto is a file in package mypackage in this directory:
+#
+#	include $(GOROOT)/src/Make.$(GOARCH)
+#	TARG=mypackage
+#	GOFILES=\
+#		myproto.pb.go
+#
+#	include $(GOROOT)/src/Make.pkg
+#	include $(GOROOT)/src/pkg/goprotobuf.googlecode.com/hg/Make.proto
+
+%.pb.go:	%.proto
+	protoc --go_out=. $<
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..5a1e6c2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,53 @@
+# Go support for Protocol Buffers - Google's data interchange format
+#
+# Copyright 2010 Google Inc.  All rights reserved.
+# http://code.google.com/p/goprotobuf/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+include $(GOROOT)/src/Make.$(GOARCH)
+
+all:	install
+
+install:
+	cd proto && make install
+	cd compiler && make install
+
+clean:
+	cd proto && make clean
+	cd compiler && make clean
+	cd compiler/testdata && make clean
+	cd compiler/descriptor && make clean
+	cd compiler/plugin && make clean
+
+nuke:
+	cd proto && make nuke
+	cd compiler && make nuke
+	cd compiler/testdata && make nuke
+	cd compiler/descriptor && make nuke
+	cd compiler/plugin && make nuke
diff --git a/README b/README
new file mode 100644
index 0000000..9507c19
--- /dev/null
+++ b/README
@@ -0,0 +1,160 @@
+Go support for Protocol Buffers - Google's data interchange format
+Copyright 2010 Google Inc.
+http://code.google.com/p/goprotobuf/
+
+This software implements Go bindings for protocol buffers.  For
+information about protocol buffers themselves, see
+	http://code.google.com/apis/protocolbuffers/
+To use this software, you must first install the standard C++
+implementation of protocol buffers from
+	http://code.google.com/p/protobuf/
+And of course you must also install the Go compiler and tools from
+	http://code.google.com/p/go/
+See
+	http://golang.org/doc/install.html
+for details or, if you are using gccgo, follow the instructions at
+	http://golang.org/doc/gccgo_install.html
+
+This software has two parts: a 'protocol compiler plugin' that
+generates Go source files that, once compiled, can access and manage
+protocol buffers; and a library that implements run-time support for
+encoding (marshaling), decoding (unmarshaling), and accessing protocol
+buffers.
+
+There is no support for RPC in Go using protocol buffers.  It may come
+once a standard RPC protocol develops for protobufs.
+
+Extensions are not supported by the plugin in this release, although
+they are in the library.  The work will be completed soon.
+
+There are no insertion points in the plugin.
+
+To install this code:
+
+The simplest way is to run goinstall.
+
+	# Grab the code from the repository and install the proto package.
+	goinstall goprotobuf.googlecode.com/hg/proto
+
+	# Compile and install the compiler plugin
+	cd $GOROOT/src/pkg/goprotobuf.googlecode.com/hg/compiler
+	make install
+
+The compiler plugin, protoc-gen-go, will be installed in $GOBIN,
+defaulting to $HOME/bin.  It must be in your $PATH for the protocol
+compiler, protoc, to find it.
+
+Once the software is installed, there are two steps to using it.
+First you must compile the protocol buffer definitions and then import
+them, with the support library, into your program.
+
+To compile the protocol buffer definition, write a Makefile in the
+style shown in the commentin the file Make.protobuf.  If your Makefile
+includes Make.protobuf, the rest should follow automatically.  The
+generated code can be compiled separately or as part of a normal Go
+package.
+
+The generated files will be suffixed .pb.go.  See the Test code below
+for an example using such a file.
+
+
+
+The package comment for the proto library contains text describing
+the interface provided in Go for protocol buffers. Here is an edited
+version.
+
+==========
+
+The proto package converts data structures to and from the
+wire format of protocol buffers.  It works in concert with the
+Go source code generated for .proto files by the protocol compiler.
+
+A summary of the properties of the protocol buffer interface
+for a protocol buffer variable v:
+
+  - Names are turned from camel_case to CamelCase for export.
+  - There are no methods on v to set and get fields; just treat
+  	them as structure fields.
+  - The zero value for a struct is its correct initialization state.
+	All desired fields must be set before marshaling.
+  - A Reset() method will restore a protobuf struct to its zero state.
+  - Each type T has a method NewT() to create a new instance. It
+	is equivalent to new(T).
+  - Non-repeated fields are pointers to the values; nil means unset.
+	That is, optional or required field int32 f becomes F *int32.
+  - Repeated fields are slices.
+  - Helper functions are available to simplify the getting and setting of fields:
+  	foo.String = proto.String("hello") // set field
+  	s := proto.GetString(foo.String)  // get field
+  - Constants are defined to hold the default values of all fields that
+	have them.  They have the form Default_StructName_FieldName.
+  - Enums are given type names and maps between names to values,
+  	plus a helper function to create values.  Enum values are prefixed
+  	with the enum's type name.
+  - Nested groups and enums have type names prefixed with the name of
+  	the surrounding message type.
+  - Marshal and Unmarshal are functions to encode and decode the wire format.
+
+Consider file test.proto, containing
+
+	package example;
+	
+	enum FOO { X = 17; };
+	
+	message Test {
+	  required string label = 1;
+	  optional int32 type = 2 [default=77];
+	  repeated int64 reps = 3;
+	  optional group OptionalGroup = 4 {
+	    required string RequiredField = 5;
+	  };
+	}
+
+To build a package from test.proto and some other Go files, write a
+Makefile like this:
+
+	include $(GOROOT)/src/Make.$(GOARCH)
+
+	TARG=path/to/example
+	GOFILES=\
+		test.pb.go\
+		other.go
+
+	include $(GOROOT)/src/Make.pkg
+	include $(GOROOT)/src/pkg/goprotobuf.googlecode.com/hg/Make.protobuf
+
+
+To create and play with a Test object from the example package,
+
+	package main
+
+	import (
+		"log"
+
+		"goprotobuf.googlecode.com/hg/proto"
+		"path/to/example"
+	)
+
+	func main() {
+		test := &example.Test {
+			Label: proto.String("hello"),
+			Type: proto.Int32(17),
+			Optionalgroup: &example.Test_OptionalGroup {
+				RequiredField: proto.String("good bye"),
+			},
+		}
+		data, err := proto.Marshal(test)
+		if err != nil {
+			log.Exit("marshaling error:", err)
+		}
+		newTest := example.NewTest()
+		err = proto.Unmarshal(data, newTest)
+		if err != nil {
+			log.Exit("unmarshaling error:", err)
+		}
+		// Now test and newTest contain the same data.
+		if proto.GetString(test.Label) != proto.GetString(newTest.Label) {
+			log.Exit("data mismatch %q %q", proto.GetString(test.Label), proto.GetString(newTest.Label))
+		}
+		// etc.
+	}
diff --git a/compiler/Makefile b/compiler/Makefile
new file mode 100644
index 0000000..ad85973
--- /dev/null
+++ b/compiler/Makefile
@@ -0,0 +1,44 @@
+# Go support for Protocol Buffers - Google's data interchange format
+#
+# Copyright 2010 Google Inc.  All rights reserved.
+# http://code.google.com/p/goprotobuf/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=protoc-gen-go
+GOFILES=\
+	main.go\
+
+DEPS=descriptor plugin
+
+include $(GOROOT)/src/Make.cmd
+
+test:
+	cd testdata && make test
diff --git a/compiler/descriptor/Makefile b/compiler/descriptor/Makefile
new file mode 100644
index 0000000..cd2add9
--- /dev/null
+++ b/compiler/descriptor/Makefile
@@ -0,0 +1,53 @@
+# Go support for Protocol Buffers - Google's data interchange format
+#
+# Copyright 2010 Google Inc.  All rights reserved.
+# http://code.google.com/p/goprotobuf/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=goprotobuf.googlecode.com/hg/compiler/descriptor
+GOFILES=\
+	descriptor.pb.go\
+
+include $(GOROOT)/src/Make.pkg
+
+# Not stored here, but descriptor.proto is in http://code.google.com/p/protobuf
+# at protobuf-2.3.0/src/google/protobuf/descriptor.proto
+# Also we need to fix an import.
+regenerate:
+	echo WARNING! THIS RULE IS PROBABLY NOT RIGHT FOR YOUR INSTALLATION
+	cd $(HOME)/protobuf-2.3.0/src && \
+	protoc --go_out=. ./google/protobuf/descriptor.proto && \
+	cp ./google/protobuf/descriptor.pb.go $(GOROOT)/src/pkg/goprotobuf.googlecode.com/hg/compiler/descriptor/descriptor.pb.go
+
+restore:
+	cp descriptor.pb.golden descriptor.pb.go
+
+preserve:
+	cp descriptor.pb.go descriptor.pb.golden
diff --git a/compiler/descriptor/descriptor.pb.go b/compiler/descriptor/descriptor.pb.go
new file mode 100644
index 0000000..dc7e4a6
--- /dev/null
+++ b/compiler/descriptor/descriptor.pb.go
@@ -0,0 +1,398 @@
+// Code generated by protoc-gen-go from "google/protobuf/descriptor.proto"
+// DO NOT EDIT!
+
+package google_protobuf
+
+import "goprotobuf.googlecode.com/hg/proto"
+
+type FieldDescriptorProto_Type int32
+const (
+	FieldDescriptorProto_TYPE_DOUBLE = 1
+	FieldDescriptorProto_TYPE_FLOAT = 2
+	FieldDescriptorProto_TYPE_INT64 = 3
+	FieldDescriptorProto_TYPE_UINT64 = 4
+	FieldDescriptorProto_TYPE_INT32 = 5
+	FieldDescriptorProto_TYPE_FIXED64 = 6
+	FieldDescriptorProto_TYPE_FIXED32 = 7
+	FieldDescriptorProto_TYPE_BOOL = 8
+	FieldDescriptorProto_TYPE_STRING = 9
+	FieldDescriptorProto_TYPE_GROUP = 10
+	FieldDescriptorProto_TYPE_MESSAGE = 11
+	FieldDescriptorProto_TYPE_BYTES = 12
+	FieldDescriptorProto_TYPE_UINT32 = 13
+	FieldDescriptorProto_TYPE_ENUM = 14
+	FieldDescriptorProto_TYPE_SFIXED32 = 15
+	FieldDescriptorProto_TYPE_SFIXED64 = 16
+	FieldDescriptorProto_TYPE_SINT32 = 17
+	FieldDescriptorProto_TYPE_SINT64 = 18
+)
+var FieldDescriptorProto_Type_name = map[int32] string {
+	1: "TYPE_DOUBLE",
+	2: "TYPE_FLOAT",
+	3: "TYPE_INT64",
+	4: "TYPE_UINT64",
+	5: "TYPE_INT32",
+	6: "TYPE_FIXED64",
+	7: "TYPE_FIXED32",
+	8: "TYPE_BOOL",
+	9: "TYPE_STRING",
+	10: "TYPE_GROUP",
+	11: "TYPE_MESSAGE",
+	12: "TYPE_BYTES",
+	13: "TYPE_UINT32",
+	14: "TYPE_ENUM",
+	15: "TYPE_SFIXED32",
+	16: "TYPE_SFIXED64",
+	17: "TYPE_SINT32",
+	18: "TYPE_SINT64",
+}
+var FieldDescriptorProto_Type_value = map[string] int32 {
+	"TYPE_DOUBLE": 1,
+	"TYPE_FLOAT": 2,
+	"TYPE_INT64": 3,
+	"TYPE_UINT64": 4,
+	"TYPE_INT32": 5,
+	"TYPE_FIXED64": 6,
+	"TYPE_FIXED32": 7,
+	"TYPE_BOOL": 8,
+	"TYPE_STRING": 9,
+	"TYPE_GROUP": 10,
+	"TYPE_MESSAGE": 11,
+	"TYPE_BYTES": 12,
+	"TYPE_UINT32": 13,
+	"TYPE_ENUM": 14,
+	"TYPE_SFIXED32": 15,
+	"TYPE_SFIXED64": 16,
+	"TYPE_SINT32": 17,
+	"TYPE_SINT64": 18,
+}
+func NewFieldDescriptorProto_Type(x int32) *FieldDescriptorProto_Type {
+	e := FieldDescriptorProto_Type(x)
+	return &e
+}
+
+type FieldDescriptorProto_Label int32
+const (
+	FieldDescriptorProto_LABEL_OPTIONAL = 1
+	FieldDescriptorProto_LABEL_REQUIRED = 2
+	FieldDescriptorProto_LABEL_REPEATED = 3
+)
+var FieldDescriptorProto_Label_name = map[int32] string {
+	1: "LABEL_OPTIONAL",
+	2: "LABEL_REQUIRED",
+	3: "LABEL_REPEATED",
+}
+var FieldDescriptorProto_Label_value = map[string] int32 {
+	"LABEL_OPTIONAL": 1,
+	"LABEL_REQUIRED": 2,
+	"LABEL_REPEATED": 3,
+}
+func NewFieldDescriptorProto_Label(x int32) *FieldDescriptorProto_Label {
+	e := FieldDescriptorProto_Label(x)
+	return &e
+}
+
+type FileOptions_OptimizeMode int32
+const (
+	FileOptions_SPEED = 1
+	FileOptions_CODE_SIZE = 2
+	FileOptions_LITE_RUNTIME = 3
+)
+var FileOptions_OptimizeMode_name = map[int32] string {
+	1: "SPEED",
+	2: "CODE_SIZE",
+	3: "LITE_RUNTIME",
+}
+var FileOptions_OptimizeMode_value = map[string] int32 {
+	"SPEED": 1,
+	"CODE_SIZE": 2,
+	"LITE_RUNTIME": 3,
+}
+func NewFileOptions_OptimizeMode(x int32) *FileOptions_OptimizeMode {
+	e := FileOptions_OptimizeMode(x)
+	return &e
+}
+
+type FieldOptions_CType int32
+const (
+	FieldOptions_STRING = 0
+	FieldOptions_CORD = 1
+	FieldOptions_STRING_PIECE = 2
+)
+var FieldOptions_CType_name = map[int32] string {
+	0: "STRING",
+	1: "CORD",
+	2: "STRING_PIECE",
+}
+var FieldOptions_CType_value = map[string] int32 {
+	"STRING": 0,
+	"CORD": 1,
+	"STRING_PIECE": 2,
+}
+func NewFieldOptions_CType(x int32) *FieldOptions_CType {
+	e := FieldOptions_CType(x)
+	return &e
+}
+
+type FileDescriptorSet struct {
+	File	[]*FileDescriptorProto	"PB(bytes,1,rep,name=file)"
+	XXX_unrecognized	[]byte
+}
+func (this *FileDescriptorSet) Reset() {
+	*this = FileDescriptorSet{}
+}
+func NewFileDescriptorSet() *FileDescriptorSet {
+	return new(FileDescriptorSet)
+}
+
+type FileDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Package	*string	"PB(bytes,2,opt,name=package)"
+	Dependency	[]string	"PB(bytes,3,rep,name=dependency)"
+	MessageType	[]*DescriptorProto	"PB(bytes,4,rep,name=message_type)"
+	EnumType	[]*EnumDescriptorProto	"PB(bytes,5,rep,name=enum_type)"
+	Service	[]*ServiceDescriptorProto	"PB(bytes,6,rep,name=service)"
+	Extension	[]*FieldDescriptorProto	"PB(bytes,7,rep,name=extension)"
+	Options	*FileOptions	"PB(bytes,8,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *FileDescriptorProto) Reset() {
+	*this = FileDescriptorProto{}
+}
+func NewFileDescriptorProto() *FileDescriptorProto {
+	return new(FileDescriptorProto)
+}
+
+type DescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Field	[]*FieldDescriptorProto	"PB(bytes,2,rep,name=field)"
+	Extension	[]*FieldDescriptorProto	"PB(bytes,6,rep,name=extension)"
+	NestedType	[]*DescriptorProto	"PB(bytes,3,rep,name=nested_type)"
+	EnumType	[]*EnumDescriptorProto	"PB(bytes,4,rep,name=enum_type)"
+	ExtensionRange	[]*DescriptorProto_ExtensionRange	"PB(bytes,5,rep,name=extension_range)"
+	Options	*MessageOptions	"PB(bytes,7,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *DescriptorProto) Reset() {
+	*this = DescriptorProto{}
+}
+func NewDescriptorProto() *DescriptorProto {
+	return new(DescriptorProto)
+}
+
+type DescriptorProto_ExtensionRange struct {
+	Start	*int32	"PB(varint,1,opt,name=start)"
+	End	*int32	"PB(varint,2,opt,name=end)"
+	XXX_unrecognized	[]byte
+}
+func (this *DescriptorProto_ExtensionRange) Reset() {
+	*this = DescriptorProto_ExtensionRange{}
+}
+func NewDescriptorProto_ExtensionRange() *DescriptorProto_ExtensionRange {
+	return new(DescriptorProto_ExtensionRange)
+}
+
+type FieldDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Number	*int32	"PB(varint,3,opt,name=number)"
+	Label	*FieldDescriptorProto_Label	"PB(varint,4,opt,name=label,enum=google_protobuf.FieldDescriptorProto_Label)"
+	Type	*FieldDescriptorProto_Type	"PB(varint,5,opt,name=type,enum=google_protobuf.FieldDescriptorProto_Type)"
+	TypeName	*string	"PB(bytes,6,opt,name=type_name)"
+	Extendee	*string	"PB(bytes,2,opt,name=extendee)"
+	DefaultValue	*string	"PB(bytes,7,opt,name=default_value)"
+	Options	*FieldOptions	"PB(bytes,8,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *FieldDescriptorProto) Reset() {
+	*this = FieldDescriptorProto{}
+}
+func NewFieldDescriptorProto() *FieldDescriptorProto {
+	return new(FieldDescriptorProto)
+}
+
+type EnumDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Value	[]*EnumValueDescriptorProto	"PB(bytes,2,rep,name=value)"
+	Options	*EnumOptions	"PB(bytes,3,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *EnumDescriptorProto) Reset() {
+	*this = EnumDescriptorProto{}
+}
+func NewEnumDescriptorProto() *EnumDescriptorProto {
+	return new(EnumDescriptorProto)
+}
+
+type EnumValueDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Number	*int32	"PB(varint,2,opt,name=number)"
+	Options	*EnumValueOptions	"PB(bytes,3,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *EnumValueDescriptorProto) Reset() {
+	*this = EnumValueDescriptorProto{}
+}
+func NewEnumValueDescriptorProto() *EnumValueDescriptorProto {
+	return new(EnumValueDescriptorProto)
+}
+
+type ServiceDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Method	[]*MethodDescriptorProto	"PB(bytes,2,rep,name=method)"
+	Options	*ServiceOptions	"PB(bytes,3,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *ServiceDescriptorProto) Reset() {
+	*this = ServiceDescriptorProto{}
+}
+func NewServiceDescriptorProto() *ServiceDescriptorProto {
+	return new(ServiceDescriptorProto)
+}
+
+type MethodDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	InputType	*string	"PB(bytes,2,opt,name=input_type)"
+	OutputType	*string	"PB(bytes,3,opt,name=output_type)"
+	Options	*MethodOptions	"PB(bytes,4,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *MethodDescriptorProto) Reset() {
+	*this = MethodDescriptorProto{}
+}
+func NewMethodDescriptorProto() *MethodDescriptorProto {
+	return new(MethodDescriptorProto)
+}
+
+type FileOptions struct {
+	JavaPackage	*string	"PB(bytes,1,opt,name=java_package)"
+	JavaOuterClassname	*string	"PB(bytes,8,opt,name=java_outer_classname)"
+	JavaMultipleFiles	*bool	"PB(varint,10,opt,name=java_multiple_files,def=0)"
+	OptimizeFor	*FileOptions_OptimizeMode	"PB(varint,9,opt,name=optimize_for,enum=google_protobuf.FileOptions_OptimizeMode,def=1)"
+	CcGenericServices	*bool	"PB(varint,16,opt,name=cc_generic_services,def=1)"
+	JavaGenericServices	*bool	"PB(varint,17,opt,name=java_generic_services,def=1)"
+	PyGenericServices	*bool	"PB(varint,18,opt,name=py_generic_services,def=1)"
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *FileOptions) Reset() {
+	*this = FileOptions{}
+}
+func NewFileOptions() *FileOptions {
+	return new(FileOptions)
+}
+const Default_FileOptions_JavaMultipleFiles bool = false
+const Default_FileOptions_OptimizeFor FileOptions_OptimizeMode = FileOptions_SPEED
+const Default_FileOptions_CcGenericServices bool = true
+const Default_FileOptions_JavaGenericServices bool = true
+const Default_FileOptions_PyGenericServices bool = true
+
+type MessageOptions struct {
+	MessageSetWireFormat	*bool	"PB(varint,1,opt,name=message_set_wire_format,def=0)"
+	NoStandardDescriptorAccessor	*bool	"PB(varint,2,opt,name=no_standard_descriptor_accessor,def=0)"
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *MessageOptions) Reset() {
+	*this = MessageOptions{}
+}
+func NewMessageOptions() *MessageOptions {
+	return new(MessageOptions)
+}
+const Default_MessageOptions_MessageSetWireFormat bool = false
+const Default_MessageOptions_NoStandardDescriptorAccessor bool = false
+
+type FieldOptions struct {
+	Ctype	*FieldOptions_CType	"PB(varint,1,opt,name=ctype,enum=google_protobuf.FieldOptions_CType,def=0)"
+	Packed	*bool	"PB(varint,2,opt,name=packed)"
+	Deprecated	*bool	"PB(varint,3,opt,name=deprecated,def=0)"
+	ExperimentalMapKey	*string	"PB(bytes,9,opt,name=experimental_map_key)"
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *FieldOptions) Reset() {
+	*this = FieldOptions{}
+}
+func NewFieldOptions() *FieldOptions {
+	return new(FieldOptions)
+}
+const Default_FieldOptions_Ctype FieldOptions_CType = FieldOptions_STRING
+const Default_FieldOptions_Deprecated bool = false
+
+type EnumOptions struct {
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *EnumOptions) Reset() {
+	*this = EnumOptions{}
+}
+func NewEnumOptions() *EnumOptions {
+	return new(EnumOptions)
+}
+
+type EnumValueOptions struct {
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *EnumValueOptions) Reset() {
+	*this = EnumValueOptions{}
+}
+func NewEnumValueOptions() *EnumValueOptions {
+	return new(EnumValueOptions)
+}
+
+type ServiceOptions struct {
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *ServiceOptions) Reset() {
+	*this = ServiceOptions{}
+}
+func NewServiceOptions() *ServiceOptions {
+	return new(ServiceOptions)
+}
+
+type MethodOptions struct {
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *MethodOptions) Reset() {
+	*this = MethodOptions{}
+}
+func NewMethodOptions() *MethodOptions {
+	return new(MethodOptions)
+}
+
+type UninterpretedOption struct {
+	Name	[]*UninterpretedOption_NamePart	"PB(bytes,2,rep,name=name)"
+	IdentifierValue	*string	"PB(bytes,3,opt,name=identifier_value)"
+	PositiveIntValue	*uint64	"PB(varint,4,opt,name=positive_int_value)"
+	NegativeIntValue	*int64	"PB(varint,5,opt,name=negative_int_value)"
+	DoubleValue	*float64	"PB(fixed64,6,opt,name=double_value)"
+	StringValue	[]byte	"PB(bytes,7,opt,name=string_value)"
+	XXX_unrecognized	[]byte
+}
+func (this *UninterpretedOption) Reset() {
+	*this = UninterpretedOption{}
+}
+func NewUninterpretedOption() *UninterpretedOption {
+	return new(UninterpretedOption)
+}
+
+type UninterpretedOption_NamePart struct {
+	NamePart	*string	"PB(bytes,1,req,name=name_part)"
+	IsExtension	*bool	"PB(varint,2,req,name=is_extension)"
+	XXX_unrecognized	[]byte
+}
+func (this *UninterpretedOption_NamePart) Reset() {
+	*this = UninterpretedOption_NamePart{}
+}
+func NewUninterpretedOption_NamePart() *UninterpretedOption_NamePart {
+	return new(UninterpretedOption_NamePart)
+}
+
+func init() {
+	proto.RegisterEnum("google_protobuf.FieldDescriptorProto_Type", FieldDescriptorProto_Type_name, FieldDescriptorProto_Type_value)
+	proto.RegisterEnum("google_protobuf.FieldDescriptorProto_Label", FieldDescriptorProto_Label_name, FieldDescriptorProto_Label_value)
+	proto.RegisterEnum("google_protobuf.FileOptions_OptimizeMode", FileOptions_OptimizeMode_name, FileOptions_OptimizeMode_value)
+	proto.RegisterEnum("google_protobuf.FieldOptions_CType", FieldOptions_CType_name, FieldOptions_CType_value)
+}
diff --git a/compiler/descriptor/descriptor.pb.golden b/compiler/descriptor/descriptor.pb.golden
new file mode 100644
index 0000000..dc7e4a6
--- /dev/null
+++ b/compiler/descriptor/descriptor.pb.golden
@@ -0,0 +1,398 @@
+// Code generated by protoc-gen-go from "google/protobuf/descriptor.proto"
+// DO NOT EDIT!
+
+package google_protobuf
+
+import "goprotobuf.googlecode.com/hg/proto"
+
+type FieldDescriptorProto_Type int32
+const (
+	FieldDescriptorProto_TYPE_DOUBLE = 1
+	FieldDescriptorProto_TYPE_FLOAT = 2
+	FieldDescriptorProto_TYPE_INT64 = 3
+	FieldDescriptorProto_TYPE_UINT64 = 4
+	FieldDescriptorProto_TYPE_INT32 = 5
+	FieldDescriptorProto_TYPE_FIXED64 = 6
+	FieldDescriptorProto_TYPE_FIXED32 = 7
+	FieldDescriptorProto_TYPE_BOOL = 8
+	FieldDescriptorProto_TYPE_STRING = 9
+	FieldDescriptorProto_TYPE_GROUP = 10
+	FieldDescriptorProto_TYPE_MESSAGE = 11
+	FieldDescriptorProto_TYPE_BYTES = 12
+	FieldDescriptorProto_TYPE_UINT32 = 13
+	FieldDescriptorProto_TYPE_ENUM = 14
+	FieldDescriptorProto_TYPE_SFIXED32 = 15
+	FieldDescriptorProto_TYPE_SFIXED64 = 16
+	FieldDescriptorProto_TYPE_SINT32 = 17
+	FieldDescriptorProto_TYPE_SINT64 = 18
+)
+var FieldDescriptorProto_Type_name = map[int32] string {
+	1: "TYPE_DOUBLE",
+	2: "TYPE_FLOAT",
+	3: "TYPE_INT64",
+	4: "TYPE_UINT64",
+	5: "TYPE_INT32",
+	6: "TYPE_FIXED64",
+	7: "TYPE_FIXED32",
+	8: "TYPE_BOOL",
+	9: "TYPE_STRING",
+	10: "TYPE_GROUP",
+	11: "TYPE_MESSAGE",
+	12: "TYPE_BYTES",
+	13: "TYPE_UINT32",
+	14: "TYPE_ENUM",
+	15: "TYPE_SFIXED32",
+	16: "TYPE_SFIXED64",
+	17: "TYPE_SINT32",
+	18: "TYPE_SINT64",
+}
+var FieldDescriptorProto_Type_value = map[string] int32 {
+	"TYPE_DOUBLE": 1,
+	"TYPE_FLOAT": 2,
+	"TYPE_INT64": 3,
+	"TYPE_UINT64": 4,
+	"TYPE_INT32": 5,
+	"TYPE_FIXED64": 6,
+	"TYPE_FIXED32": 7,
+	"TYPE_BOOL": 8,
+	"TYPE_STRING": 9,
+	"TYPE_GROUP": 10,
+	"TYPE_MESSAGE": 11,
+	"TYPE_BYTES": 12,
+	"TYPE_UINT32": 13,
+	"TYPE_ENUM": 14,
+	"TYPE_SFIXED32": 15,
+	"TYPE_SFIXED64": 16,
+	"TYPE_SINT32": 17,
+	"TYPE_SINT64": 18,
+}
+func NewFieldDescriptorProto_Type(x int32) *FieldDescriptorProto_Type {
+	e := FieldDescriptorProto_Type(x)
+	return &e
+}
+
+type FieldDescriptorProto_Label int32
+const (
+	FieldDescriptorProto_LABEL_OPTIONAL = 1
+	FieldDescriptorProto_LABEL_REQUIRED = 2
+	FieldDescriptorProto_LABEL_REPEATED = 3
+)
+var FieldDescriptorProto_Label_name = map[int32] string {
+	1: "LABEL_OPTIONAL",
+	2: "LABEL_REQUIRED",
+	3: "LABEL_REPEATED",
+}
+var FieldDescriptorProto_Label_value = map[string] int32 {
+	"LABEL_OPTIONAL": 1,
+	"LABEL_REQUIRED": 2,
+	"LABEL_REPEATED": 3,
+}
+func NewFieldDescriptorProto_Label(x int32) *FieldDescriptorProto_Label {
+	e := FieldDescriptorProto_Label(x)
+	return &e
+}
+
+type FileOptions_OptimizeMode int32
+const (
+	FileOptions_SPEED = 1
+	FileOptions_CODE_SIZE = 2
+	FileOptions_LITE_RUNTIME = 3
+)
+var FileOptions_OptimizeMode_name = map[int32] string {
+	1: "SPEED",
+	2: "CODE_SIZE",
+	3: "LITE_RUNTIME",
+}
+var FileOptions_OptimizeMode_value = map[string] int32 {
+	"SPEED": 1,
+	"CODE_SIZE": 2,
+	"LITE_RUNTIME": 3,
+}
+func NewFileOptions_OptimizeMode(x int32) *FileOptions_OptimizeMode {
+	e := FileOptions_OptimizeMode(x)
+	return &e
+}
+
+type FieldOptions_CType int32
+const (
+	FieldOptions_STRING = 0
+	FieldOptions_CORD = 1
+	FieldOptions_STRING_PIECE = 2
+)
+var FieldOptions_CType_name = map[int32] string {
+	0: "STRING",
+	1: "CORD",
+	2: "STRING_PIECE",
+}
+var FieldOptions_CType_value = map[string] int32 {
+	"STRING": 0,
+	"CORD": 1,
+	"STRING_PIECE": 2,
+}
+func NewFieldOptions_CType(x int32) *FieldOptions_CType {
+	e := FieldOptions_CType(x)
+	return &e
+}
+
+type FileDescriptorSet struct {
+	File	[]*FileDescriptorProto	"PB(bytes,1,rep,name=file)"
+	XXX_unrecognized	[]byte
+}
+func (this *FileDescriptorSet) Reset() {
+	*this = FileDescriptorSet{}
+}
+func NewFileDescriptorSet() *FileDescriptorSet {
+	return new(FileDescriptorSet)
+}
+
+type FileDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Package	*string	"PB(bytes,2,opt,name=package)"
+	Dependency	[]string	"PB(bytes,3,rep,name=dependency)"
+	MessageType	[]*DescriptorProto	"PB(bytes,4,rep,name=message_type)"
+	EnumType	[]*EnumDescriptorProto	"PB(bytes,5,rep,name=enum_type)"
+	Service	[]*ServiceDescriptorProto	"PB(bytes,6,rep,name=service)"
+	Extension	[]*FieldDescriptorProto	"PB(bytes,7,rep,name=extension)"
+	Options	*FileOptions	"PB(bytes,8,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *FileDescriptorProto) Reset() {
+	*this = FileDescriptorProto{}
+}
+func NewFileDescriptorProto() *FileDescriptorProto {
+	return new(FileDescriptorProto)
+}
+
+type DescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Field	[]*FieldDescriptorProto	"PB(bytes,2,rep,name=field)"
+	Extension	[]*FieldDescriptorProto	"PB(bytes,6,rep,name=extension)"
+	NestedType	[]*DescriptorProto	"PB(bytes,3,rep,name=nested_type)"
+	EnumType	[]*EnumDescriptorProto	"PB(bytes,4,rep,name=enum_type)"
+	ExtensionRange	[]*DescriptorProto_ExtensionRange	"PB(bytes,5,rep,name=extension_range)"
+	Options	*MessageOptions	"PB(bytes,7,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *DescriptorProto) Reset() {
+	*this = DescriptorProto{}
+}
+func NewDescriptorProto() *DescriptorProto {
+	return new(DescriptorProto)
+}
+
+type DescriptorProto_ExtensionRange struct {
+	Start	*int32	"PB(varint,1,opt,name=start)"
+	End	*int32	"PB(varint,2,opt,name=end)"
+	XXX_unrecognized	[]byte
+}
+func (this *DescriptorProto_ExtensionRange) Reset() {
+	*this = DescriptorProto_ExtensionRange{}
+}
+func NewDescriptorProto_ExtensionRange() *DescriptorProto_ExtensionRange {
+	return new(DescriptorProto_ExtensionRange)
+}
+
+type FieldDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Number	*int32	"PB(varint,3,opt,name=number)"
+	Label	*FieldDescriptorProto_Label	"PB(varint,4,opt,name=label,enum=google_protobuf.FieldDescriptorProto_Label)"
+	Type	*FieldDescriptorProto_Type	"PB(varint,5,opt,name=type,enum=google_protobuf.FieldDescriptorProto_Type)"
+	TypeName	*string	"PB(bytes,6,opt,name=type_name)"
+	Extendee	*string	"PB(bytes,2,opt,name=extendee)"
+	DefaultValue	*string	"PB(bytes,7,opt,name=default_value)"
+	Options	*FieldOptions	"PB(bytes,8,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *FieldDescriptorProto) Reset() {
+	*this = FieldDescriptorProto{}
+}
+func NewFieldDescriptorProto() *FieldDescriptorProto {
+	return new(FieldDescriptorProto)
+}
+
+type EnumDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Value	[]*EnumValueDescriptorProto	"PB(bytes,2,rep,name=value)"
+	Options	*EnumOptions	"PB(bytes,3,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *EnumDescriptorProto) Reset() {
+	*this = EnumDescriptorProto{}
+}
+func NewEnumDescriptorProto() *EnumDescriptorProto {
+	return new(EnumDescriptorProto)
+}
+
+type EnumValueDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Number	*int32	"PB(varint,2,opt,name=number)"
+	Options	*EnumValueOptions	"PB(bytes,3,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *EnumValueDescriptorProto) Reset() {
+	*this = EnumValueDescriptorProto{}
+}
+func NewEnumValueDescriptorProto() *EnumValueDescriptorProto {
+	return new(EnumValueDescriptorProto)
+}
+
+type ServiceDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	Method	[]*MethodDescriptorProto	"PB(bytes,2,rep,name=method)"
+	Options	*ServiceOptions	"PB(bytes,3,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *ServiceDescriptorProto) Reset() {
+	*this = ServiceDescriptorProto{}
+}
+func NewServiceDescriptorProto() *ServiceDescriptorProto {
+	return new(ServiceDescriptorProto)
+}
+
+type MethodDescriptorProto struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	InputType	*string	"PB(bytes,2,opt,name=input_type)"
+	OutputType	*string	"PB(bytes,3,opt,name=output_type)"
+	Options	*MethodOptions	"PB(bytes,4,opt,name=options)"
+	XXX_unrecognized	[]byte
+}
+func (this *MethodDescriptorProto) Reset() {
+	*this = MethodDescriptorProto{}
+}
+func NewMethodDescriptorProto() *MethodDescriptorProto {
+	return new(MethodDescriptorProto)
+}
+
+type FileOptions struct {
+	JavaPackage	*string	"PB(bytes,1,opt,name=java_package)"
+	JavaOuterClassname	*string	"PB(bytes,8,opt,name=java_outer_classname)"
+	JavaMultipleFiles	*bool	"PB(varint,10,opt,name=java_multiple_files,def=0)"
+	OptimizeFor	*FileOptions_OptimizeMode	"PB(varint,9,opt,name=optimize_for,enum=google_protobuf.FileOptions_OptimizeMode,def=1)"
+	CcGenericServices	*bool	"PB(varint,16,opt,name=cc_generic_services,def=1)"
+	JavaGenericServices	*bool	"PB(varint,17,opt,name=java_generic_services,def=1)"
+	PyGenericServices	*bool	"PB(varint,18,opt,name=py_generic_services,def=1)"
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *FileOptions) Reset() {
+	*this = FileOptions{}
+}
+func NewFileOptions() *FileOptions {
+	return new(FileOptions)
+}
+const Default_FileOptions_JavaMultipleFiles bool = false
+const Default_FileOptions_OptimizeFor FileOptions_OptimizeMode = FileOptions_SPEED
+const Default_FileOptions_CcGenericServices bool = true
+const Default_FileOptions_JavaGenericServices bool = true
+const Default_FileOptions_PyGenericServices bool = true
+
+type MessageOptions struct {
+	MessageSetWireFormat	*bool	"PB(varint,1,opt,name=message_set_wire_format,def=0)"
+	NoStandardDescriptorAccessor	*bool	"PB(varint,2,opt,name=no_standard_descriptor_accessor,def=0)"
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *MessageOptions) Reset() {
+	*this = MessageOptions{}
+}
+func NewMessageOptions() *MessageOptions {
+	return new(MessageOptions)
+}
+const Default_MessageOptions_MessageSetWireFormat bool = false
+const Default_MessageOptions_NoStandardDescriptorAccessor bool = false
+
+type FieldOptions struct {
+	Ctype	*FieldOptions_CType	"PB(varint,1,opt,name=ctype,enum=google_protobuf.FieldOptions_CType,def=0)"
+	Packed	*bool	"PB(varint,2,opt,name=packed)"
+	Deprecated	*bool	"PB(varint,3,opt,name=deprecated,def=0)"
+	ExperimentalMapKey	*string	"PB(bytes,9,opt,name=experimental_map_key)"
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *FieldOptions) Reset() {
+	*this = FieldOptions{}
+}
+func NewFieldOptions() *FieldOptions {
+	return new(FieldOptions)
+}
+const Default_FieldOptions_Ctype FieldOptions_CType = FieldOptions_STRING
+const Default_FieldOptions_Deprecated bool = false
+
+type EnumOptions struct {
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *EnumOptions) Reset() {
+	*this = EnumOptions{}
+}
+func NewEnumOptions() *EnumOptions {
+	return new(EnumOptions)
+}
+
+type EnumValueOptions struct {
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *EnumValueOptions) Reset() {
+	*this = EnumValueOptions{}
+}
+func NewEnumValueOptions() *EnumValueOptions {
+	return new(EnumValueOptions)
+}
+
+type ServiceOptions struct {
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *ServiceOptions) Reset() {
+	*this = ServiceOptions{}
+}
+func NewServiceOptions() *ServiceOptions {
+	return new(ServiceOptions)
+}
+
+type MethodOptions struct {
+	UninterpretedOption	[]*UninterpretedOption	"PB(bytes,999,rep,name=uninterpreted_option)"
+	XXX_unrecognized	[]byte
+}
+func (this *MethodOptions) Reset() {
+	*this = MethodOptions{}
+}
+func NewMethodOptions() *MethodOptions {
+	return new(MethodOptions)
+}
+
+type UninterpretedOption struct {
+	Name	[]*UninterpretedOption_NamePart	"PB(bytes,2,rep,name=name)"
+	IdentifierValue	*string	"PB(bytes,3,opt,name=identifier_value)"
+	PositiveIntValue	*uint64	"PB(varint,4,opt,name=positive_int_value)"
+	NegativeIntValue	*int64	"PB(varint,5,opt,name=negative_int_value)"
+	DoubleValue	*float64	"PB(fixed64,6,opt,name=double_value)"
+	StringValue	[]byte	"PB(bytes,7,opt,name=string_value)"
+	XXX_unrecognized	[]byte
+}
+func (this *UninterpretedOption) Reset() {
+	*this = UninterpretedOption{}
+}
+func NewUninterpretedOption() *UninterpretedOption {
+	return new(UninterpretedOption)
+}
+
+type UninterpretedOption_NamePart struct {
+	NamePart	*string	"PB(bytes,1,req,name=name_part)"
+	IsExtension	*bool	"PB(varint,2,req,name=is_extension)"
+	XXX_unrecognized	[]byte
+}
+func (this *UninterpretedOption_NamePart) Reset() {
+	*this = UninterpretedOption_NamePart{}
+}
+func NewUninterpretedOption_NamePart() *UninterpretedOption_NamePart {
+	return new(UninterpretedOption_NamePart)
+}
+
+func init() {
+	proto.RegisterEnum("google_protobuf.FieldDescriptorProto_Type", FieldDescriptorProto_Type_name, FieldDescriptorProto_Type_value)
+	proto.RegisterEnum("google_protobuf.FieldDescriptorProto_Label", FieldDescriptorProto_Label_name, FieldDescriptorProto_Label_value)
+	proto.RegisterEnum("google_protobuf.FileOptions_OptimizeMode", FileOptions_OptimizeMode_name, FileOptions_OptimizeMode_value)
+	proto.RegisterEnum("google_protobuf.FieldOptions_CType", FieldOptions_CType_name, FieldOptions_CType_value)
+}
diff --git a/compiler/doc.go b/compiler/doc.go
new file mode 100644
index 0000000..f84ff8e
--- /dev/null
+++ b/compiler/doc.go
@@ -0,0 +1,51 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/*
+	A plugin for the Google protocol buffer compiler to generate Go code.
+	Run it by building this program and putting it in your path with the name
+		protoc-gen-go
+	That word 'go' at the end becomes part of the option string set for the
+	protocol compiler, so once the protocol compiler (protoc) is installed
+	you can run
+		protoc --go_out=output_directory input_directory/file.proto
+	to generate Go bindings for the protocol defined by file.proto.
+	With that input, the output will be written to
+		output_directory/file.pb.go
+
+	The generated code is documented in the package comment for
+	the library.
+
+	See the README and documentation for protocol buffers to learn more:
+		http://code.google.com/p/protobuf/
+
+*/
+package documentation
diff --git a/compiler/main.go b/compiler/main.go
new file mode 100644
index 0000000..88bb4c5
--- /dev/null
+++ b/compiler/main.go
@@ -0,0 +1,903 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/*
+	A plugin for the Google protocol buffer compiler to generate Go code.
+
+	This plugin takes no options and the protocol buffer file syntax does
+	not yet define any options for Go, so program does no option evaluation.
+	That may change.
+
+	Not supported yet:
+		Extensions
+		Services
+*/
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"strings"
+	"unicode"
+
+	"goprotobuf.googlecode.com/hg/proto"
+	plugin "goprotobuf.googlecode.com/hg/compiler/plugin"
+	descriptor "goprotobuf.googlecode.com/hg/compiler/descriptor"
+)
+
+func main() {
+	// Begin by allocating a generator. The request and response structures are stored there
+	// so we can do error handling easily - the response structure contains the field to
+	// report failure.
+	g := NewGenerator()
+
+	data, err := ioutil.ReadAll(os.Stdin)
+	if err != nil {
+		g.error(err, "reading input")
+	}
+
+	if err := proto.Unmarshal(data, g.request); err != nil {
+		g.error(err, "parsing input proto")
+	}
+
+	if len(g.request.FileToGenerate) == 0 {
+		g.fail("no files to generate")
+	}
+
+	// Create a wrapped version of the Descriptors and EnumDescriptors that
+	// point to the file that defines them.
+	g.WrapTypes()
+
+	g.SetPackageNames()
+	g.BuildTypeNameMap()
+
+	g.GenerateAllFiles()
+
+	// Send back the results.
+	data, err = proto.Marshal(g.response)
+	if err != nil {
+		g.error(err, "failed to marshal output proto")
+	}
+	_, err = os.Stdout.Write(data)
+	if err != nil {
+		g.error(err, "failed to write output proto")
+	}
+}
+
+// Each type we import as a protocol buffer (other than FileDescriptorProto) needs
+// a pointer to the FileDescriptorProto that represents it.  These types achieve that
+// wrapping by placing each Proto inside a struct with the pointer to its File. The
+// structs have the same names as their contents, with "Proto" removed.
+// FileDescriptor is used to store the things that it points to.
+
+// The file and package name method are common to messages and enums.
+type common struct {
+	file *descriptor.FileDescriptorProto // File this object comes from.
+}
+
+// The package name we will produce in our output.
+func (c *common) packageName() string { return uniquePackageOf(c.file) }
+
+// A message (struct).
+type Descriptor struct {
+	common
+	*descriptor.DescriptorProto
+	parent   *Descriptor   // The containing message, if any.
+	nested   []*Descriptor // Inner messages, if any.
+	typename []string      // Cached typename vector.
+}
+
+// Return the elements of the dotted type name.  The package name is not part
+// of this name.
+func (d *Descriptor) typeName() []string {
+	if d.typename != nil {
+		return d.typename
+	}
+	n := 0
+	for parent := d; parent != nil; parent = parent.parent {
+		n++
+	}
+	s := make([]string, n, n)
+	for parent := d; parent != nil; parent = parent.parent {
+		n--
+		s[n] = proto.GetString(parent.Name)
+	}
+	d.typename = s
+	return s
+}
+
+// An enum. If it's at top level, its parent will be nil. Otherwise it will be
+// the descriptor of the message in which it is defined.
+type EnumDescriptor struct {
+	common
+	*descriptor.EnumDescriptorProto
+	parent   *Descriptor // The containing message, if any.
+	typename []string    // Cached typename vector.
+}
+
+// Return the elements of the dotted type name.
+func (e *EnumDescriptor) typeName() (s []string) {
+	if e.typename != nil {
+		return e.typename
+	}
+	name := proto.GetString(e.Name)
+	if e.parent == nil {
+		s = make([]string, 1)
+	} else {
+		pname := e.parent.typeName()
+		s = make([]string, len(pname)+1)
+		copy(s, pname)
+	}
+	s[len(s)-1] = name
+	e.typename = s
+	return s
+}
+
+// Everything but the last element of the full type name, CamelCased.
+// The values of type Foo.Bar are call Foo_value1... not Foo_Bar_value1... .
+func (e *EnumDescriptor) prefix() string {
+	typeName := e.typeName()
+	ccPrefix := CamelCaseSlice(typeName[0:len(typeName)-1]) + "_"
+	if e.parent == nil {
+		// If the enum is not part of a message, the prefix is just the type name.
+		ccPrefix = CamelCase(*e.Name) + "_"
+	}
+	return ccPrefix
+}
+
+// The integer value of the named constant in this enumerated type.
+func (e *EnumDescriptor) integerValueAsString(name string) string {
+	for _, c := range e.Value {
+		if proto.GetString(c.Name) == name {
+			return fmt.Sprint(proto.GetInt32(c.Number))
+		}
+	}
+	log.Exit("cannot find value for enum constant")
+	return ""
+}
+
+// A file. Includes slices of all the messages and enums defined within it.
+// Those slices are constructed by WrapTypes.
+type FileDescriptor struct {
+	*descriptor.FileDescriptorProto
+	desc []*Descriptor     // All the messages defined in this file.
+	enum []*EnumDescriptor // All the enums defined in this file.
+}
+
+// The package name we'll use in the generated code to refer to this file.
+func (d *FileDescriptor) packageName() string { return uniquePackageOf(d.FileDescriptorProto) }
+
+// The package named defined in the input for this file, possibly dotted.
+func (d *FileDescriptor) originalPackageName() string {
+	return proto.GetString(d.Package)
+}
+
+// Simplify some things by abstracting the abilities shared by enums and messages.
+type Object interface {
+	packageName() string // The name we use in our output (a_b_c), possibly renamed for uniqueness.
+	typeName() []string
+}
+
+// Each package name we generate must be unique. The package we're generating
+// gets its own name but every other package must have a unqiue name that does
+// not conflict in the code we generate.  These names are chosen globally (although
+// they don't have to be, it simplifies things to do them globally).
+func uniquePackageOf(fd *descriptor.FileDescriptorProto) string {
+	s, ok := uniquePackageName[fd]
+	if !ok {
+		log.Exit("internal error: no package name defined for", proto.GetString(fd.Name))
+	}
+	return s
+}
+
+// The type whose methods generate the output, stored in the associated response structure.
+type Generator struct {
+	bytes.Buffer
+
+	request  *plugin.CodeGeneratorRequest  // The input.
+	response *plugin.CodeGeneratorResponse // The output.
+
+	packageName      string            // What we're calling ourselves.
+	allFiles         []*FileDescriptor // All files in the tree
+	genFiles         []*FileDescriptor // Those files we will generate output for.
+	file             *FileDescriptor   // The file we are compiling now.
+	typeNameToObject map[string]Object // Key is a fully-qualified name in input syntax.
+	indent           string
+}
+
+// Create a new generator and allocate the request and response protobufs.
+func NewGenerator() *Generator {
+	g := new(Generator)
+	g.request = plugin.NewCodeGeneratorRequest()
+	g.response = plugin.NewCodeGeneratorResponse()
+	return g
+}
+
+// Report problem, including an os.Error, and fail.
+func (g *Generator) error(err os.Error, msgs ...string) {
+	s := strings.Join(msgs, " ") + ":" + err.String()
+	log.Stderr("protoc-gen-go: error: ", s)
+	g.response.Error = proto.String(s)
+	os.Exit(1)
+}
+
+// Report problem and fail.
+func (g *Generator) fail(msgs ...string) {
+	s := strings.Join(msgs, " ")
+	log.Stderr("protoc-gen-go: error: ", s)
+	g.response.Error = proto.String(s)
+	os.Exit(1)
+}
+
+// If this file is in a different package, return the package name we're using for this file, plus ".".
+// Otherwise return the empty string.
+func (g *Generator) DefaultPackageName(obj Object) string {
+	pkg := obj.packageName()
+	if pkg == g.packageName {
+		return ""
+	}
+	return pkg + "."
+}
+
+// For each input file, the unique package name to use, underscored.
+var uniquePackageName = make(map[*descriptor.FileDescriptorProto]string)
+
+// Set the package name for this run.  It must agree across all files being generated.
+// Also define unique package names for all imported files.
+func (g *Generator) SetPackageNames() {
+	inUse := make(map[string]bool)
+	pkg := proto.GetString(g.genFiles[0].Package)
+	g.packageName = strings.Map(DotToUnderscore, pkg)
+	inUse[pkg] = true
+	for _, f := range g.genFiles {
+		thisPkg := proto.GetString(f.Package)
+		if thisPkg != pkg {
+			g.fail("inconsistent package names:", thisPkg, pkg)
+		}
+	}
+AllFiles:
+	for _, f := range g.allFiles {
+		for _, genf := range g.genFiles {
+			if f == genf {
+				// In this package already.
+				uniquePackageName[f.FileDescriptorProto] = g.packageName
+				continue AllFiles
+			}
+		}
+		truePkg := proto.GetString(f.Package)
+		pkg := truePkg
+		for {
+			_, present := inUse[pkg]
+			if present {
+				// It's a duplicate; must rename.
+				pkg += "X"
+				continue
+			}
+			break
+		}
+		// Install it.
+		if pkg != truePkg {
+			log.Stderr("renaming duplicate imported package named", truePkg, "to", pkg)
+		}
+		inUse[pkg] = true
+		uniquePackageName[f.FileDescriptorProto] = strings.Map(DotToUnderscore, pkg)
+	}
+}
+
+// Walk the incoming data, wrapping DescriptorProtos and EnumDescriptorProtos
+// into file-referenced objects within the Generator.  Also create the list of files
+// to generate
+func (g *Generator) WrapTypes() {
+	g.allFiles = make([]*FileDescriptor, len(g.request.ProtoFile))
+	for i, f := range g.request.ProtoFile {
+		pkg := proto.GetString(f.Package)
+		if pkg == "" {
+			g.fail(proto.GetString(f.Name), "is missing a package declaration")
+		}
+		// We must wrap the descriptors before we wrap the enums
+		descs := WrapDescriptors(f)
+		g.BuildNestedDescriptors(descs)
+		enums := WrapEnumDescriptors(f, descs)
+		g.allFiles[i] = &FileDescriptor{
+			FileDescriptorProto: f,
+			desc:                descs,
+			enum:                enums,
+		}
+	}
+
+	g.genFiles = make([]*FileDescriptor, len(g.request.FileToGenerate))
+FindFiles:
+	for i, fileName := range g.request.FileToGenerate {
+		// Search the list.  This algorithm is n^2 but n is tiny.
+		for _, file := range g.allFiles {
+			if fileName == proto.GetString(file.Name) {
+				g.genFiles[i] = file
+				continue FindFiles
+			}
+		}
+		g.fail("could not find file named", fileName)
+	}
+	g.response.File = make([]*plugin.CodeGeneratorResponse_File, len(g.genFiles))
+}
+
+// Scan the descriptors in this file.  For each one, build the slice of nested descriptors
+func (g *Generator) BuildNestedDescriptors(descs []*Descriptor) {
+	for _, desc := range descs {
+		if len(desc.NestedType) != 0 {
+			desc.nested = make([]*Descriptor, len(desc.NestedType))
+			n := 0
+			for _, nest := range descs {
+				if nest.parent == desc {
+					desc.nested[n] = nest
+					n++
+				}
+			}
+			if n != len(desc.NestedType) {
+				g.fail("internal error: nesting failure for", proto.GetString(desc.Name))
+			}
+		}
+	}
+}
+
+// Construct the Descriptor and add it to the slice
+func AddDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*Descriptor {
+	if len(sl) == cap(sl) {
+		nsl := make([]*Descriptor, len(sl), 2*len(sl))
+		copy(nsl, sl)
+		sl = nsl
+	}
+	sl = sl[0 : len(sl)+1]
+	sl[len(sl)-1] = &Descriptor{common{file: file}, desc, parent, nil, nil}
+	return sl
+}
+
+// Return a slice of all the Descriptors defined within this file
+func WrapDescriptors(file *descriptor.FileDescriptorProto) []*Descriptor {
+	sl := make([]*Descriptor, 0, len(file.MessageType)+10)
+	for _, desc := range file.MessageType {
+		sl = WrapThisDescriptor(sl, desc, nil, file)
+	}
+	return sl
+}
+
+// Wrap this Descriptor, recursively
+func WrapThisDescriptor(sl []*Descriptor, desc *descriptor.DescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*Descriptor {
+	sl = AddDescriptor(sl, desc, parent, file)
+	me := sl[len(sl)-1]
+	for _, nested := range desc.NestedType {
+		sl = WrapThisDescriptor(sl, nested, me, file)
+	}
+	return sl
+}
+
+// Construct the EnumDescriptor and add it to the slice
+func AddEnumDescriptor(sl []*EnumDescriptor, desc *descriptor.EnumDescriptorProto, parent *Descriptor, file *descriptor.FileDescriptorProto) []*EnumDescriptor {
+	if len(sl) == cap(sl) {
+		nsl := make([]*EnumDescriptor, len(sl), 2*len(sl))
+		copy(nsl, sl)
+		sl = nsl
+	}
+	sl = sl[0 : len(sl)+1]
+	sl[len(sl)-1] = &EnumDescriptor{common{file: file}, desc, parent, nil}
+	return sl
+}
+
+// Return a slice of all the EnumDescriptors defined within this file
+func WrapEnumDescriptors(file *descriptor.FileDescriptorProto, descs []*Descriptor) []*EnumDescriptor {
+	sl := make([]*EnumDescriptor, 0, len(file.EnumType)+10)
+	for _, enum := range file.EnumType {
+		sl = AddEnumDescriptor(sl, enum, nil, file)
+	}
+	for _, nested := range descs {
+		sl = WrapEnumDescriptorsInMessage(sl, nested, file)
+	}
+	return sl
+}
+
+// Wrap this EnumDescriptor, recursively
+func WrapEnumDescriptorsInMessage(sl []*EnumDescriptor, desc *Descriptor, file *descriptor.FileDescriptorProto) []*EnumDescriptor {
+	for _, enum := range desc.EnumType {
+		sl = AddEnumDescriptor(sl, enum, desc, file)
+	}
+	for _, nested := range desc.nested {
+		sl = WrapEnumDescriptorsInMessage(sl, nested, file)
+	}
+	return sl
+}
+
+// Build the map from fully qualified type names to objects.  The key for the map
+// comes from the input data, which puts a period at the beginning.
+func (g *Generator) BuildTypeNameMap() {
+	g.typeNameToObject = make(map[string]Object)
+	for _, f := range g.allFiles {
+		dottedPkg := "." + f.originalPackageName() + "."
+		for _, enum := range f.enum {
+			name := dottedPkg + DottedSlice(enum.typeName())
+			g.typeNameToObject[name] = enum
+		}
+		for _, desc := range f.desc {
+			name := dottedPkg + DottedSlice(desc.typeName())
+			g.typeNameToObject[name] = desc
+		}
+	}
+}
+
+// Given a fully-qualified input type name, return the descriptor for the message or enum with that type.
+func (g *Generator) objectNamed(typeName string) Object {
+	f, ok := g.typeNameToObject[typeName]
+	if !ok {
+panicln()
+		g.fail("can't find object with type", typeName)
+	}
+	return f
+}
+
+// Print the arguments, handling indirections because they may be *string, etc.
+func (g *Generator) p(str ...interface{}) {
+	g.WriteString(g.indent)
+	for _, v := range str {
+		switch s := v.(type) {
+		case string:
+			g.WriteString(s)
+		case *string:
+			g.WriteString(*s)
+		case *int32:
+			g.WriteString(fmt.Sprintf("%d", *s))
+		default:
+			g.fail(fmt.Sprintf("unknown type in printer: %T", v))
+		}
+	}
+	g.WriteByte('\n')
+}
+
+// Indent the output one tab stop.
+func (g *Generator) in() { g.indent += "\t" }
+
+// Unindent the output one tab stop.
+func (g *Generator) out() {
+	if len(g.indent) > 0 {
+		g.indent = g.indent[1:]
+	}
+}
+
+// Generate the output for all the files we're generating output for.
+func (g *Generator) GenerateAllFiles() {
+	for i, file := range g.genFiles {
+		g.Reset()
+		g.Generate(file)
+		g.response.File[i] = plugin.NewCodeGeneratorResponse_File()
+		g.response.File[i].Name = proto.String(GoName(*file.Name))
+		g.response.File[i].Content = proto.String(g.String())
+	}
+}
+
+// Return the FileDescriptor for this FileDescriptorProto
+func (g *Generator) FileOf(fd *descriptor.FileDescriptorProto) *FileDescriptor {
+	for _, file := range g.allFiles {
+		if file.FileDescriptorProto == fd {
+			return file
+		}
+	}
+	g.fail("could not find file in table:", proto.GetString(fd.Name))
+	return nil
+}
+
+// Fill the response protocol buffer with the generated output for all the files we're
+// supposed to generate.
+func (g *Generator) Generate(file *FileDescriptor) {
+	g.file = g.FileOf(file.FileDescriptorProto)
+	g.GenerateHeader()
+	g.GenerateImports()
+	for _, enum := range g.file.enum {
+		g.GenerateEnum(enum)
+	}
+	for _, desc := range g.file.desc {
+		g.GenerateMessage(desc)
+	}
+	g.GenerateInitFunction()
+}
+
+// Generate the header, including package definition and imports
+func (g *Generator) GenerateHeader() {
+	g.p("// Code generated by protoc-gen-go from ", Quote(*g.file.Name))
+	g.p("// DO NOT EDIT!")
+	g.p()
+	g.p("package ", g.file.packageName())
+	g.p()
+}
+
+// Generate the header, including package definition and imports
+func (g *Generator) GenerateImports() {
+	if len(g.file.enum) > 0 {
+		g.p(`import "goprotobuf.googlecode.com/hg/proto"`)
+	}
+	for _, s := range g.file.Dependency {
+		// Need to find the descriptor for this file
+		for _, fd := range g.allFiles {
+			if proto.GetString(fd.Name) == s {
+				filename := GoName(s)
+				if strings.HasSuffix(filename, ".go") {
+					filename = filename[0:len(filename)-3]
+				}
+				g.p("import ", fd.packageName(), " ", Quote(filename))
+				break
+			}
+		}
+	}
+	g.p()
+}
+
+// Generate the enum definitions for this EnumDescriptor.
+func (g *Generator) GenerateEnum(enum *EnumDescriptor) {
+	// The full type name
+	typeName := enum.typeName()
+	// The full type name, CamelCased.
+	ccTypeName := CamelCaseSlice(typeName)
+	ccPrefix := enum.prefix()
+	g.p("type ", ccTypeName, " int32")
+	g.p("const (")
+	g.in()
+	for _, e := range enum.Value {
+		g.p(ccPrefix+*e.Name, " = ", e.Number)
+	}
+	g.out()
+	g.p(")")
+	g.p("var ", ccTypeName, "_name = map[int32] string {")
+	g.in()
+	generated := make(map[int32] bool)	// avoid duplicate values
+	for _, e := range enum.Value {
+		duplicate := ""
+		if _, present := generated[*e.Number]; present {
+			duplicate = "// Duplicate value: "
+		}
+		g.p(duplicate, e.Number, ": ", Quote(*e.Name), ",")
+		generated[*e.Number] = true
+	}
+	g.out()
+	g.p("}")
+	g.p("var ", ccTypeName, "_value = map[string] int32 {")
+	g.in()
+	for _, e := range enum.Value {
+		g.p(Quote(*e.Name), ": ", e.Number, ",")
+	}
+	g.out()
+	g.p("}")
+	g.p("func New", ccTypeName, "(x int32) *", ccTypeName, " {")
+	g.in()
+	g.p("e := ", ccTypeName, "(x)")
+	g.p("return &e")
+	g.out()
+	g.p("}")
+	g.p()
+}
+
+// The tag is a string like "PB(varint,2,opt,name=fieldname,def=7)" that
+// identifies details of the field for the protocol buffer marshaling and unmarshaling
+// code.  The fields are:
+//	wire encoding
+//	protocol tag number
+//	opt,req,rep for optional, required, or repeated
+//	name= the original declared name
+//	enum= the name of the enum type if it is an enum-typed field.
+//	def= string representation of the default value, if any.
+// The default value must be in a representation that can be used at run-time
+// to generate the default value. Thus bools become 0 and 1, for instance.
+func (g *Generator) GoTag(field *descriptor.FieldDescriptorProto, wiretype string) string {
+	optrepreq := ""
+	switch {
+	case IsOptional(field):
+		optrepreq = "opt"
+	case IsRequired(field):
+		optrepreq = "req"
+	case IsRepeated(field):
+		optrepreq = "rep"
+	}
+	defaultValue := proto.GetString(field.DefaultValue)
+	if defaultValue != "" {
+		switch *field.Type {
+		case descriptor.FieldDescriptorProto_TYPE_BOOL:
+			if defaultValue == "true" {
+				defaultValue = "1"
+			} else {
+				defaultValue = "0"
+			}
+		case descriptor.FieldDescriptorProto_TYPE_STRING,
+			descriptor.FieldDescriptorProto_TYPE_BYTES:
+			// Protect frogs.
+			defaultValue = Quote(defaultValue)
+			// Don't need the quotes
+			defaultValue = defaultValue[1 : len(defaultValue)-1]
+		case descriptor.FieldDescriptorProto_TYPE_ENUM:
+			// For enums we need to provide the integer constant.
+			obj := g.objectNamed(proto.GetString(field.TypeName))
+			enum, ok := obj.(*EnumDescriptor)
+			if !ok {
+				g.fail("enum type inconsistent for", CamelCaseSlice(obj.typeName()))
+			}
+			defaultValue = enum.integerValueAsString(defaultValue)
+		}
+		defaultValue = ",def=" + defaultValue
+	}
+	enum := ""
+	if *field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM {
+		obj := g.objectNamed(proto.GetString(field.TypeName))
+		enum = ",enum=" + obj.packageName() + "." + CamelCaseSlice(obj.typeName())
+	}
+	name := proto.GetString(field.Name)
+	if name == CamelCase(name) {
+		name = ""
+	} else {
+		name = ",name=" + name
+	}
+	return Quote(fmt.Sprintf("PB(%s,%d,%s%s%s%s)",
+		wiretype,
+		proto.GetInt32(field.Number),
+		optrepreq,
+		name,
+		enum,
+		defaultValue))
+}
+
+func NeedsStar(typ descriptor.FieldDescriptorProto_Type) bool {
+	switch typ {
+	case descriptor.FieldDescriptorProto_TYPE_GROUP:
+		return false
+	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
+		return false
+	case descriptor.FieldDescriptorProto_TYPE_BYTES:
+		return false
+	}
+	return true
+}
+
+// The type name appropriate for an item. If it's in the current file,
+// drop the package name and underscore the rest.
+// Otherwise it's from another package; use the underscored package name
+// followed by the field name.  The result has an initial capital.
+func (g *Generator) TypeName(obj Object) string {
+	return g.DefaultPackageName(obj) + CamelCaseSlice(obj.typeName())
+}
+
+// Like TypeName, but always includes the package name even if it's our own package.
+func (g *Generator) TypeNameWithPackage(obj Object) string {
+	return obj.packageName() + CamelCaseSlice(obj.typeName())
+}
+
+// Returns a string representing the type name, and the wire type
+func (g *Generator) GoType(message *Descriptor, field *descriptor.FieldDescriptorProto) (typ string, wire string) {
+	// TODO: Options.
+	switch *field.Type {
+	case descriptor.FieldDescriptorProto_TYPE_DOUBLE:
+		typ, wire = "float64", "fixed64"
+	case descriptor.FieldDescriptorProto_TYPE_FLOAT:
+		typ, wire = "float32", "fixed32"
+	case descriptor.FieldDescriptorProto_TYPE_INT64:
+		typ, wire = "int64", "varint"
+	case descriptor.FieldDescriptorProto_TYPE_UINT64:
+		typ, wire = "uint64", "varint"
+	case descriptor.FieldDescriptorProto_TYPE_INT32:
+		typ, wire = "int32", "varint"
+	case descriptor.FieldDescriptorProto_TYPE_UINT32:
+		typ, wire = "uint32", "varint"
+	case descriptor.FieldDescriptorProto_TYPE_FIXED64:
+		typ, wire = "uint64", "fixed64"
+	case descriptor.FieldDescriptorProto_TYPE_FIXED32:
+		typ, wire = "uint32", "fixed32"
+	case descriptor.FieldDescriptorProto_TYPE_BOOL:
+		typ, wire = "bool", "varint"
+	case descriptor.FieldDescriptorProto_TYPE_STRING:
+		typ, wire = "string", "bytes"
+	case descriptor.FieldDescriptorProto_TYPE_GROUP:
+		desc := g.objectNamed(proto.GetString(field.TypeName))
+		typ, wire = "*"+g.TypeName(desc), "group"
+	case descriptor.FieldDescriptorProto_TYPE_MESSAGE:
+		desc := g.objectNamed(proto.GetString(field.TypeName))
+		typ, wire = "*"+g.TypeName(desc), "bytes"
+	case descriptor.FieldDescriptorProto_TYPE_BYTES:
+		typ, wire = "[]byte", "bytes"
+	case descriptor.FieldDescriptorProto_TYPE_ENUM:
+		desc := g.objectNamed(proto.GetString(field.TypeName))
+		typ, wire = g.TypeName(desc), "varint"
+	case descriptor.FieldDescriptorProto_TYPE_SFIXED32:
+		typ, wire = "int32", "fixed32"
+	case descriptor.FieldDescriptorProto_TYPE_SFIXED64:
+		typ, wire = "int64", "fixed64"
+	case descriptor.FieldDescriptorProto_TYPE_SINT32:
+		typ, wire = "int32", "zigzag32"
+	case descriptor.FieldDescriptorProto_TYPE_SINT64:
+		typ, wire = "int64", "zigzag64"
+	default:
+		g.fail("unknown type for", proto.GetString(field.Name))
+	}
+	if IsRepeated(field) {
+		typ = "[]" + typ
+	} else if NeedsStar(*field.Type) {
+		typ = "*" + typ
+	}
+	return
+}
+
+// Generate the type and default constant definitions for this Descriptor.
+func (g *Generator) GenerateMessage(message *Descriptor) {
+	// The full type name
+	typeName := message.typeName()
+	// The full type name, CamelCased.
+	ccTypeName := CamelCaseSlice(typeName)
+
+	g.p("type ", ccTypeName, " struct {")
+	g.in()
+	for _, field := range message.Field {
+		fieldname := CamelCase(*field.Name)
+		typename, wiretype := g.GoType(message, field)
+		tag := g.GoTag(field, wiretype)
+		g.p(fieldname, "\t", typename, "\t", tag)
+	}
+	g.p("XXX_unrecognized\t[]byte")
+	g.out()
+	g.p("}")
+
+	// Reset and New functions
+	g.p("func (this *", ccTypeName, ") Reset() {")
+	g.in()
+	g.p("*this = ", ccTypeName, "{}")
+	g.out()
+	g.p("}")
+	g.p("func New", ccTypeName, "() *", ccTypeName, " {")
+	g.in()
+	g.p("return new(", ccTypeName, ")")
+	g.out()
+	g.p("}")
+
+	// Default constants
+	for _, field := range message.Field {
+		def := proto.GetString(field.DefaultValue)
+		if def == "" {
+			continue
+		}
+		fieldname := "Default_" + ccTypeName + "_" + CamelCase(*field.Name)
+		typename, _ := g.GoType(message, field)
+		if typename[0] == '*' {
+			typename = typename[1:]
+		}
+		kind := "const "
+		switch {
+		case typename == "bool":
+		case typename == "string":
+			def = Quote(def)
+		case typename == "[]byte":
+			def = "[]byte(" + Quote(def) + ")"
+			kind = "var "
+		case 	*field.Type == descriptor.FieldDescriptorProto_TYPE_ENUM:
+			// Must be an enum.  Need to construct the prefixed name.
+			obj := g.objectNamed(proto.GetString(field.TypeName))
+			enum, ok := obj.(*EnumDescriptor)
+			if !ok {
+				log.Stderr("don't know how to generate constant for", fieldname)
+				continue
+			}
+			def = enum.prefix() + def
+		}
+		g.p(kind, fieldname, " ", typename, " = ", def)
+	}
+	g.p()
+}
+
+func (g *Generator) GenerateInitFunction() {
+	g.p("func init() {")
+	g.in()
+	for _, enum := range g.file.enum {
+		g.GenerateEnumRegistration(enum)
+	}
+	g.out()
+	g.p("}")
+}
+
+func (g *Generator) GenerateEnumRegistration(enum *EnumDescriptor) {
+	pkg := g.packageName + "." // We always print the full package name here.
+	// The full type name
+	typeName := enum.typeName()
+	// The full type name, CamelCased.
+	ccTypeName := CamelCaseSlice(typeName)
+	g.p("proto.RegisterEnum(", Quote(pkg+ccTypeName), ", ", ccTypeName+"_name, ", ccTypeName+"_value)")
+}
+
+// And now lots of helper functions.
+
+// Return change foo_bar_Baz to FooBar_Baz.
+func CamelCase(name string) string {
+	elems := strings.Split(name, "_", 0)
+	for i, e := range elems {
+		if e == "" {
+			elems[i] = "_"
+			continue
+		}
+		runes := []int(e)
+		if unicode.IsLower(runes[0]) {
+			runes[0] = unicode.ToUpper(runes[0])
+			elems[i] = string(runes)
+		} else {
+			if i > 0 {
+				elems[i] = "_" + e
+			}
+		}
+	}
+	s := strings.Join(elems, "")
+	// Name must not begin with an underscore.
+	if len(s) > 0 && s[0] == '_' {
+		s = "X" + s[1:]
+	}
+	return s
+}
+
+// Like CamelCase, but the argument is a slice of strings to
+// be concatenated with "_"
+func CamelCaseSlice(elem []string) string { return CamelCase(strings.Join(elem, "_")) }
+
+// Turn a sliced name into a dotted name
+func DottedSlice(elem []string) string { return strings.Join(elem, ".") }
+
+// Return a Go-source quoted string representation of s.
+func Quote(s string) string { return fmt.Sprintf("%q", s) }
+
+// Given a .proto file name, return the output name for the generated Go program.
+func GoName(name string) string {
+	if strings.HasSuffix(name, ".proto") {
+		name = name[0 : len(name)-6]
+	}
+	return name + ".pb.go"
+}
+
+// Is this field optional?
+func IsOptional(field *descriptor.FieldDescriptorProto) bool {
+	return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_OPTIONAL
+}
+
+// Is this field required?
+func IsRequired(field *descriptor.FieldDescriptorProto) bool {
+	return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REQUIRED
+}
+
+// Is this field repeated?
+func IsRepeated(field *descriptor.FieldDescriptorProto) bool {
+	return field.Label != nil && *field.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED
+}
+
+// Mapping function used to generate Go names from package names, which can be dotted.
+func DotToUnderscore(rune int) int {
+	if rune == '.' {
+		return '_'
+	}
+	return rune
+}
diff --git a/compiler/plugin/Makefile b/compiler/plugin/Makefile
new file mode 100644
index 0000000..08be77f
--- /dev/null
+++ b/compiler/plugin/Makefile
@@ -0,0 +1,54 @@
+# Go support for Protocol Buffers - Google's data interchange format
+#
+# Copyright 2010 Google Inc.  All rights reserved.
+# http://code.google.com/p/goprotobuf/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=goprotobuf.googlecode.com/hg/compiler/plugin
+GOFILES=\
+	plugin.pb.go\
+
+include $(GOROOT)/src/Make.pkg
+
+# Not stored here, but plugin.proto is in http://code.google.com/p/protobuf
+# at protobuf-2.3.0/src/google/protobuf/compiler/plugin.proto
+# Also we need to fix an import.
+regenerate:
+	echo WARNING! THIS RULE IS PROBABLY NOT RIGHT FOR YOUR INSTALLATION
+	cd $(HOME)/protobuf-2.3.0/src && \
+	protoc --go_out=. ./google/protobuf/compiler/plugin.proto && \
+	cat ./google/protobuf/compiler/plugin.pb.go | \
+		sed '/^import/s;google/protobuf/descriptor.pb;goprotobuf.googlecode.com/hg/compiler/descriptor;' >$(GOROOT)/src/pkg/goprotobuf.googlecode.com/hg/compiler/plugin/plugin.pb.go
+
+restore:
+	cp plugin.pb.golden plugin.pb.go
+
+preserve:
+	cp plugin.pb.go plugin.pb.golden
diff --git a/compiler/plugin/plugin.pb.go b/compiler/plugin/plugin.pb.go
new file mode 100644
index 0000000..1c11686
--- /dev/null
+++ b/compiler/plugin/plugin.pb.go
@@ -0,0 +1,47 @@
+// Code generated by protoc-gen-go from "google/protobuf/compiler/plugin.proto"
+// DO NOT EDIT!
+
+package google_protobuf_compiler
+
+import google_protobuf "goprotobuf.googlecode.com/hg/compiler/descriptor"
+
+type CodeGeneratorRequest struct {
+	FileToGenerate	[]string	"PB(bytes,1,rep,name=file_to_generate)"
+	Parameter	*string	"PB(bytes,2,opt,name=parameter)"
+	ProtoFile	[]*google_protobuf.FileDescriptorProto	"PB(bytes,15,rep,name=proto_file)"
+	XXX_unrecognized	[]byte
+}
+func (this *CodeGeneratorRequest) Reset() {
+	*this = CodeGeneratorRequest{}
+}
+func NewCodeGeneratorRequest() *CodeGeneratorRequest {
+	return new(CodeGeneratorRequest)
+}
+
+type CodeGeneratorResponse struct {
+	Error	*string	"PB(bytes,1,opt,name=error)"
+	File	[]*CodeGeneratorResponse_File	"PB(bytes,15,rep,name=file)"
+	XXX_unrecognized	[]byte
+}
+func (this *CodeGeneratorResponse) Reset() {
+	*this = CodeGeneratorResponse{}
+}
+func NewCodeGeneratorResponse() *CodeGeneratorResponse {
+	return new(CodeGeneratorResponse)
+}
+
+type CodeGeneratorResponse_File struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	InsertionPoint	*string	"PB(bytes,2,opt,name=insertion_point)"
+	Content	*string	"PB(bytes,15,opt,name=content)"
+	XXX_unrecognized	[]byte
+}
+func (this *CodeGeneratorResponse_File) Reset() {
+	*this = CodeGeneratorResponse_File{}
+}
+func NewCodeGeneratorResponse_File() *CodeGeneratorResponse_File {
+	return new(CodeGeneratorResponse_File)
+}
+
+func init() {
+}
diff --git a/compiler/plugin/plugin.pb.golden b/compiler/plugin/plugin.pb.golden
new file mode 100644
index 0000000..1c11686
--- /dev/null
+++ b/compiler/plugin/plugin.pb.golden
@@ -0,0 +1,47 @@
+// Code generated by protoc-gen-go from "google/protobuf/compiler/plugin.proto"
+// DO NOT EDIT!
+
+package google_protobuf_compiler
+
+import google_protobuf "goprotobuf.googlecode.com/hg/compiler/descriptor"
+
+type CodeGeneratorRequest struct {
+	FileToGenerate	[]string	"PB(bytes,1,rep,name=file_to_generate)"
+	Parameter	*string	"PB(bytes,2,opt,name=parameter)"
+	ProtoFile	[]*google_protobuf.FileDescriptorProto	"PB(bytes,15,rep,name=proto_file)"
+	XXX_unrecognized	[]byte
+}
+func (this *CodeGeneratorRequest) Reset() {
+	*this = CodeGeneratorRequest{}
+}
+func NewCodeGeneratorRequest() *CodeGeneratorRequest {
+	return new(CodeGeneratorRequest)
+}
+
+type CodeGeneratorResponse struct {
+	Error	*string	"PB(bytes,1,opt,name=error)"
+	File	[]*CodeGeneratorResponse_File	"PB(bytes,15,rep,name=file)"
+	XXX_unrecognized	[]byte
+}
+func (this *CodeGeneratorResponse) Reset() {
+	*this = CodeGeneratorResponse{}
+}
+func NewCodeGeneratorResponse() *CodeGeneratorResponse {
+	return new(CodeGeneratorResponse)
+}
+
+type CodeGeneratorResponse_File struct {
+	Name	*string	"PB(bytes,1,opt,name=name)"
+	InsertionPoint	*string	"PB(bytes,2,opt,name=insertion_point)"
+	Content	*string	"PB(bytes,15,opt,name=content)"
+	XXX_unrecognized	[]byte
+}
+func (this *CodeGeneratorResponse_File) Reset() {
+	*this = CodeGeneratorResponse_File{}
+}
+func NewCodeGeneratorResponse_File() *CodeGeneratorResponse_File {
+	return new(CodeGeneratorResponse_File)
+}
+
+func init() {
+}
diff --git a/compiler/testdata/Makefile b/compiler/testdata/Makefile
new file mode 100644
index 0000000..0cc9ad1
--- /dev/null
+++ b/compiler/testdata/Makefile
@@ -0,0 +1,63 @@
+# Go support for Protocol Buffers - Google's data interchange format
+#
+# Copyright 2010 Google Inc.  All rights reserved.
+# http://code.google.com/p/goprotobuf/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+include $(GOROOT)/src/Make.$(GOARCH)
+
+all:
+	@echo run make test
+
+include $(GOROOT)/src/Make.common
+include $(GOROOT)/src/pkg/goprotobuf.googlecode.com/hg/Make.protobuf
+
+CLEANFILES+=*.pb.go
+
+test:	golden testbuild
+	@echo PASS
+
+golden:
+	$(QUOTED_GOBIN)/gomake -B test.pb.go
+	diff test.pb.go test.pb.go.golden
+
+nuke:	clean
+
+testbuild:	main.$O
+	$(LD) -L. main.$O
+
+multi.a: multi3.pb.$O multi2.pb.$O multi1.pb.$O
+	rm -f multi.a
+	$(QUOTED_GOBIN)/gopack grc $@ $<
+
+%.$O:	%.go
+	$(QUOTED_GOBIN)/$(GC) -I . -o $@ $<
+
+test.pb.go:	imp.pb.go
+multi1.pb.go:	multi2.pb.go multi3.pb.go
+main.$O: imp.pb.$O test.pb.$O multi.a
diff --git a/compiler/testdata/imp.proto b/compiler/testdata/imp.proto
new file mode 100644
index 0000000..beb6805
--- /dev/null
+++ b/compiler/testdata/imp.proto
@@ -0,0 +1,41 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package imp;
+
+message ImportedMessage {
+  required int64 field = 1;
+
+  enum Owner {
+    DAVE = 1;
+    MIKE = 2;
+  }
+}
diff --git a/compiler/testdata/main.go b/compiler/testdata/main.go
new file mode 100644
index 0000000..29100be
--- /dev/null
+++ b/compiler/testdata/main.go
@@ -0,0 +1,44 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A simple binary to link together the protocol buffers in this test.
+
+package main
+
+import (
+	"./test.pb"
+	"./multi1.pb"
+)
+
+func main() {
+	_ = my_test.NewRequest()
+	_ = multitest.NewMulti1()
+}
diff --git a/compiler/testdata/multi1.proto b/compiler/testdata/multi1.proto
new file mode 100644
index 0000000..47a4d2f
--- /dev/null
+++ b/compiler/testdata/multi1.proto
@@ -0,0 +1,42 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import "multi2.proto";
+import "multi3.proto";
+
+package multitest;
+
+message Multi1 {
+  required Multi2 multi2 = 1;
+  optional Multi2.Color color = 2;
+  optional Multi3.HatType hat_type = 3;
+}
+
diff --git a/compiler/testdata/multi2.proto b/compiler/testdata/multi2.proto
new file mode 100644
index 0000000..6bb76f9
--- /dev/null
+++ b/compiler/testdata/multi2.proto
@@ -0,0 +1,44 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package multitest;
+
+message Multi2 {
+  required int32 required_value = 1;
+
+  enum Color {
+    BLUE = 1;
+    GREEN = 2;
+    RED = 3;
+  };
+  optional Color color = 2;
+}
+
diff --git a/compiler/testdata/multi3.proto b/compiler/testdata/multi3.proto
new file mode 100644
index 0000000..191fefd
--- /dev/null
+++ b/compiler/testdata/multi3.proto
@@ -0,0 +1,41 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package multitest;
+
+message Multi3 {
+  enum HatType {
+    FEDORA = 1;
+    FEZ = 2;
+  };
+  optional HatType hat_type = 1;
+}
+
diff --git a/compiler/testdata/test.pb.go.golden b/compiler/testdata/test.pb.go.golden
new file mode 100644
index 0000000..0d7a7cb
--- /dev/null
+++ b/compiler/testdata/test.pb.go.golden
@@ -0,0 +1,124 @@
+// Code generated by protoc-gen-go from "test.proto"
+// DO NOT EDIT!
+
+package my_test
+
+import "goprotobuf.googlecode.com/hg/proto"
+import imp "imp.pb"
+
+type HatType int32
+const (
+	HatType_FEDORA = 1
+	HatType_FEZ = 2
+)
+var HatType_name = map[int32] string {
+	1: "FEDORA",
+	2: "FEZ",
+}
+var HatType_value = map[string] int32 {
+	"FEDORA": 1,
+	"FEZ": 2,
+}
+func NewHatType(x int32) *HatType {
+	e := HatType(x)
+	return &e
+}
+
+type Days int32
+const (
+	Days_MONDAY = 1
+	Days_TUESDAY = 2
+	Days_LUNDI = 1
+)
+var Days_name = map[int32] string {
+	1: "MONDAY",
+	2: "TUESDAY",
+	// Duplicate value: 1: "LUNDI",
+}
+var Days_value = map[string] int32 {
+	"MONDAY": 1,
+	"TUESDAY": 2,
+	"LUNDI": 1,
+}
+func NewDays(x int32) *Days {
+	e := Days(x)
+	return &e
+}
+
+type Request_Color int32
+const (
+	Request_RED = 0
+	Request_GREEN = 1
+	Request_BLUE = 2
+)
+var Request_Color_name = map[int32] string {
+	0: "RED",
+	1: "GREEN",
+	2: "BLUE",
+}
+var Request_Color_value = map[string] int32 {
+	"RED": 0,
+	"GREEN": 1,
+	"BLUE": 2,
+}
+func NewRequest_Color(x int32) *Request_Color {
+	e := Request_Color(x)
+	return &e
+}
+
+type Request struct {
+	Key	[]int64	"PB(varint,1,rep,name=key)"
+	ImportedMessage	*imp.ImportedMessage	"PB(bytes,2,opt,name=imported_message)"
+	Hue	*Request_Color	"PB(varint,3,opt,name=hue,enum=my_test.Request_Color)"
+	Hat	*HatType	"PB(varint,4,opt,name=hat,enum=my_test.HatType,def=1)"
+	Owner	*imp.ImportedMessage_Owner	"PB(varint,6,opt,name=owner,enum=imp.ImportedMessage_Owner)"
+	XXX_unrecognized	[]byte
+}
+func (this *Request) Reset() {
+	*this = Request{}
+}
+func NewRequest() *Request {
+	return new(Request)
+}
+const Default_Request_Hat HatType = HatType_FEDORA
+
+type Reply struct {
+	Found	[]*Reply_Entry	"PB(bytes,1,rep,name=found)"
+	XXX_unrecognized	[]byte
+}
+func (this *Reply) Reset() {
+	*this = Reply{}
+}
+func NewReply() *Reply {
+	return new(Reply)
+}
+
+type Reply_Entry struct {
+	KeyThatNeeds_1234camel_CasIng	*int64	"PB(varint,1,req,name=key_that_needs_1234camel_CasIng)"
+	Value	*int64	"PB(varint,2,opt,name=value,def=7)"
+	XMyFieldName_2	*int64	"PB(varint,3,opt,name=_my_field_name_2)"
+	XXX_unrecognized	[]byte
+}
+func (this *Reply_Entry) Reset() {
+	*this = Reply_Entry{}
+}
+func NewReply_Entry() *Reply_Entry {
+	return new(Reply_Entry)
+}
+const Default_Reply_Entry_Value int64 = 7
+
+type ReplyExtensions struct {
+	XXX_unrecognized	[]byte
+}
+func (this *ReplyExtensions) Reset() {
+	*this = ReplyExtensions{}
+}
+func NewReplyExtensions() *ReplyExtensions {
+	return new(ReplyExtensions)
+}
+
+func init() {
+	proto.RegisterEnum("my_test.HatType", HatType_name, HatType_value)
+	proto.RegisterEnum("my_test.Days", Days_name, Days_value)
+	proto.RegisterEnum("my_test.Request_Color", Request_Color_name, Request_Color_value)
+}
diff --git a/compiler/testdata/test.proto b/compiler/testdata/test.proto
new file mode 100644
index 0000000..f7e7a3d
--- /dev/null
+++ b/compiler/testdata/test.proto
@@ -0,0 +1,75 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package my.test;  // dotted package name
+
+import "imp.proto";
+
+enum HatType {
+  // deliberately skipping 0
+  FEDORA = 1;
+  FEZ = 2;
+}
+
+enum Days {
+  MONDAY = 1;
+  TUESDAY = 2;
+  LUNDI = 1;  // same value as MONDAY
+}
+
+message Request {
+  enum Color {
+    RED = 0;
+    GREEN = 1;
+    BLUE = 2;
+  }
+  repeated int64 key = 1;
+  optional imp.ImportedMessage imported_message = 2;
+  optional Color hue = 3;
+  optional HatType hat = 4 [default=FEDORA];
+  optional imp.ImportedMessage.Owner owner = 6;
+}
+
+message Reply {
+  message Entry {
+    required int64 key_that_needs_1234camel_CasIng = 1;
+    optional int64 value = 2 [default=7];
+    optional int64 _my_field_name_2 = 3;
+  }
+  repeated Entry found = 1;
+  extensions 100 to max;
+}
+
+message ReplyExtensions {
+  extend Reply {
+    optional double time = 101;
+  }
+}
diff --git a/proto/Makefile b/proto/Makefile
new file mode 100644
index 0000000..e9a5ce4
--- /dev/null
+++ b/proto/Makefile
@@ -0,0 +1,45 @@
+# Go support for Protocol Buffers - Google's data interchange format
+#
+# Copyright 2010 Google Inc.  All rights reserved.
+# http://code.google.com/p/goprotobuf/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=goprotobuf.googlecode.com/hg/proto
+GOFILES=\
+	encode.go\
+	decode.go\
+	extensions.go\
+	lib.go\
+	properties.go\
+	text.go\
+	text_parser.go\
+
+include $(GOROOT)/src/Make.pkg
diff --git a/proto/all_test.go b/proto/all_test.go
new file mode 100644
index 0000000..83a0638
--- /dev/null
+++ b/proto/all_test.go
@@ -0,0 +1,1042 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// We need to compile the .pb.gos, which import this package, so
+// to run the test we must make install here and then make in the
+// testdata directory.
+// gotest: make install && cd testdata && make nuke && make
+
+package proto_test
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+
+	. "goprotobuf.googlecode.com/hg/proto"
+	. "./testdata/_obj/test_proto"
+)
+
+var globalO *Buffer
+
+func old() *Buffer {
+	if globalO == nil {
+		globalO = NewBuffer(nil)
+	}
+	globalO.Reset()
+	return globalO
+}
+
+func equalbytes(b1, b2 []byte, t *testing.T) {
+	if len(b1) != len(b2) {
+		t.Errorf("wrong lengths: 2*%d != %d", len(b1), len(b2))
+		return
+	}
+	for i := 0; i < len(b1); i++ {
+		if b1[i] != b2[i] {
+			t.Errorf("bad byte[%d]:%x %x: %s %s", i, b1[i], b2[i], b1, b2)
+		}
+	}
+}
+
+func initGoTestField() *GoTestField {
+	f := NewGoTestField()
+	f.Label = String("label")
+	f.Type = String("type")
+	return f
+}
+
+// These are all structurally equivalent but the tag numbers differ.
+// (It's remarkable that required, optional, and repeated all have
+// 8 letters.)
+func initGoTest_RequiredGroup() *GoTest_RequiredGroup {
+	f := NewGoTest_RequiredGroup()
+	f.RequiredField = String("required")
+	return f
+}
+
+func initGoTest_OptionalGroup() *GoTest_OptionalGroup {
+	f := NewGoTest_OptionalGroup()
+	f.RequiredField = String("optional")
+	return f
+}
+
+func initGoTest_RepeatedGroup() *GoTest_RepeatedGroup {
+	f := NewGoTest_RepeatedGroup()
+	f.RequiredField = String("repeated")
+	return f
+}
+
+func initGoTest(setdefaults bool) *GoTest {
+	pb := NewGoTest()
+	if setdefaults {
+		pb.F_BoolDefaulted = Bool(Default_GoTest_F_BoolDefaulted)
+		pb.F_Int32Defaulted = Int32(Default_GoTest_F_Int32Defaulted)
+		pb.F_Int64Defaulted = Int64(Default_GoTest_F_Int64Defaulted)
+		pb.F_Fixed32Defaulted = Uint32(Default_GoTest_F_Fixed32Defaulted)
+		pb.F_Fixed64Defaulted = Uint64(Default_GoTest_F_Fixed64Defaulted)
+		pb.F_Uint32Defaulted = Uint32(Default_GoTest_F_Uint32Defaulted)
+		pb.F_Uint64Defaulted = Uint64(Default_GoTest_F_Uint64Defaulted)
+		pb.F_FloatDefaulted = Float32(Default_GoTest_F_FloatDefaulted)
+		pb.F_DoubleDefaulted = Float64(Default_GoTest_F_DoubleDefaulted)
+		pb.F_StringDefaulted = String(Default_GoTest_F_StringDefaulted)
+		pb.F_BytesDefaulted = Default_GoTest_F_BytesDefaulted
+		pb.F_Sint32Defaulted = Int32(Default_GoTest_F_Sint32Defaulted)
+		pb.F_Sint64Defaulted = Int64(Default_GoTest_F_Sint64Defaulted)
+	}
+
+	pb.Kind = Int32(GoTest_TIME)
+	pb.RequiredField = initGoTestField()
+	pb.F_BoolRequired = Bool(true)
+	pb.F_Int32Required = Int32(3)
+	pb.F_Int64Required = Int64(6)
+	pb.F_Fixed32Required = Uint32(32)
+	pb.F_Fixed64Required = Uint64(64)
+	pb.F_Uint32Required = Uint32(3232)
+	pb.F_Uint64Required = Uint64(6464)
+	pb.F_FloatRequired = Float32(3232)
+	pb.F_DoubleRequired = Float64(6464)
+	pb.F_StringRequired = String("string")
+	pb.F_BytesRequired = []byte("bytes")
+	pb.F_Sint32Required = Int32(-32)
+	pb.F_Sint64Required = Int64(-64)
+	pb.Requiredgroup = initGoTest_RequiredGroup()
+
+	return pb
+}
+
+func fail(msg string, b *bytes.Buffer, s string, t *testing.T) {
+	data := b.Bytes()
+	ld := len(data)
+	ls := len(s) / 2
+
+	fmt.Printf("fail %s ld=%d ls=%d\n", msg, ld, ls)
+
+	// find the interesting spot - n
+	n := ls
+	if ld < ls {
+		n = ld
+	}
+	j := 0
+	for i := 0; i < n; i++ {
+		bs := hex(s[j])*16 + hex(s[j+1])
+		j += 2
+		if data[i] == bs {
+			continue
+		}
+		n = i
+		break
+	}
+	l := n - 10
+	if l < 0 {
+		l = 0
+	}
+	h := n + 10
+
+	// find the interesting spot - n
+	fmt.Printf("is[%d]:", l)
+	for i := l; i < h; i++ {
+		if i >= ld {
+			fmt.Printf(" --")
+			continue
+		}
+		fmt.Printf(" %.2x", data[i])
+	}
+	fmt.Printf("\n")
+
+	fmt.Printf("sb[%d]:", l)
+	for i := l; i < h; i++ {
+		if i >= ls {
+			fmt.Printf(" --")
+			continue
+		}
+		bs := hex(s[j])*16 + hex(s[j+1])
+		j += 2
+		fmt.Printf(" %.2x", bs)
+	}
+	fmt.Printf("\n")
+
+	t.Fail()
+
+
+	//	t.Errorf("%s: \ngood: %s\nbad: %x", msg, s, b.Bytes())
+	// Print the output in a partially-decoded format; can
+	// be helpful when updating the test.  It produces the output
+	// that is pasted, with minor edits, into the argument to verify().
+	//	data := b.Bytes()
+	//	nesting := 0
+	//	for b.Len() > 0 {
+	//		start := len(data) - b.Len()
+	//		var u uint64
+	//		u, err := DecodeVarint(b)
+	//		if err != nil {
+	//			fmt.Printf("decode error on varint:", err)
+	//			return
+	//		}
+	//		wire := u & 0x7
+	//		tag := u >> 3
+	//		switch wire {
+	//		case WireVarint:
+	//			v, err := DecodeVarint(b)
+	//			if err != nil {
+	//				fmt.Printf("decode error on varint:", err)
+	//				return
+	//			}
+	//			fmt.Printf("\t\t\"%x\"  // field %d, encoding %d, value %d\n",
+	//				data[start:len(data)-b.Len()], tag, wire, v)
+	//		case WireFixed32:
+	//			v, err := DecodeFixed32(b)
+	//			if err != nil {
+	//				fmt.Printf("decode error on fixed32:", err)
+	//				return
+	//			}
+	//			fmt.Printf("\t\t\"%x\"  // field %d, encoding %d, value %d\n",
+	//				data[start:len(data)-b.Len()], tag, wire, v)
+	//		case WireFixed64:
+	//			v, err := DecodeFixed64(b)
+	//			if err != nil {
+	//				fmt.Printf("decode error on fixed64:", err)
+	//				return
+	//			}
+	//			fmt.Printf("\t\t\"%x\"  // field %d, encoding %d, value %d\n",
+	//				data[start:len(data)-b.Len()], tag, wire, v)
+	//		case WireBytes:
+	//			nb, err := DecodeVarint(b)
+	//			if err != nil {
+	//				fmt.Printf("decode error on bytes:", err)
+	//				return
+	//			}
+	//			after_tag := len(data) - b.Len()
+	//			str := make([]byte, nb)
+	//			_, err = b.Read(str)
+	//			if err != nil {
+	//				fmt.Printf("decode error on bytes:", err)
+	//				return
+	//			}
+	//			fmt.Printf("\t\t\"%x\" \"%x\"  // field %d, encoding %d (FIELD)\n",
+	//				data[start:after_tag], str, tag, wire)
+	//		case WireStartGroup:
+	//			nesting++
+	//			fmt.Printf("\t\t\"%x\"\t\t// start group field %d level %d\n",
+	//				data[start:len(data)-b.Len()], tag, nesting)
+	//		case WireEndGroup:
+	//			fmt.Printf("\t\t\"%x\"\t\t// end group field %d level %d\n",
+	//				data[start:len(data)-b.Len()], tag, nesting)
+	//			nesting--
+	//		default:
+	//			fmt.Printf("unrecognized wire type %d\n", wire)
+	//			return
+	//		}
+	//	}
+}
+
+func hex(c uint8) uint8 {
+	if '0' <= c && c <= '9' {
+		return c - '0'
+	}
+	if 'a' <= c && c <= 'f' {
+		return 10 + c - 'a'
+	}
+	if 'A' <= c && c <= 'F' {
+		return 10 + c - 'A'
+	}
+	return 0
+}
+
+func equal(b []byte, s string, t *testing.T) bool {
+	if 2*len(b) != len(s) {
+		//		fail(fmt.Sprintf("wrong lengths: 2*%d != %d", len(b), len(s)), b, s, t)
+		fmt.Printf("wrong lengths: 2*%d != %d\n", len(b), len(s))
+		return false
+	}
+	for i, j := 0, 0; i < len(b); i, j = i+1, j+2 {
+		x := hex(s[j])*16 + hex(s[j+1])
+		if b[i] != x {
+			//			fail(fmt.Sprintf("bad byte[%d]:%x %x", i, b[i], x), b, s, t)
+			fmt.Printf("bad byte[%d]:%x %x", i, b[i], x)
+			return false
+		}
+	}
+	return true
+}
+
+func overify(t *testing.T, pb *GoTest, expected string) {
+	o := old()
+	err := o.Marshal(pb)
+	if err != nil {
+		fmt.Printf("overify marshal-1 err = %v", err)
+		o.DebugPrint("", o.Bytes())
+		t.Fatalf("expected = %s", expected)
+	}
+	if !equal(o.Bytes(), expected, t) {
+		o.DebugPrint("overify neq 1", o.Bytes())
+		t.Fatalf("expected = %s", expected)
+	}
+
+	// Now test Unmarshal by recreating the original buffer.
+	pbd := NewGoTest()
+	err = o.Unmarshal(pbd)
+	if err != nil {
+		t.Fatalf("overify unmarshal err = %v", err)
+		o.DebugPrint("", o.Bytes())
+		t.Fatalf("string = %s", expected)
+	}
+	o.Reset()
+	err = o.Marshal(pbd)
+	if err != nil {
+		t.Errorf("overify marshal-2 err = %v", err)
+		o.DebugPrint("", o.Bytes())
+		t.Fatalf("string = %s", expected)
+	}
+	if !equal(o.Bytes(), expected, t) {
+		o.DebugPrint("overify neq 2", o.Bytes())
+		t.Fatalf("string = %s", expected)
+	}
+}
+
+// Simple tests for numeric encode/decode primitives (varint, etc.)
+func TestNumericPrimitives(t *testing.T) {
+	for i := uint64(0); i < 1e6; i += 111 {
+		o := old()
+		if o.EncodeVarint(i) != nil {
+			t.Error("EncodeVarint")
+			break
+		}
+		x, e := o.DecodeVarint()
+		if e != nil {
+			t.Fatal("DecodeVarint")
+		}
+		if x != i {
+			t.Fatal("varint decode fail:", i, x)
+		}
+
+		o = old()
+		if o.EncodeFixed32(i) != nil {
+			t.Fatal("encFixed32")
+		}
+		x, e = o.DecodeFixed32()
+		if e != nil {
+			t.Fatal("decFixed32")
+		}
+		if x != i {
+			t.Fatal("fixed32 decode fail:", i, x)
+		}
+
+		o = old()
+		if o.EncodeFixed64(i*1234567) != nil {
+			t.Error("encFixed64")
+			break
+		}
+		x, e = o.DecodeFixed64()
+		if e != nil {
+			t.Error("decFixed64")
+			break
+		}
+		if x != i*1234567 {
+			t.Error("fixed64 decode fail:", i*1234567, x)
+			break
+		}
+
+		o = old()
+		i32 := int32(i - 12345)
+		if o.EncodeZigzag32(uint64(i32)) != nil {
+			t.Fatal("EncodeZigzag32")
+		}
+		x, e = o.DecodeZigzag32()
+		if e != nil {
+			t.Fatal("DecodeZigzag32")
+		}
+		if x != uint64(uint32(i32)) {
+			t.Fatal("zigzag32 decode fail:", i32, x)
+		}
+
+		o = old()
+		i64 := int64(i - 12345)
+		if o.EncodeZigzag64(uint64(i64)) != nil {
+			t.Fatal("EncodeZigzag64")
+		}
+		x, e = o.DecodeZigzag64()
+		if e != nil {
+			t.Fatal("DecodeZigzag64")
+		}
+		if x != uint64(i64) {
+			t.Fatal("zigzag64 decode fail:", i64, x)
+		}
+	}
+}
+
+// Simple tests for bytes
+func TestBytesPrimitives(t *testing.T) {
+	o := old()
+	bytes := []byte{'n', 'o', 'w', ' ', 'i', 's', ' ', 't', 'h', 'e', ' ', 't', 'i', 'm', 'e'}
+	if o.EncodeRawBytes(bytes) != nil {
+		t.Error("EncodeRawBytes")
+	}
+	decb, e := o.DecodeRawBytes(false)
+	if e != nil {
+		t.Error("DecodeRawBytes")
+	}
+	equalbytes(bytes, decb, t)
+}
+
+// Simple tests for strings
+func TestStringPrimitives(t *testing.T) {
+	o := old()
+	s := "now is the time"
+	if o.EncodeStringBytes(s) != nil {
+		t.Error("enc_string")
+	}
+	decs, e := o.DecodeStringBytes()
+	if e != nil {
+		t.Error("dec_string")
+	}
+	if s != decs {
+		t.Error("string encode/decode fail:", s, decs)
+	}
+}
+
+// Do we catch the "required bit not set" case?
+func TestRequiredBit(t *testing.T) {
+	o := old()
+	pb := NewGoTest()
+	if o.Marshal(pb) != ErrRequiredNotSet {
+		t.Errorf("did not catch missing required fields")
+	}
+}
+
+// Check that all fields are nil.
+// Clearly silly, and a residue from a more interesting test with an earlier,
+// different initialization property, but it once caught a compiler bug so
+// it lives.
+func checkInitialized(pb *GoTest, t *testing.T) {
+	if pb.F_BoolDefaulted != nil {
+		t.Error("New or Reset did not set boolean:", *pb.F_BoolDefaulted)
+	}
+	if pb.F_Int32Defaulted != nil {
+		t.Error("New or Reset did not set int32:", *pb.F_Int32Defaulted)
+	}
+	if pb.F_Int64Defaulted != nil {
+		t.Error("New or Reset did not set int64:", *pb.F_Int64Defaulted)
+	}
+	if pb.F_Fixed32Defaulted != nil {
+		t.Error("New or Reset did not set fixed32:", *pb.F_Fixed32Defaulted)
+	}
+	if pb.F_Fixed64Defaulted != nil {
+		t.Error("New or Reset did not set fixed64:", *pb.F_Fixed64Defaulted)
+	}
+	if pb.F_Uint32Defaulted != nil {
+		t.Error("New or Reset did not set uint32:", *pb.F_Uint32Defaulted)
+	}
+	if pb.F_Uint64Defaulted != nil {
+		t.Error("New or Reset did not set uint64:", *pb.F_Uint64Defaulted)
+	}
+	if pb.F_FloatDefaulted != nil {
+		t.Error("New or Reset did not set float:", *pb.F_FloatDefaulted)
+	}
+	if pb.F_DoubleDefaulted != nil {
+		t.Error("New or Reset did not set double:", *pb.F_DoubleDefaulted)
+	}
+	if pb.F_StringDefaulted != nil {
+		t.Error("New or Reset did not set string:", *pb.F_StringDefaulted)
+	}
+	if pb.F_BytesDefaulted != nil {
+		t.Error("New or Reset did not set bytes:", string(pb.F_BytesDefaulted))
+	}
+	if pb.F_Sint32Defaulted != nil {
+		t.Error("New or Reset did not set int32:", *pb.F_Sint32Defaulted)
+	}
+	if pb.F_Sint64Defaulted != nil {
+		t.Error("New or Reset did not set int64:", *pb.F_Sint64Defaulted)
+	}
+}
+
+// Does Reset() reset?
+func TestReset(t *testing.T) {
+	pb := initGoTest(true)
+	// muck with some values
+	pb.F_BoolDefaulted = Bool(false)
+	pb.F_Int32Defaulted = Int32(237)
+	pb.F_Int64Defaulted = Int64(12346)
+	pb.F_Fixed32Defaulted = Uint32(32000)
+	pb.F_Fixed64Defaulted = Uint64(666)
+	pb.F_Uint32Defaulted = Uint32(323232)
+	pb.F_Uint64Defaulted = nil
+	pb.F_FloatDefaulted = nil
+	pb.F_DoubleDefaulted = Float64(0)
+	pb.F_StringDefaulted = String("gotcha")
+	pb.F_BytesDefaulted = []byte("asdfasdf")
+	pb.F_Sint32Defaulted = Int32(123)
+	pb.F_Sint64Defaulted = Int64(789)
+	pb.Reset()
+	checkInitialized(pb, t)
+}
+
+// All required fields set, no defaults provided.
+func TestEncodeDecode1(t *testing.T) {
+	pb := initGoTest(false)
+	overify(t, pb,
+		"0807"+ // field 1, encoding 0, value 7
+			"220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField)
+			"5001"+ // field 10, encoding 0, value 1
+			"5803"+ // field 11, encoding 0, value 3
+			"6006"+ // field 12, encoding 0, value 6
+			"6d20000000"+ // field 13, encoding 5, value 0x20
+			"714000000000000000"+ // field 14, encoding 1, value 0x40
+			"78a019"+ // field 15, encoding 0, value 0xca0 = 3232
+			"8001c032"+ // field 16, encoding 0, value 0x1940 = 6464
+			"8d0100004a45"+ // field 17, encoding 5, value 3232.0
+			"9101000000000040b940"+ // field 18, encoding 1, value 6464.0
+			"9a0106"+"737472696e67"+ // field 19, encoding 2, string "string"
+			"aa0605"+"6279746573"+ // field 101, encoding 2, string "bytes"
+			"b0063f"+ // field 102, encoding 0, 0x3f zigzag32
+			"b8067f"+ // field 103, encoding 0, 0x7f zigzag64
+			"b304"+ // field 70, encoding 3, start group
+			"ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required"
+			"b404") // field 70, encoding 4, end group
+}
+
+// All required fields set, defaults provided.
+func TestEncodeDecode2(t *testing.T) {
+	pb := initGoTest(true)
+	overify(t, pb,
+		"0807"+ // field 1, encoding 0, value 7
+			"220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField)
+			"5001"+ // field 10, encoding 0, value 1
+			"5803"+ // field 11, encoding 0, value 3
+			"6006"+ // field 12, encoding 0, value 6
+			"6d20000000"+ // field 13, encoding 5, value 32
+			"714000000000000000"+ // field 14, encoding 1, value 64
+			"78a019"+ // field 15, encoding 0, value 3232
+			"8001c032"+ // field 16, encoding 0, value 6464
+			"8d0100004a45"+ // field 17, encoding 5, value 3232.0
+			"9101000000000040b940"+ // field 18, encoding 1, value 6464.0
+			"9a0106"+"737472696e67"+ // field 19, encoding 2 string "string"
+			"aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes"
+			"b0063f"+ // field 102, encoding 0, 0x3f zigzag32
+			"b8067f"+ // field 103, encoding 0, 0x7f zigzag64
+			"c00201"+ // field 40, encoding 0, value 1
+			"c80220"+ // field 41, encoding 0, value 32
+			"d00240"+ // field 42, encoding 0, value 64
+			"dd0240010000"+ // field 43, encoding 5, value 320
+			"e1028002000000000000"+ // field 44, encoding 1, value 640
+			"e8028019"+ // field 45, encoding 0, value 3200
+			"f0028032"+ // field 46, encoding 0, value 6400
+			"fd02e0659948"+ // field 47, encoding 5, value 314159.0
+			"81030000000050971041"+ // field 48, encoding 1, value 271828.0
+			"8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n"
+			"90193f"+ // field 402, encoding 0, value 63
+			"98197f"+ // field 403, encoding 0, value 127
+			"b304"+ // start group field 70 level 1
+			"ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required"
+			"b404") // end group field 70 level 1
+
+}
+
+// All default fields set to their default value by hand
+func TestEncodeDecode3(t *testing.T) {
+	pb := initGoTest(false)
+	pb.F_BoolDefaulted = Bool(true)
+	pb.F_Int32Defaulted = Int32(32)
+	pb.F_Int64Defaulted = Int64(64)
+	pb.F_Fixed32Defaulted = Uint32(320)
+	pb.F_Fixed64Defaulted = Uint64(640)
+	pb.F_Uint32Defaulted = Uint32(3200)
+	pb.F_Uint64Defaulted = Uint64(6400)
+	pb.F_FloatDefaulted = Float32(314159)
+	pb.F_DoubleDefaulted = Float64(271828)
+	pb.F_StringDefaulted = String("hello, \"world!\"\n")
+	pb.F_BytesDefaulted = []byte("Bignose")
+	pb.F_Sint32Defaulted = Int32(-32)
+	pb.F_Sint64Defaulted = Int64(-64)
+
+	overify(t, pb,
+		"0807"+ // field 1, encoding 0, value 7
+			"220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField)
+			"5001"+ // field 10, encoding 0, value 1
+			"5803"+ // field 11, encoding 0, value 3
+			"6006"+ // field 12, encoding 0, value 6
+			"6d20000000"+ // field 13, encoding 5, value 32
+			"714000000000000000"+ // field 14, encoding 1, value 64
+			"78a019"+ // field 15, encoding 0, value 3232
+			"8001c032"+ // field 16, encoding 0, value 6464
+			"8d0100004a45"+ // field 17, encoding 5, value 3232.0
+			"9101000000000040b940"+ // field 18, encoding 1, value 6464.0
+			"9a0106"+"737472696e67"+ // field 19, encoding 2 string "string"
+			"aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes"
+			"b0063f"+ // field 102, encoding 0, 0x3f zigzag32
+			"b8067f"+ // field 103, encoding 0, 0x7f zigzag64
+			"c00201"+ // field 40, encoding 0, value 1
+			"c80220"+ // field 41, encoding 0, value 32
+			"d00240"+ // field 42, encoding 0, value 64
+			"dd0240010000"+ // field 43, encoding 5, value 320
+			"e1028002000000000000"+ // field 44, encoding 1, value 640
+			"e8028019"+ // field 45, encoding 0, value 3200
+			"f0028032"+ // field 46, encoding 0, value 6400
+			"fd02e0659948"+ // field 47, encoding 5, value 314159.0
+			"81030000000050971041"+ // field 48, encoding 1, value 271828.0
+			"8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n"
+			"90193f"+ // field 402, encoding 0, value 63
+			"98197f"+ // field 403, encoding 0, value 127
+			"b304"+ // start group field 70 level 1
+			"ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required"
+			"b404") // end group field 70 level 1
+
+}
+
+// All required fields set, defaults provided, all non-defaulted optional fields have values.
+func TestEncodeDecode4(t *testing.T) {
+	pb := initGoTest(true)
+	pb.Table = String("hello")
+	pb.Param = Int32(7)
+	pb.OptionalField = initGoTestField()
+	pb.F_BoolOptional = Bool(true)
+	pb.F_Int32Optional = Int32(32)
+	pb.F_Int64Optional = Int64(64)
+	pb.F_Fixed32Optional = Uint32(3232)
+	pb.F_Fixed64Optional = Uint64(6464)
+	pb.F_Uint32Optional = Uint32(323232)
+	pb.F_Uint64Optional = Uint64(646464)
+	pb.F_FloatOptional = Float32(32.)
+	pb.F_DoubleOptional = Float64(64.)
+	pb.F_StringOptional = String("hello")
+	pb.F_BytesOptional = []byte("Bignose")
+	pb.F_Sint32Optional = Int32(-32)
+	pb.F_Sint64Optional = Int64(-64)
+	pb.Optionalgroup = initGoTest_OptionalGroup()
+
+	overify(t, pb,
+		"0807"+ // field 1, encoding 0, value 7
+			"1205"+"68656c6c6f"+ // field 2, encoding 2, string "hello"
+			"1807"+ // field 3, encoding 0, value 7
+			"220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField)
+			"320d"+"0a056c6162656c120474797065"+ // field 6, encoding 2 (GoTestField)
+			"5001"+ // field 10, encoding 0, value 1
+			"5803"+ // field 11, encoding 0, value 3
+			"6006"+ // field 12, encoding 0, value 6
+			"6d20000000"+ // field 13, encoding 5, value 32
+			"714000000000000000"+ // field 14, encoding 1, value 64
+			"78a019"+ // field 15, encoding 0, value 3232
+			"8001c032"+ // field 16, encoding 0, value 6464
+			"8d0100004a45"+ // field 17, encoding 5, value 3232.0
+			"9101000000000040b940"+ // field 18, encoding 1, value 6464.0
+			"9a0106"+"737472696e67"+ // field 19, encoding 2 string "string"
+			"aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes"
+			"b0063f"+ // field 102, encoding 0, 0x3f zigzag32
+			"b8067f"+ // field 103, encoding 0, 0x7f zigzag64
+			"f00101"+ // field 30, encoding 0, value 1
+			"f80120"+ // field 31, encoding 0, value 32
+			"800240"+ // field 32, encoding 0, value 64
+			"8d02a00c0000"+ // field 33, encoding 5, value 3232
+			"91024019000000000000"+ // field 34, encoding 1, value 6464
+			"9802a0dd13"+ // field 35, encoding 0, value 323232
+			"a002c0ba27"+ // field 36, encoding 0, value 646464
+			"ad0200000042"+ // field 37, encoding 5, value 32.0
+			"b1020000000000005040"+ // field 38, encoding 1, value 64.0
+			"ba0205"+"68656c6c6f"+ // field 39, encoding 2, string "hello"
+			"ea1207"+"4269676e6f7365"+ // field 301, encoding 2, string "Bignose"
+			"f0123f"+ // field 302, encoding 0, value 63
+			"f8127f"+ // field 303, encoding 0, value 127
+			"c00201"+ // field 40, encoding 0, value 1
+			"c80220"+ // field 41, encoding 0, value 32
+			"d00240"+ // field 42, encoding 0, value 64
+			"dd0240010000"+ // field 43, encoding 5, value 320
+			"e1028002000000000000"+ // field 44, encoding 1, value 640
+			"e8028019"+ // field 45, encoding 0, value 3200
+			"f0028032"+ // field 46, encoding 0, value 6400
+			"fd02e0659948"+ // field 47, encoding 5, value 314159.0
+			"81030000000050971041"+ // field 48, encoding 1, value 271828.0
+			"8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n"
+			"90193f"+ // field 402, encoding 0, value 63
+			"98197f"+ // field 403, encoding 0, value 127
+			"b304"+ // start group field 70 level 1
+			"ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required"
+			"b404"+ // end group field 70 level 1
+			"d305"+ // start group field 90 level 1
+			"da0508"+"6f7074696f6e616c"+ // field 91, encoding 2, string "optional"
+			"d405") // end group field 90 level 1
+
+}
+
+// All required fields set, defaults provided, all repeated fields given two values.
+func TestEncodeDecode5(t *testing.T) {
+	pb := initGoTest(true)
+	pb.RepeatedField = []*GoTestField{initGoTestField(), initGoTestField()}
+	pb.F_BoolRepeated = []bool{false, true}
+	pb.F_Int32Repeated = []int32{32, 33}
+	pb.F_Int64Repeated = []int64{64, 65}
+	pb.F_Fixed32Repeated = []uint32{3232, 3333}
+	pb.F_Fixed64Repeated = []uint64{6464, 6565}
+	pb.F_Uint32Repeated = []uint32{323232, 333333}
+	pb.F_Uint64Repeated = []uint64{646464, 656565}
+	pb.F_FloatRepeated = []float32{32., 33.}
+	pb.F_DoubleRepeated = []float64{64., 65.}
+	pb.F_StringRepeated = []string{"hello", "sailor"}
+	pb.F_BytesRepeated = [][]byte{[]byte("big"), []byte("nose")}
+	pb.F_Sint32Repeated = []int32{32, -32}
+	pb.F_Sint64Repeated = []int64{64, -64}
+	pb.Repeatedgroup = []*GoTest_RepeatedGroup{initGoTest_RepeatedGroup(), initGoTest_RepeatedGroup()}
+
+	overify(t, pb,
+		"0807"+ // field 1, encoding 0, value 7
+			"220d"+"0a056c6162656c120474797065"+ // field 4, encoding 2 (GoTestField)
+			"2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField)
+			"2a0d"+"0a056c6162656c120474797065"+ // field 5, encoding 2 (GoTestField)
+			"5001"+ // field 10, encoding 0, value 1
+			"5803"+ // field 11, encoding 0, value 3
+			"6006"+ // field 12, encoding 0, value 6
+			"6d20000000"+ // field 13, encoding 5, value 32
+			"714000000000000000"+ // field 14, encoding 1, value 64
+			"78a019"+ // field 15, encoding 0, value 3232
+			"8001c032"+ // field 16, encoding 0, value 6464
+			"8d0100004a45"+ // field 17, encoding 5, value 3232.0
+			"9101000000000040b940"+ // field 18, encoding 1, value 6464.0
+			"9a0106"+"737472696e67"+ // field 19, encoding 2 string "string"
+			"aa0605"+"6279746573"+ // field 101, encoding 2 string "bytes"
+			"b0063f"+ // field 102, encoding 0, 0x3f zigzag32
+			"b8067f"+ // field 103, encoding 0, 0x7f zigzag64
+			"a00100"+ // field 20, encoding 0, value 0
+			"a00101"+ // field 20, encoding 0, value 1
+			"a80120"+ // field 21, encoding 0, value 32
+			"a80121"+ // field 21, encoding 0, value 33
+			"b00140"+ // field 22, encoding 0, value 64
+			"b00141"+ // field 22, encoding 0, value 65
+			"bd01a00c0000"+ // field 23, encoding 5, value 3232
+			"bd01050d0000"+ // field 23, encoding 5, value 3333
+			"c1014019000000000000"+ // field 24, encoding 1, value 6464
+			"c101a519000000000000"+ // field 24, encoding 1, value 6565
+			"c801a0dd13"+ // field 25, encoding 0, value 323232
+			"c80195ac14"+ // field 25, encoding 0, value 333333
+			"d001c0ba27"+ // field 26, encoding 0, value 646464
+			"d001b58928"+ // field 26, encoding 0, value 656565
+			"dd0100000042"+ // field 27, encoding 5, value 32.0
+			"dd0100000442"+ // field 27, encoding 5, value 33.0
+			"e1010000000000005040"+ // field 28, encoding 1, value 64.0
+			"e1010000000000405040"+ // field 28, encoding 1, value 65.0
+			"ea0105"+"68656c6c6f"+ // field 29, encoding 2, string "hello"
+			"ea0106"+"7361696c6f72"+ // field 29, encoding 2, string "sailor"
+			"ca0c03"+"626967"+ // field 201, encoding 2, string "big"
+			"ca0c04"+"6e6f7365"+ // field 201, encoding 2, string "nose"
+			"d00c40"+ // field 202, encoding 0, value 64
+			"d00c3f"+ // field 202, encoding 0, value 63
+			"d80c8001"+ // field 203, encoding 0, value 128
+			"d80c7f"+ // field 203, encoding 0, value 127
+			"c00201"+ // field 40, encoding 0, value 1
+			"c80220"+ // field 41, encoding 0, value 32
+			"d00240"+ // field 42, encoding 0, value 64
+			"dd0240010000"+ // field 43, encoding 5, value 320
+			"e1028002000000000000"+ // field 44, encoding 1, value 640
+			"e8028019"+ // field 45, encoding 0, value 3200
+			"f0028032"+ // field 46, encoding 0, value 6400
+			"fd02e0659948"+ // field 47, encoding 5, value 314159.0
+			"81030000000050971041"+ // field 48, encoding 1, value 271828.0
+			"8a0310"+"68656c6c6f2c2022776f726c6421220a"+ // field 49, encoding 2 string "hello, \"world!\"\n"
+			"90193f"+ // field 402, encoding 0, value 63
+			"98197f"+ // field 403, encoding 0, value 127
+			"b304"+ // start group field 70 level 1
+			"ba0408"+"7265717569726564"+ // field 71, encoding 2, string "required"
+			"b404"+ // end group field 70 level 1
+			"8305"+ // start group field 80 level 1
+			"8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated"
+			"8405"+ // end group field 80 level 1
+			"8305"+ // start group field 80 level 1
+			"8a0508"+"7265706561746564"+ // field 81, encoding 2, string "repeated"
+			"8405") // end group field 80 level 1
+
+}
+
+// All required fields set, defaults provided, all repeated fields given two values.
+func TestSkippingUnrecognizedFields(t *testing.T) {
+	o := old()
+	pb := initGoTestField()
+
+	// Marshal it normally.
+	o.Marshal(pb)
+
+	// Now new a GoSkipTest record.
+	skipgroup := NewGoSkipTest_SkipGroup()
+	skipgroup.GroupInt32 = Int32(75)
+	skipgroup.GroupString = String("wxyz")
+	skip := NewGoSkipTest()
+	skip.SkipInt32 = Int32(32)
+	skip.SkipFixed32 = Uint32(3232)
+	skip.SkipFixed64 = Uint64(6464)
+	skip.SkipString = String("skipper")
+	skip.Skipgroup = skipgroup
+
+	// Marshal it into same buffer.
+	o.Marshal(skip)
+
+	pbd := NewGoTestField()
+	o.Unmarshal(pbd)
+
+	// The __unrecognized field should be a marshaling of GoSkipTest
+	skipd := NewGoSkipTest()
+
+	o.SetBuf(pbd.XXX_unrecognized)
+	o.Unmarshal(skipd)
+
+	if *skipd.SkipInt32 != *skip.SkipInt32 {
+		t.Error("skip int32", skipd.SkipInt32)
+	}
+	if *skipd.SkipFixed32 != *skip.SkipFixed32 {
+		t.Error("skip fixed32", skipd.SkipFixed32)
+	}
+	if *skipd.SkipFixed64 != *skip.SkipFixed64 {
+		t.Error("skip fixed64", skipd.SkipFixed64)
+	}
+	if *skipd.SkipString != *skip.SkipString {
+		t.Error("skip string", *skipd.SkipString)
+	}
+	if *skipd.Skipgroup.GroupInt32 != *skip.Skipgroup.GroupInt32 {
+		t.Error("skip group int32", skipd.Skipgroup.GroupInt32)
+	}
+	if *skipd.Skipgroup.GroupString != *skip.Skipgroup.GroupString {
+		t.Error("skip group string", *skipd.Skipgroup.GroupString)
+	}
+}
+
+// Check that we can grow an array (repeated field) to have many elements.
+// This test doesn't depend only on our encoding; for variety, it makes sure
+// we create, encode, and decode the correct contents explicitly.  It's therefore
+// a bit messier.
+// This test also uses (and hence tests) the Marshal/Unmarshal functions
+// instead of the methods.
+func TestBigRepeated(t *testing.T) {
+	pb := initGoTest(true)
+
+	// Create the arrays
+	const N = 50 // Internally the library starts much smaller.
+	pb.Repeatedgroup = make([]*GoTest_RepeatedGroup, N)
+	pb.F_Sint64Repeated = make([]int64, N)
+	pb.F_Sint32Repeated = make([]int32, N)
+	pb.F_BytesRepeated = make([][]byte, N)
+	pb.F_StringRepeated = make([]string, N)
+	pb.F_DoubleRepeated = make([]float64, N)
+	pb.F_FloatRepeated = make([]float32, N)
+	pb.F_Uint64Repeated = make([]uint64, N)
+	pb.F_Uint32Repeated = make([]uint32, N)
+	pb.F_Fixed64Repeated = make([]uint64, N)
+	pb.F_Fixed32Repeated = make([]uint32, N)
+	pb.F_Int64Repeated = make([]int64, N)
+	pb.F_Int32Repeated = make([]int32, N)
+	pb.F_BoolRepeated = make([]bool, N)
+	pb.RepeatedField = make([]*GoTestField, N)
+
+	// Fill in the arrays with checkable values.
+	igtf := initGoTestField()
+	igtrg := initGoTest_RepeatedGroup()
+	for i := 0; i < N; i++ {
+		pb.Repeatedgroup[i] = igtrg
+		pb.F_Sint64Repeated[i] = int64(i)
+		pb.F_Sint32Repeated[i] = int32(i)
+		s := fmt.Sprint(i)
+		pb.F_BytesRepeated[i] = []byte(s)
+		pb.F_StringRepeated[i] = s
+		pb.F_DoubleRepeated[i] = float64(i)
+		pb.F_FloatRepeated[i] = float32(i)
+		pb.F_Uint64Repeated[i] = uint64(i)
+		pb.F_Uint32Repeated[i] = uint32(i)
+		pb.F_Fixed64Repeated[i] = uint64(i)
+		pb.F_Fixed32Repeated[i] = uint32(i)
+		pb.F_Int64Repeated[i] = int64(i)
+		pb.F_Int32Repeated[i] = int32(i)
+		pb.F_BoolRepeated[i] = i%2 == 0
+		pb.RepeatedField[i] = igtf
+	}
+
+	// Marshal.
+	buf, _ := Marshal(pb)
+
+	// Now test Unmarshal by recreating the original buffer.
+	pbd := NewGoTest()
+	Unmarshal(buf, pbd)
+
+	// Check the checkable values
+	for i := uint64(0); i < N; i++ {
+		if pbd.Repeatedgroup[i] == nil { // TODO: more checking?
+			t.Error("pbd.Repeatedgroup bad")
+		}
+		var x uint64
+		x = uint64(pbd.F_Sint64Repeated[i])
+		if x != i {
+			t.Error("pbd.F_Sint64Repeated bad", x, i)
+		}
+		x = uint64(pbd.F_Sint32Repeated[i])
+		if x != i {
+			t.Error("pbd.F_Sint32Repeated bad", x, i)
+		}
+		s := fmt.Sprint(i)
+		equalbytes(pbd.F_BytesRepeated[i], []byte(s), t)
+		if pbd.F_StringRepeated[i] != s {
+			t.Error("pbd.F_Sint32Repeated bad", pbd.F_StringRepeated[i], i)
+		}
+		x = uint64(pbd.F_DoubleRepeated[i])
+		if x != i {
+			t.Error("pbd.F_DoubleRepeated bad", x, i)
+		}
+		x = uint64(pbd.F_FloatRepeated[i])
+		if x != i {
+			t.Error("pbd.F_FloatRepeated bad", x, i)
+		}
+		x = pbd.F_Uint64Repeated[i]
+		if x != i {
+			t.Error("pbd.F_Uint64Repeated bad", x, i)
+		}
+		x = uint64(pbd.F_Uint32Repeated[i])
+		if x != i {
+			t.Error("pbd.F_Uint32Repeated bad", x, i)
+		}
+		x = pbd.F_Fixed64Repeated[i]
+		if x != i {
+			t.Error("pbd.F_Fixed64Repeated bad", x, i)
+		}
+		x = uint64(pbd.F_Fixed32Repeated[i])
+		if x != i {
+			t.Error("pbd.F_Fixed32Repeated bad", x, i)
+		}
+		x = uint64(pbd.F_Int64Repeated[i])
+		if x != i {
+			t.Error("pbd.F_Int64Repeated bad", x, i)
+		}
+		x = uint64(pbd.F_Int32Repeated[i])
+		if x != i {
+			t.Error("pbd.F_Int32Repeated bad", x, i)
+		}
+		if pbd.F_BoolRepeated[i] != (i%2 == 0) {
+			t.Error("pbd.F_BoolRepeated bad", x, i)
+		}
+		if pbd.RepeatedField[i] == nil { // TODO: more checking?
+			t.Error("pbd.RepeatedField bad")
+		}
+	}
+}
+
+// Verify we give a useful message when decoding to the wrong structure type.
+func TestTypeMismatch(t *testing.T) {
+	pb1 := initGoTest(true)
+
+	// Marshal
+	o := old()
+	o.Marshal(pb1)
+
+	// Now Unmarshal it to the wrong type.
+	pb2 := initGoTestField()
+	err := o.Unmarshal(pb2)
+	switch err {
+	case ErrWrongType:
+		// fine
+	case nil:
+		t.Error("expected wrong type error, got no error")
+	default:
+		t.Error("expected wrong type error, got", err)
+	}
+}
+
+func TestProto1RepeatedGroup(t *testing.T) {
+	pb := NewMessageList()
+
+	pb.Message = make([]*MessageList_Message, 2)
+	pb.Message[0] = NewMessageList_Message()
+	pb.Message[0].Name = String("blah")
+	pb.Message[0].Count = Int32(7)
+	// NOTE: pb.Message[1] is a nil
+
+	o := old()
+	if err := o.Marshal(pb); err != ErrRepeatedHasNil {
+		t.Fatalf("unexpected or no error when marshaling: %v", err)
+	}
+}
+
+// Test that enums work.  Checks for a bug introduced by making enums
+// named types instead of int32: newInt32FromUint64 would crash with
+// a type mismatch in reflect.PointTo.
+func TestEnum(t *testing.T) {
+	pb := new(GoEnum)
+	pb.Foo = NewFOO(FOO_FOO1)
+	o := old()
+	if err := o.Marshal(pb); err != nil {
+		t.Fatalf("error encoding enum:", err)
+	}
+	pb1 := new(GoEnum)
+	if err := o.Unmarshal(pb1); err != nil {
+		t.Fatalf("error decoding enum:", err)
+	}
+	if *pb1.Foo != FOO_FOO1 {
+		t.Errorf("expected 7 but got ", *pb1.Foo)
+	}
+}
+
+func BenchmarkMarshal(b *testing.B) {
+	b.StopTimer()
+
+	pb := initGoTest(true)
+
+	// Create an array
+	const N = 1000 // Internally the library starts much smaller.
+	pb.F_Int32Repeated = make([]int32, N)
+
+	// Fill in the array with some values.
+	for i := 0; i < N; i++ {
+		pb.F_Int32Repeated[i] = int32(i)
+	}
+	p := NewBuffer(nil)
+
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		p.Reset()
+		p.Marshal(pb)
+	}
+}
+
+func BenchmarkUnmarshal(b *testing.B) {
+	b.StopTimer()
+
+	pb := initGoTest(true)
+
+	// Create an array
+	const N = 1000 // Internally the library starts much smaller.
+	pb.F_Int32Repeated = make([]int32, N)
+
+	// Fill in the array with some values.
+	for i := 0; i < N; i++ {
+		pb.F_Int32Repeated[i] = int32(i)
+	}
+	pbd := NewGoTest()
+	p := NewBuffer(nil)
+	p.Marshal(pb)
+	p2 := NewBuffer(nil)
+
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		p2.SetBuf(p.Bytes())
+		p2.Unmarshal(pbd)
+	}
+}
diff --git a/proto/decode.go b/proto/decode.go
new file mode 100644
index 0000000..0c237e1
--- /dev/null
+++ b/proto/decode.go
@@ -0,0 +1,741 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto
+
+/*
+ * Routines for decoding protocol buffer data to construct in-memory representations.
+ */
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"runtime"
+	"unsafe"
+)
+
+// ErrWrongType occurs when the wire encoding for the field disagrees with
+// that specified in the type being decoded.  This is usually caused by attempting
+// to convert an encoded protocol buffer into a struct of the wrong type.
+var ErrWrongType = os.NewError("field/encoding mismatch: wrong type for field")
+
+// The fundamental decoders that interpret bytes on the wire.
+// Those that take integer types all return uint64 and are
+// therefore of type valueDecoder.
+
+// DecodeVarint reads a varint-encoded integer from the slice.
+// It returns the integer and the number of bytes consumed, or
+// zero if there is not enough.
+// This is the format for the
+// int32, int64, uint32, uint64, bool, and enum
+// protocol buffer types.
+func DecodeVarint(buf []byte) (x uint64, n int) {
+	// x, n already 0
+	for shift := uint(0); ; shift += 7 {
+		if n >= len(buf) {
+			return 0, 0
+		}
+		b := uint64(buf[n])
+		n++
+		x |= (b & 0x7F) << shift
+		if (b & 0x80) == 0 {
+			break
+		}
+	}
+	return x, n
+}
+
+// DecodeVarint reads a varint-encoded integer from the Buffer.
+// This is the format for the
+// int32, int64, uint32, uint64, bool, and enum
+// protocol buffer types.
+func (p *Buffer) DecodeVarint() (x uint64, err os.Error) {
+	// x, err already 0
+
+	i := p.index
+	l := len(p.buf)
+
+	for shift := uint(0); ; shift += 7 {
+		if i >= l {
+			err = io.ErrUnexpectedEOF
+			return
+		}
+		b := p.buf[i]
+		i++
+		x |= (uint64(b) & 0x7F) << shift
+		if b < 0x80 {
+			break
+		}
+	}
+	p.index = i
+	return
+}
+
+// DecodeFixed64 reads a 64-bit integer from the Buffer.
+// This is the format for the
+// fixed64, sfixed64, and double protocol buffer types.
+func (p *Buffer) DecodeFixed64() (x uint64, err os.Error) {
+	// x, err already 0
+	i := p.index + 8
+	if i > len(p.buf) {
+		err = io.ErrUnexpectedEOF
+		return
+	}
+	p.index = i
+
+	x = uint64(p.buf[i-8])
+	x |= uint64(p.buf[i-7]) << 8
+	x |= uint64(p.buf[i-6]) << 16
+	x |= uint64(p.buf[i-5]) << 24
+	x |= uint64(p.buf[i-4]) << 32
+	x |= uint64(p.buf[i-3]) << 40
+	x |= uint64(p.buf[i-2]) << 48
+	x |= uint64(p.buf[i-1]) << 56
+	return
+}
+
+// DecodeFixed32 reads a 32-bit integer from the Buffer.
+// This is the format for the
+// fixed32, sfixed32, and float protocol buffer types.
+func (p *Buffer) DecodeFixed32() (x uint64, err os.Error) {
+	// x, err already 0
+	i := p.index + 4
+	if i > len(p.buf) {
+		err = io.ErrUnexpectedEOF
+		return
+	}
+	p.index = i
+
+	x = uint64(p.buf[i-4])
+	x |= uint64(p.buf[i-3]) << 8
+	x |= uint64(p.buf[i-2]) << 16
+	x |= uint64(p.buf[i-1]) << 24
+	return
+}
+
+// DecodeZigzag64 reads a zigzag-encoded 64-bit integer
+// from the Buffer.
+// This is the format used for the sint64 protocol buffer type.
+func (p *Buffer) DecodeZigzag64() (x uint64, err os.Error) {
+	x, err = p.DecodeVarint()
+	if err != nil {
+		return
+	}
+	x = (x >> 1) ^ uint64((int64(x&1)<<63)>>63)
+	return
+}
+
+// DecodeZigzag32 reads a zigzag-encoded 32-bit integer
+// from  the Buffer.
+// This is the format used for the sint32 protocol buffer type.
+func (p *Buffer) DecodeZigzag32() (x uint64, err os.Error) {
+	x, err = p.DecodeVarint()
+	if err != nil {
+		return
+	}
+	x = uint64((uint32(x) >> 1) ^ uint32((int32(x&1)<<31)>>31))
+	return
+}
+
+// These are not ValueDecoders: they produce an array of bytes or a string.
+// bytes, embedded messages
+
+// DecodeRawBytes reads a count-delimited byte buffer from the Buffer.
+// This is the format used for the bytes protocol buffer
+// type and for embedded messages.
+func (p *Buffer) DecodeRawBytes(alloc bool) (buf []byte, err os.Error) {
+	n, err := p.DecodeVarint()
+	if err != nil {
+		return
+	}
+
+	nb := int(n)
+	if p.index+nb > len(p.buf) {
+		err = io.ErrUnexpectedEOF
+		return
+	}
+
+	if !alloc {
+		// todo: check if can get more uses of alloc=false
+		buf = p.buf[p.index : p.index+nb]
+		p.index += nb
+		return
+	}
+
+	buf = make([]byte, nb)
+	copy(buf, p.buf[p.index:])
+	p.index += nb
+	return
+}
+
+// DecodeStringBytes reads an encoded string from the Buffer.
+// This is the format used for the proto2 string type.
+func (p *Buffer) DecodeStringBytes() (s string, err os.Error) {
+	buf, err := p.DecodeRawBytes(false)
+	if err != nil {
+		return
+	}
+	return string(buf), nil
+}
+
+// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
+// If the protocol buffer has extensions, and the field matches, add it as an extension.
+// Otherwise, if the XXX_unrecognized field exists, append the skipped data there.
+func (o *Buffer) skipAndSave(t *reflect.StructType, tag, wire int, base uintptr) os.Error {
+
+	oi := o.index
+
+	err := o.skip(t, tag, wire)
+	if err != nil {
+		return err
+	}
+
+	x := fieldIndex(t, "XXX_unrecognized")
+	if x == nil {
+		return nil
+	}
+
+	p := propByIndex(t, x)
+	ptr := (*[]byte)(unsafe.Pointer(base + p.offset))
+
+	if *ptr == nil {
+		// This is the first skipped element,
+		// allocate a new buffer.
+		*ptr = o.bufalloc()
+	}
+
+	// Add the skipped field to struct field
+	obuf := o.buf
+
+	o.buf = *ptr
+	o.EncodeVarint(uint64(tag<<3 | wire))
+	*ptr = bytes.Add(o.buf, obuf[oi:o.index])
+
+	o.buf = obuf
+
+	return nil
+}
+
+// Skip the next item in the buffer. Its wire type is decoded and presented as an argument.
+func (o *Buffer) skip(t *reflect.StructType, tag, wire int) os.Error {
+
+	var u uint64
+	var err os.Error
+
+	switch wire {
+	case WireVarint:
+		_, err = o.DecodeVarint()
+	case WireFixed64:
+		_, err = o.DecodeFixed64()
+	case WireBytes:
+		_, err = o.DecodeRawBytes(false)
+	case WireFixed32:
+		_, err = o.DecodeFixed32()
+	case WireStartGroup:
+		for {
+			u, err = o.DecodeVarint()
+			if err != nil {
+				break
+			}
+			fwire := int(u & 0x7)
+			if fwire == WireEndGroup {
+				break
+			}
+			ftag := int(u >> 3)
+			err = o.skip(t, ftag, fwire)
+			if err != nil {
+				break
+			}
+		}
+	default:
+		fmt.Fprintf(os.Stderr, "proto: can't skip wire type %d for %s\n", wire, t)
+	}
+	return err
+}
+
+// Unmarshaler is the interface representing objects that can unmarshal themselves.
+type Unmarshaler interface {
+	Unmarshal([]byte) os.Error
+}
+
+// Unmarshal parses the protocol buffer representation in buf and places the
+// decoded result in pb.  If the struct underlying pb does not match
+// the data in buf, the results can be unpredictable.
+func Unmarshal(buf []byte, pb interface{}) os.Error {
+	// If the object can unmarshal itself, let it.
+	if u, ok := pb.(Unmarshaler); ok {
+		return u.Unmarshal(buf)
+	}
+
+	return NewBuffer(buf).Unmarshal(pb)
+}
+
+// Unmarshal parses the protocol buffer representation in the
+// Buffer and places the decoded result in pb.  If the struct
+// underlying pb does not match the data in the buffer, the results can be
+// unpredictable.
+func (p *Buffer) Unmarshal(pb interface{}) os.Error {
+	// If the object can unmarshal itself, let it.
+	if u, ok := pb.(Unmarshaler); ok {
+		err := u.Unmarshal(p.buf[p.index:])
+		p.index = len(p.buf)
+		return err
+	}
+
+	mstat := runtime.MemStats.Mallocs
+
+	typ, base, err := getbase(pb)
+	if err != nil {
+		return err
+	}
+
+	err = p.unmarshalType(typ, false, base)
+
+	mstat = runtime.MemStats.Mallocs - mstat
+	stats.Dmalloc += mstat
+	stats.Decode++
+
+	return err
+}
+
+// unmarshalType does the work of unmarshaling a structure.
+func (o *Buffer) unmarshalType(t *reflect.PtrType, is_group bool, base uintptr) os.Error {
+	st := t.Elem().(*reflect.StructType)
+	prop := GetProperties(st)
+	sbase := getsbase(prop) // scratch area for data items
+
+	var err os.Error
+	for err == nil && o.index < len(o.buf) {
+		oi := o.index
+		var u uint64
+		u, err = o.DecodeVarint()
+		if err != nil {
+			break
+		}
+		wire := int(u & 0x7)
+		if wire == WireEndGroup {
+			if is_group {
+				return nil // input is satisfied
+			}
+			return ErrWrongType
+		}
+		tag := int(u >> 3)
+		fieldnum, ok := prop.tags[tag]
+		if !ok {
+			// Maybe it's an extension?
+			o.ptr = base
+			iv := unsafe.Unreflect(t, unsafe.Pointer(&o.ptr))
+			if e, ok := iv.(extendableProto); ok && isExtensionField(e, int32(tag)) {
+				if err = o.skip(st, tag, wire); err == nil {
+					e.ExtensionMap()[int32(tag)] = bytes.Add(nil, o.buf[oi:o.index])
+				}
+				continue
+			}
+			err = o.skipAndSave(st, tag, wire, base)
+			continue
+		}
+		p := prop.Prop[fieldnum]
+
+		if p.dec != nil {
+			if wire != WireStartGroup && wire != p.WireType {
+				err = ErrWrongType
+				continue
+			}
+			err = p.dec(o, p, base, sbase)
+			continue
+		}
+
+		fmt.Fprintf(os.Stderr, "no protobuf decoder for %s.%s\n", t, st.Field(fieldnum).Name)
+	}
+	if err == nil && is_group {
+		return io.ErrUnexpectedEOF
+	}
+	return err
+}
+
+// Make *pslice have base address base, length 0, and capacity startSize.
+func initSlice(pslice unsafe.Pointer, base uintptr) {
+	sp := (*reflect.SliceHeader)(pslice)
+	sp.Data = base
+	sp.Len = 0
+	sp.Cap = startSize
+}
+
+// Individual type decoders
+// For each,
+//	u is the decoded value,
+//	v is a pointer to the field (pointer) in the struct
+//	x is a pointer to the preallocated scratch space to hold the decoded value.
+
+// Decode a bool.
+func (o *Buffer) dec_bool(p *Properties, base uintptr, sbase uintptr) os.Error {
+	u, err := p.valDec(o)
+	if err != nil {
+		return err
+	}
+	v := (**uint8)(unsafe.Pointer(base + p.offset))
+	x := (*uint8)(unsafe.Pointer(sbase + p.scratch))
+	*x = uint8(u)
+	*v = x
+	return nil
+}
+
+// Decode an int32.
+func (o *Buffer) dec_int32(p *Properties, base uintptr, sbase uintptr) os.Error {
+	u, err := p.valDec(o)
+	if err != nil {
+		return err
+	}
+	v := (**int32)(unsafe.Pointer(base + p.offset))
+	x := (*int32)(unsafe.Pointer(sbase + p.scratch))
+	*x = int32(u)
+	*v = x
+	return nil
+}
+
+// Decode an int64.
+func (o *Buffer) dec_int64(p *Properties, base uintptr, sbase uintptr) os.Error {
+	u, err := p.valDec(o)
+	if err != nil {
+		return err
+	}
+	v := (**int64)(unsafe.Pointer(base + p.offset))
+	x := (*int64)(unsafe.Pointer(sbase + p.scratch))
+	*x = int64(u)
+	*v = x
+	return nil
+}
+
+// Decode a string.
+func (o *Buffer) dec_string(p *Properties, base uintptr, sbase uintptr) os.Error {
+	s, err := o.DecodeStringBytes()
+	if err != nil {
+		return err
+	}
+	v := (**string)(unsafe.Pointer(base + p.offset))
+	x := (*string)(unsafe.Pointer(sbase + p.scratch))
+	*x = s
+	*v = x
+	return nil
+}
+
+// Decode a slice of bytes ([]byte).
+func (o *Buffer) dec_slice_byte(p *Properties, base uintptr, sbase uintptr) os.Error {
+	b, err := o.DecodeRawBytes(false)
+	if err != nil {
+		return err
+	}
+	lb := len(b)
+	if lb == 0 {
+		return nil
+	}
+	x := (*[]uint8)(unsafe.Pointer(base + p.offset))
+
+	y := *x
+	c := cap(y)
+	if c == 0 {
+		initSlice(unsafe.Pointer(x), sbase+p.scratch)
+		y = *x
+		c = cap(y)
+	}
+
+	l := len(y)
+	if l+lb > c {
+		// incremental growth is max(len(slice)*1.5, len(slice)+len(bytes))
+		g := l * 3 / 2
+		if l+lb > g {
+			g = l + lb
+		}
+		z := make([]uint8, l, g)
+		copy(z, y)
+		y = z
+	}
+
+	y = y[0 : l+lb]
+	copy(y[l:l+lb], b)
+
+	*x = y
+	return nil
+}
+
+// Decode a slice of bools ([]bool).
+func (o *Buffer) dec_slice_bool(p *Properties, base uintptr, sbase uintptr) os.Error {
+	u, err := p.valDec(o)
+	if err != nil {
+		return err
+	}
+	x := (*[]bool)(unsafe.Pointer(base + p.offset))
+
+	y := *x
+	c := cap(y)
+	if c == 0 {
+		initSlice(unsafe.Pointer(x), sbase+p.scratch)
+		y = *x
+		c = cap(y)
+	}
+	l := len(y)
+	if l >= c {
+		g := l * 3 / 2
+		z := make([]bool, l, g)
+		copy(z, y)
+		y = z
+	}
+	y = y[0 : l+1]
+	y[l] = u != 0
+	*x = y
+	return nil
+}
+
+// Decode a slice of int32s ([]int32).
+func (o *Buffer) dec_slice_int32(p *Properties, base uintptr, sbase uintptr) os.Error {
+	u, err := p.valDec(o)
+	if err != nil {
+		return err
+	}
+	x := (*[]int32)(unsafe.Pointer(base + p.offset))
+
+	y := *x
+	c := cap(y)
+	if c == 0 {
+		initSlice(unsafe.Pointer(x), sbase+p.scratch)
+		y = *x
+		c = cap(y)
+	}
+	l := len(y)
+	if l >= c {
+		g := l * 3 / 2
+		z := make([]int32, l, g)
+		copy(z, y)
+		y = z
+	}
+	y = y[0 : l+1]
+	y[l] = int32(u)
+	*x = y
+	return nil
+}
+
+// Decode a slice of int64s ([]int64).
+func (o *Buffer) dec_slice_int64(p *Properties, base uintptr, sbase uintptr) os.Error {
+	u, err := p.valDec(o)
+	if err != nil {
+		return err
+	}
+	x := (*[]int64)(unsafe.Pointer(base + p.offset))
+
+	y := *x
+	c := cap(y)
+	if c == 0 {
+		initSlice(unsafe.Pointer(x), sbase+p.scratch)
+		y = *x
+		c = cap(y)
+	}
+	l := len(y)
+	if l >= c {
+		g := l * 3 / 2
+		z := make([]int64, l, g)
+		copy(z, y)
+		y = z
+	}
+	y = y[0 : l+1]
+	y[l] = int64(u)
+	*x = y
+	return nil
+}
+
+// Decode a slice of strings ([]string).
+func (o *Buffer) dec_slice_string(p *Properties, base uintptr, sbase uintptr) os.Error {
+	s, err := o.DecodeStringBytes()
+	if err != nil {
+		return err
+	}
+	x := (*[]string)(unsafe.Pointer(base + p.offset))
+
+	y := *x
+	c := cap(y)
+	if c == 0 {
+		initSlice(unsafe.Pointer(x), sbase+p.scratch)
+		y = *x
+		c = cap(y)
+	}
+	l := len(y)
+	if l >= c {
+		g := l * 3 / 2
+		z := make([]string, l, g)
+		copy(z, y)
+		y = z
+	}
+	y = y[0 : l+1]
+	y[l] = s
+	*x = y
+	return nil
+}
+
+// Decode a slice of slice of bytes ([][]byte).
+func (o *Buffer) dec_slice_slice_byte(p *Properties, base uintptr, sbase uintptr) os.Error {
+	b, err := o.DecodeRawBytes(true)
+	if err != nil {
+		return err
+	}
+	x := (*[][]byte)(unsafe.Pointer(base + p.offset))
+
+	y := *x
+	c := cap(y)
+	if c == 0 {
+		initSlice(unsafe.Pointer(x), sbase+p.scratch)
+		y = *x
+		c = cap(y)
+	}
+	l := len(y)
+	if l >= c {
+		g := l * 3 / 2
+		z := make([][]byte, l, g)
+		copy(z, y)
+		y = z
+	}
+	y = y[0 : l+1]
+	y[l] = b
+	*x = y
+	return nil
+}
+
+// Decode a group.
+func (o *Buffer) dec_struct_group(p *Properties, base uintptr, sbase uintptr) os.Error {
+	ptr := (**struct{})(unsafe.Pointer(base + p.offset))
+	typ := p.stype.Elem().(*reflect.StructType)
+	structv := unsafe.New(typ)
+	bas := uintptr(structv)
+	*ptr = (*struct{})(structv)
+
+	err := o.unmarshalType(p.stype, true, bas)
+
+	return err
+}
+
+// Decode an embedded message.
+func (o *Buffer) dec_struct_message(p *Properties, base uintptr, sbase uintptr) (err os.Error) {
+	raw, e := o.DecodeRawBytes(false)
+	if e != nil {
+		return e
+	}
+
+	ptr := (**struct{})(unsafe.Pointer(base + p.offset))
+	typ := p.stype.Elem().(*reflect.StructType)
+	structv := unsafe.New(typ)
+	bas := uintptr(structv)
+	*ptr = (*struct{})(structv)
+
+	// If the object can unmarshal itself, let it.
+	iv := unsafe.Unreflect(p.stype, unsafe.Pointer(ptr))
+	if u, ok := iv.(Unmarshaler); ok {
+		return u.Unmarshal(raw)
+	}
+
+	obuf := o.buf
+	oi := o.index
+	o.buf = raw
+	o.index = 0
+
+	err = o.unmarshalType(p.stype, false, bas)
+	o.buf = obuf
+	o.index = oi
+
+	return err
+}
+
+// Decode a slice of embedded messages.
+func (o *Buffer) dec_slice_struct_message(p *Properties, base uintptr, sbase uintptr) os.Error {
+	return o.dec_slice_struct(p, false, base, sbase)
+}
+
+// Decode a slice of embedded groups.
+func (o *Buffer) dec_slice_struct_group(p *Properties, base uintptr, sbase uintptr) os.Error {
+	return o.dec_slice_struct(p, true, base, sbase)
+}
+
+// Decode a slice of structs ([]*struct).
+func (o *Buffer) dec_slice_struct(p *Properties, is_group bool, base uintptr, sbase uintptr) os.Error {
+
+	x := (*[]*struct{})(unsafe.Pointer(base + p.offset))
+	y := *x
+	c := cap(y)
+	if c == 0 {
+		initSlice(unsafe.Pointer(x), sbase+p.scratch)
+		y = *x
+		c = cap(y)
+	}
+
+	l := len(y)
+	if l >= c {
+		// Create a new slice with 1.5X the capacity.
+		g := l * 3 / 2
+		z := make([]*struct{}, l, g)
+		copy(z, y)
+		y = z
+	}
+	y = y[0 : l+1]
+	*x = y
+
+	typ := p.stype.Elem().(*reflect.StructType)
+	structv := unsafe.New(typ)
+	bas := uintptr(structv)
+	y[l] = (*struct{})(structv)
+
+	if is_group {
+		err := o.unmarshalType(p.stype, is_group, bas)
+		return err
+	}
+
+	raw, err := o.DecodeRawBytes(true)
+	if err != nil {
+		return err
+	}
+
+	// If the object can unmarshal itself, let it.
+	iv := unsafe.Unreflect(p.stype, unsafe.Pointer(&y[l]))
+	if u, ok := iv.(Unmarshaler); ok {
+		return u.Unmarshal(raw)
+	}
+
+	obuf := o.buf
+	oi := o.index
+	o.buf = raw
+	o.index = 0
+
+	err = o.unmarshalType(p.stype, is_group, bas)
+
+	o.buf = obuf
+	o.index = oi
+
+	return err
+}
diff --git a/proto/encode.go b/proto/encode.go
new file mode 100644
index 0000000..9c323b2
--- /dev/null
+++ b/proto/encode.go
@@ -0,0 +1,557 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto
+
+/*
+ * Routines for encoding data into the wire format for protocol buffers.
+ */
+
+import (
+	"bytes"
+	"os"
+	"reflect"
+	"runtime"
+	"unsafe"
+)
+
+// ErrRequiredNotSet is the error returned if Marshal is called with
+// a protocol buffer struct whose required fields have not
+// all been initialized.
+var ErrRequiredNotSet = os.NewError("required fields not set")
+
+// ErrRepeatedHasNil is the error returned if Marshal is called with
+// a protocol buffer struct with a repeated field containing a nil element.
+var ErrRepeatedHasNil = os.NewError("repeated field has nil")
+
+// ErrNil is the error returned if Marshal is called with nil.
+var ErrNil = os.NewError("marshal called with nil")
+
+// The fundamental encoders that put bytes on the wire.
+// Those that take integer types all accept uint64 and are
+// therefore of type valueEncoder.
+
+// EncodeVarint returns the varint encoding of x.
+// This is the format for the
+// int32, int64, uint32, uint64, bool, and enum
+// protocol buffer types.
+// Not used by the package itself, but helpful to clients
+// wishing to use the same encoding.
+func EncodeVarint(x uint64) []byte {
+	var buf [16]byte
+	var n int
+	for n = 0; x > 127; n++ {
+		buf[n] = 0x80 | uint8(x&0x7F)
+		x >>= 7
+	}
+	buf[n] = uint8(x)
+	n++
+	return buf[0:n]
+}
+
+// EncodeVarint writes a varint-encoded integer to the Buffer.
+// This is the format for the
+// int32, int64, uint32, uint64, bool, and enum
+// protocol buffer types.
+func (p *Buffer) EncodeVarint(x uint64) os.Error {
+	l := len(p.buf)
+	c := cap(p.buf)
+	if l+10 > c {
+		c += c/2 + 10
+		obuf := make([]byte, c)
+		copy(obuf, p.buf)
+		p.buf = obuf
+	}
+	p.buf = p.buf[0:c]
+
+	for {
+		if x < 1<<7 {
+			break
+		}
+		p.buf[l] = uint8(x&0x7f | 0x80)
+		l++
+		x >>= 7
+	}
+	p.buf[l] = uint8(x)
+	p.buf = p.buf[0 : l+1]
+	return nil
+}
+
+// EncodeFixed64 writes a 64-bit integer to the Buffer.
+// This is the format for the
+// fixed64, sfixed64, and double protocol buffer types.
+func (p *Buffer) EncodeFixed64(x uint64) os.Error {
+	l := len(p.buf)
+	c := cap(p.buf)
+	if l+8 > c {
+		c += c/2 + 8
+		obuf := make([]byte, c)
+		copy(obuf, p.buf)
+		p.buf = obuf
+	}
+	p.buf = p.buf[0 : l+8]
+
+	p.buf[l] = uint8(x)
+	p.buf[l+1] = uint8(x >> 8)
+	p.buf[l+2] = uint8(x >> 16)
+	p.buf[l+3] = uint8(x >> 24)
+	p.buf[l+4] = uint8(x >> 32)
+	p.buf[l+5] = uint8(x >> 40)
+	p.buf[l+6] = uint8(x >> 48)
+	p.buf[l+7] = uint8(x >> 56)
+	return nil
+}
+
+// EncodeFixed32 writes a 32-bit integer to the Buffer.
+// This is the format for the
+// fixed32, sfixed32, and float protocol buffer types.
+func (p *Buffer) EncodeFixed32(x uint64) os.Error {
+	l := len(p.buf)
+	c := cap(p.buf)
+	if l+4 > c {
+		c += c/2 + 4
+		obuf := make([]byte, c)
+		copy(obuf, p.buf)
+		p.buf = obuf
+	}
+	p.buf = p.buf[0 : l+4]
+
+	p.buf[l] = uint8(x)
+	p.buf[l+1] = uint8(x >> 8)
+	p.buf[l+2] = uint8(x >> 16)
+	p.buf[l+3] = uint8(x >> 24)
+	return nil
+}
+
+// EncodeZigzag64 writes a zigzag-encoded 64-bit integer
+// to the Buffer.
+// This is the format used for the sint64 protocol buffer type.
+func (p *Buffer) EncodeZigzag64(x uint64) os.Error {
+	// use signed number to get arithmetic right shift.
+	return p.EncodeVarint(uint64((x << 1) ^ uint64((int64(x) >> 63))))
+}
+
+// EncodeZigzag32 writes a zigzag-encoded 32-bit integer
+// to the Buffer.
+// This is the format used for the sint32 protocol buffer type.
+func (p *Buffer) EncodeZigzag32(x uint64) os.Error {
+	// use signed number to get arithmetic right shift.
+	return p.EncodeVarint(uint64((uint32(x) << 1) ^ uint32((int32(x) >> 31))))
+}
+
+// EncodeRawBytes writes a count-delimited byte buffer to the Buffer.
+// This is the format used for the bytes protocol buffer
+// type and for embedded messages.
+func (p *Buffer) EncodeRawBytes(b []byte) os.Error {
+	lb := len(b)
+	p.EncodeVarint(uint64(lb))
+	p.buf = bytes.Add(p.buf, b)
+	return nil
+}
+
+// EncodeStringBytes writes an encoded string to the Buffer.
+// This is the format used for the proto2 string type.
+func (p *Buffer) EncodeStringBytes(s string) os.Error {
+
+	// this works because strings and slices are the same.
+	y := *(*[]byte)(unsafe.Pointer(&s))
+	p.EncodeRawBytes(y)
+	return nil
+}
+
+// Marshaler is the interface representing objects that can marshal themselves.
+type Marshaler interface {
+	Marshal() ([]byte, os.Error)
+}
+
+// Marshal takes the protocol buffer struct represented by pb
+// and encodes it into the wire format, returning the data.
+func Marshal(pb interface{}) ([]byte, os.Error) {
+	// Can the object marshal itself?
+	if m, ok := pb.(Marshaler); ok {
+		return m.Marshal()
+	}
+	p := NewBuffer(nil)
+	err := p.Marshal(pb)
+	if err != nil {
+		return nil, err
+	}
+	return p.buf, err
+}
+
+// Marshal takes the protocol buffer struct represented by pb
+// and encodes it into the wire format, writing the result to the
+// Buffer.
+func (p *Buffer) Marshal(pb interface{}) os.Error {
+	// Can the object marshal itself?
+	if m, ok := pb.(Marshaler); ok {
+		data, err := m.Marshal()
+		if err != nil {
+			return err
+		}
+		p.buf = bytes.Add(p.buf, data)
+		return nil
+	}
+
+	mstat := runtime.MemStats.Mallocs
+
+	t, b, err := getbase(pb)
+	if err == nil {
+		err = p.enc_struct(t.Elem().(*reflect.StructType), b)
+	}
+
+	mstat = runtime.MemStats.Mallocs - mstat
+	stats.Emalloc += mstat
+	stats.Encode++
+
+	return err
+}
+
+// Individual type encoders.
+
+// Encode a bool.
+func (o *Buffer) enc_bool(p *Properties, base uintptr) os.Error {
+	v := *(**uint8)(unsafe.Pointer(base + p.offset))
+	if v == nil {
+		return ErrNil
+	}
+	x := *v
+	if x != 0 {
+		x = 1
+	}
+	o.buf = bytes.Add(o.buf, p.tagcode)
+	p.valEnc(o, uint64(x))
+	return nil
+}
+
+// Encode an int32.
+func (o *Buffer) enc_int32(p *Properties, base uintptr) os.Error {
+	v := *(**uint32)(unsafe.Pointer(base + p.offset))
+	if v == nil {
+		return ErrNil
+	}
+	x := *v
+	o.buf = bytes.Add(o.buf, p.tagcode)
+	p.valEnc(o, uint64(x))
+	return nil
+}
+
+// Encode an int64.
+func (o *Buffer) enc_int64(p *Properties, base uintptr) os.Error {
+	v := *(**uint64)(unsafe.Pointer(base + p.offset))
+	if v == nil {
+		return ErrNil
+	}
+	x := *v
+	o.buf = bytes.Add(o.buf, p.tagcode)
+	p.valEnc(o, uint64(x))
+	return nil
+}
+
+// Encode a string.
+func (o *Buffer) enc_string(p *Properties, base uintptr) os.Error {
+	v := *(**string)(unsafe.Pointer(base + p.offset))
+	if v == nil {
+		return ErrNil
+	}
+	x := *v
+	o.buf = bytes.Add(o.buf, p.tagcode)
+	o.EncodeStringBytes(x)
+	return nil
+}
+
+// Encode a message struct.
+func (o *Buffer) enc_struct_message(p *Properties, base uintptr) os.Error {
+	// Can the object marshal itself?
+	iv := unsafe.Unreflect(p.stype, unsafe.Pointer(base+p.offset))
+	if m, ok := iv.(Marshaler); ok {
+		data, err := m.Marshal()
+		if err != nil {
+			return err
+		}
+		o.buf = bytes.Add(o.buf, p.tagcode)
+		o.EncodeRawBytes(data)
+		return nil
+	}
+	v := *(**struct{})(unsafe.Pointer(base + p.offset))
+	if v == nil {
+		return ErrNil
+	}
+
+	// need the length before we can write out the message itself,
+	// so marshal into a separate byte buffer first.
+	obuf := o.buf
+	o.buf = o.bufalloc()
+
+	b := uintptr(unsafe.Pointer(v))
+	typ := p.stype.Elem().(*reflect.StructType)
+	err := o.enc_struct(typ, b)
+
+	nbuf := o.buf
+	o.buf = obuf
+	if err != nil {
+		o.buffree(nbuf)
+		return err
+	}
+	o.buf = bytes.Add(o.buf, p.tagcode)
+	o.EncodeRawBytes(nbuf)
+	o.buffree(nbuf)
+	return nil
+}
+
+// Encode a group struct.
+func (o *Buffer) enc_struct_group(p *Properties, base uintptr) os.Error {
+	v := *(**struct{})(unsafe.Pointer(base + p.offset))
+	if v == nil {
+		return ErrNil
+	}
+
+	o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
+	b := uintptr(unsafe.Pointer(v))
+	typ := p.stype.Elem().(*reflect.StructType)
+	err := o.enc_struct(typ, b)
+	if err != nil {
+		return err
+	}
+	o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
+	return nil
+}
+
+// Encode a slice of bools ([]bool).
+func (o *Buffer) enc_slice_bool(p *Properties, base uintptr) os.Error {
+	s := *(*[]uint8)(unsafe.Pointer(base + p.offset))
+	l := len(s)
+	if l == 0 {
+		return ErrNil
+	}
+	for _, x := range s {
+		o.buf = bytes.Add(o.buf, p.tagcode)
+		if x != 0 {
+			x = 1
+		}
+		p.valEnc(o, uint64(x))
+	}
+	return nil
+}
+
+// Encode a slice of bytes ([]byte).
+func (o *Buffer) enc_slice_byte(p *Properties, base uintptr) os.Error {
+	s := *(*[]uint8)(unsafe.Pointer(base + p.offset))
+	// if the field is required, we must send something, even if it's an empty array.
+	if !p.Required {
+		l := len(s)
+		if l == 0 {
+			return ErrNil
+		}
+		// check default
+		if l == len(p.Default) {
+			same := true
+			for i := 0; i < len(p.Default); i++ {
+				if p.Default[i] != s[i] {
+					same = false
+					break
+				}
+			}
+			if same {
+				return ErrNil
+			}
+		}
+	}
+	o.buf = bytes.Add(o.buf, p.tagcode)
+	o.EncodeRawBytes(s)
+	return nil
+}
+
+// Encode a slice of int32s ([]int32).
+func (o *Buffer) enc_slice_int32(p *Properties, base uintptr) os.Error {
+	s := *(*[]uint32)(unsafe.Pointer(base + p.offset))
+	l := len(s)
+	if l == 0 {
+		return ErrNil
+	}
+	for i := 0; i < l; i++ {
+		o.buf = bytes.Add(o.buf, p.tagcode)
+		x := s[i]
+		p.valEnc(o, uint64(x))
+	}
+	return nil
+}
+
+// Encode a slice of int64s ([]int64).
+func (o *Buffer) enc_slice_int64(p *Properties, base uintptr) os.Error {
+	s := *(*[]uint64)(unsafe.Pointer(base + p.offset))
+	l := len(s)
+	if l == 0 {
+		return ErrNil
+	}
+	for i := 0; i < l; i++ {
+		o.buf = bytes.Add(o.buf, p.tagcode)
+		x := s[i]
+		p.valEnc(o, uint64(x))
+	}
+	return nil
+}
+
+// Encode a slice of slice of bytes ([][]byte).
+func (o *Buffer) enc_slice_slice_byte(p *Properties, base uintptr) os.Error {
+	ss := *(*[][]uint8)(unsafe.Pointer(base + p.offset))
+	l := len(ss)
+	if l == 0 {
+		return ErrNil
+	}
+	for i := 0; i < l; i++ {
+		o.buf = bytes.Add(o.buf, p.tagcode)
+		s := ss[i]
+		o.EncodeRawBytes(s)
+	}
+	return nil
+}
+
+// Encode a slice of strings ([]string).
+func (o *Buffer) enc_slice_string(p *Properties, base uintptr) os.Error {
+	ss := *(*[]string)(unsafe.Pointer(base + p.offset))
+	l := len(ss)
+	for i := 0; i < l; i++ {
+		o.buf = bytes.Add(o.buf, p.tagcode)
+		s := ss[i]
+		o.EncodeStringBytes(s)
+	}
+	return nil
+}
+
+// Encode a slice of message structs ([]*struct).
+func (o *Buffer) enc_slice_struct_message(p *Properties, base uintptr) os.Error {
+	s := *(*[]*struct{})(unsafe.Pointer(base + p.offset))
+	l := len(s)
+	typ := p.stype.Elem().(*reflect.StructType)
+
+	for i := 0; i < l; i++ {
+		v := s[i]
+		if v == nil {
+			return ErrRepeatedHasNil
+		}
+
+		// Can the object marshal itself?
+		iv := unsafe.Unreflect(p.stype, unsafe.Pointer(&s[i]))
+		if m, ok := iv.(Marshaler); ok {
+			data, err := m.Marshal()
+			if err != nil {
+				return err
+			}
+			o.buf = bytes.Add(o.buf, p.tagcode)
+			o.EncodeRawBytes(data)
+			continue
+		}
+
+		obuf := o.buf
+		o.buf = o.bufalloc()
+
+		b := uintptr(unsafe.Pointer(v))
+		err := o.enc_struct(typ, b)
+
+		nbuf := o.buf
+		o.buf = obuf
+		if err != nil {
+			o.buffree(nbuf)
+			if err == ErrNil {
+				return ErrRepeatedHasNil
+			}
+			return err
+		}
+		o.buf = bytes.Add(o.buf, p.tagcode)
+		o.EncodeRawBytes(nbuf)
+
+		o.buffree(nbuf)
+	}
+	return nil
+}
+
+// Encode a slice of group structs ([]*struct).
+func (o *Buffer) enc_slice_struct_group(p *Properties, base uintptr) os.Error {
+	s := *(*[]*struct{})(unsafe.Pointer(base + p.offset))
+	l := len(s)
+	typ := p.stype.Elem().(*reflect.StructType)
+
+	for i := 0; i < l; i++ {
+		v := s[i]
+		if v == nil {
+			return ErrRepeatedHasNil
+		}
+
+		o.EncodeVarint(uint64((p.Tag << 3) | WireStartGroup))
+
+		b := uintptr(unsafe.Pointer(v))
+		err := o.enc_struct(typ, b)
+
+		if err != nil {
+			if err == ErrNil {
+				return ErrRepeatedHasNil
+			}
+			return err
+		}
+
+		o.EncodeVarint(uint64((p.Tag << 3) | WireEndGroup))
+	}
+	return nil
+}
+
+// Encode an extension map.
+func (o *Buffer) enc_map(p *Properties, base uintptr) os.Error {
+	v := *(*map[int32][]byte)(unsafe.Pointer(base + p.offset))
+	for _, b := range v {
+		o.buf = bytes.Add(o.buf, b)
+	}
+	return nil
+}
+
+// Encode a struct.
+func (o *Buffer) enc_struct(t *reflect.StructType, base uintptr) os.Error {
+	prop := GetProperties(t)
+	required := prop.reqCount
+	for _, p := range prop.Prop {
+		if p.enc != nil {
+			err := p.enc(o, p, base)
+			if err != nil {
+				if err != ErrNil {
+					return err
+				}
+			} else if p.Required {
+				required--
+			}
+		}
+	}
+	// See if we encoded all required fields.
+	if required > 0 {
+		return ErrRequiredNotSet
+	}
+
+	return nil
+}
diff --git a/proto/extensions.go b/proto/extensions.go
new file mode 100644
index 0000000..480e8d3
--- /dev/null
+++ b/proto/extensions.go
@@ -0,0 +1,153 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto
+
+
+/*
+ * Types and routines for supporting protocol buffer extensions.
+ */
+
+import (
+	"os"
+	"reflect"
+	"unsafe"
+)
+
+// ExtensionRange represents a range of message extensions for a protocol buffer.
+// Used in code generated by the protocol compiler.
+type ExtensionRange struct {
+	Start, End int32 // both inclusive
+}
+
+// extendableProto is an interface implemented by any protocol buffer that may be extended.
+type extendableProto interface {
+	ExtensionRangeArray() []ExtensionRange
+	ExtensionMap() map[int32][]byte
+}
+
+// ExtensionDesc represents an extension specification.
+// Used in generated code from the protocol compiler.
+type ExtensionDesc struct {
+	ExtendedType  interface{} // nil pointer to the type that is being extended
+	ExtensionType interface{} // nil pointer to the extension type
+	Field         int32       // field number
+	Tag           string      // PB(...) tag style
+}
+
+// Return true iff the given field number is in an extension range.
+func isExtensionField(extended extendableProto, field int32) bool {
+	for _, er := range extended.ExtensionRangeArray() {
+		if er.Start <= field && field <= er.End {
+			return true
+		}
+	}
+	return false
+}
+
+func checkExtensionTypes(extended extendableProto, extension *ExtensionDesc) os.Error {
+	// Check the extended type.
+	if a, b := reflect.Typeof(extended), reflect.Typeof(extension.ExtendedType); a != b {
+		return os.NewError("bad extended type; " + b.String() + " does not extend " + a.String())
+	}
+	// Check the range.
+	if !isExtensionField(extended, extension.Field) {
+		return os.NewError("bad extension number; not in declared ranges")
+	}
+	return nil
+}
+
+func HasExtension(extended extendableProto, extension *ExtensionDesc) bool {
+	// TODO: Check types, field numbers, etc.?
+	_, ok := extended.ExtensionMap()[extension.Field]
+	return ok
+}
+
+func ClearExtension(extended extendableProto, extension *ExtensionDesc) {
+	// TODO: Check types, field numbers, etc.?
+	extended.ExtensionMap()[extension.Field] = nil, false
+}
+
+func GetExtension(extended extendableProto, extension *ExtensionDesc) (interface{}, os.Error) {
+	if err := checkExtensionTypes(extended, extension); err != nil {
+		return nil, err
+	}
+
+	b, ok := extended.ExtensionMap()[extension.Field]
+	if !ok {
+		return nil, nil // not an error
+	}
+
+	// Discard wire type and field number varint. It isn't needed.
+	_, n := DecodeVarint(b)
+	o := NewBuffer(b[n:])
+
+	t := reflect.Typeof(extension.ExtensionType).(*reflect.PtrType)
+	props := &Properties{}
+	props.Init(t, "irrelevant_name", extension.Tag, 0)
+
+	base := unsafe.New(t)
+	var sbase uintptr
+	if _, ok := t.Elem().(*reflect.StructType); ok {
+		// props.dec will be dec_struct_message, which does not refer to sbase.
+		*(*unsafe.Pointer)(base) = unsafe.New(t.Elem())
+	} else {
+		sbase = uintptr(unsafe.New(t.Elem()))
+	}
+	if err := props.dec(o, props, uintptr(base), sbase); err != nil {
+		return nil, err
+	}
+	return unsafe.Unreflect(t, base), nil
+}
+
+// TODO(: (needed for repeated extensions)
+//   - ExtensionSize
+//   - AddExtension
+
+func SetExtension(extended extendableProto, extension *ExtensionDesc, value interface{}) os.Error {
+	if err := checkExtensionTypes(extended, extension); err != nil {
+		return err
+	}
+	if reflect.Typeof(extension.ExtensionType) != reflect.Typeof(value) {
+		return os.NewError("bad extension value type")
+	}
+
+	props := new(Properties)
+	props.Init(reflect.Typeof(extension.ExtensionType), "unknown_name", extension.Tag, 0)
+
+	p := NewBuffer(nil)
+	v := reflect.NewValue(value)
+	if err := props.enc(p, props, v.Addr()); err != nil {
+		return err
+	}
+	extended.ExtensionMap()[extension.Field] = p.buf
+	return nil
+}
diff --git a/proto/lib.go b/proto/lib.go
new file mode 100644
index 0000000..8660335
--- /dev/null
+++ b/proto/lib.go
@@ -0,0 +1,537 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/*
+	The proto package converts data structures to and from the
+	wire format of protocol buffers.  It works in concert with the
+	Go source code generated for .proto files by the protocol compiler.
+
+	A summary of the properties of the protocol buffer interface
+	for a protocol buffer variable v:
+
+	  - Names are turned from camel_case to CamelCase for export.
+	  - There are no methods on v to set and get fields; just treat
+	  	them as structure fields.
+	  - The zero value for a struct is its correct initialization state.
+		All desired fields must be set before marshaling.
+	  - A Reset() method will restore a protobuf struct to its zero state.
+	  - Each type T has a method NewT() to create a new instance. It
+		is equivalent to new(T).
+	  - Non-repeated fields are pointers to the values; nil means unset.
+		That is, optional or required field int32 f becomes F *int32.
+	  - Repeated fields are slices.
+	  - Helper functions are available to simplify the getting and setting of fields:
+	  	foo.String = proto.String("hello") // set field
+	  	s := proto.GetString(foo.String)  // get field
+	  - Constants are defined to hold the default values of all fields that
+		have them.  They have the form Default_StructName_FieldName.
+	  - Enums are given type names and maps between names to values,
+	  	plus a helper function to create values.  Enum values are prefixed
+	  	with the enum's type name.
+	  - Nested groups and enums have type names prefixed with the name of
+	  	the surrounding message type.
+	  - Marshal and Unmarshal are functions to encode and decode the wire format.
+
+	The simplest way to describe this is to see an example.
+	Given file test.proto, containing
+
+		package example;
+
+		enum FOO { X = 17; };
+
+		message Test {
+		  required string label = 1;
+		  optional int32 type = 2 [default=77];
+		  repeated int64 reps = 3;
+		  optional group OptionalGroup = 4 {
+		    required string RequiredField = 5;
+		  };
+		}
+
+	The resulting file, test.pb.go, is:
+
+		package example
+
+		import "goprotobuf.googlecode.com/hg/proto"
+
+		type FOO int32
+		const (
+			FOO_X = 17
+		)
+		var FOO_name = map[int32] string {
+			17: "X",
+		}
+		var FOO_value = map[string] int32 {
+			"X": 17,
+		}
+		func NewFOO(x int32) *FOO {
+			e := FOO(x)
+			return &e
+		}
+
+		type Test struct {
+			Label	*string	"PB(bytes,1,req,name=label)"
+			Type	*int32	"PB(varint,2,opt,name=type,def=77)"
+			Reps	[]int64	"PB(varint,3,rep,name=reps)"
+			Optionalgroup	*Test_OptionalGroup	"PB(group,4,opt,name=optionalgroup)"
+			XXX_unrecognized []byte
+		}
+		func (this *Test) Reset() {
+			*this = Test{}
+		}
+		func NewTest() *Test {
+			return new(Test)
+		}
+		const Default_Test_Type int32 = 77
+
+		type Test_OptionalGroup struct {
+			RequiredField	*string	"PB(bytes,5,req)"
+			XXX_unrecognized []byte
+		}
+		func (this *Test_OptionalGroup) Reset() {
+			*this = Test_OptionalGroup{}
+		}
+		func NewTest_OptionalGroup() *Test_OptionalGroup {
+			return new(Test_OptionalGroup)
+		}
+
+		func init() {
+			proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
+		}
+
+	To create and play with a Test object:
+
+		package main
+
+		import (
+			"log"
+
+			"goprotobuf.googlecode.com/hg/proto"
+			"./example.pb"
+		)
+
+		func main() {
+			test := &example.Test {
+				Label: proto.String("hello"),
+				Type: proto.Int32(17),
+				Optionalgroup: &example.Test_OptionalGroup {
+					RequiredField: proto.String("good bye"),
+				},
+			}
+			data, err := proto.Marshal(test)
+			if err != nil {
+				log.Exit("marshaling error:", err)
+			}
+			newTest := example.NewTest()
+			err = proto.Unmarshal(data, newTest)
+			if err != nil {
+				log.Exit("unmarshaling error:", err)
+			}
+			// Now test and newTest contain the same data.
+			if proto.GetString(test.Label) != proto.GetString(newTest.Label) {
+				log.Exit("data mismatch %q %q", proto.GetString(test.Label), proto.GetString(newTest.Label))
+			}
+			// etc.
+		}
+*/
+package proto
+
+import (
+	"fmt"
+	"strconv"
+)
+
+// Stats records allocation details about the protocol buffer encoders
+// and decoders.  Useful for tuning the library itself.
+type Stats struct {
+	Emalloc uint64 // mallocs in encode
+	Dmalloc uint64 // mallocs in decode
+	Encode  uint64 // number of encodes
+	Decode  uint64 // number of decodes
+	Chit    uint64 // number of cache hits
+	Cmiss   uint64 // number of cache misses
+}
+
+var stats Stats
+
+// GetStats returns a copy of the global Stats structure.
+func GetStats() Stats { return stats }
+
+// A Buffer is a buffer manager for marshaling and unmarshaling
+// protocol buffers.  It may be reused between invocations to
+// reduce memory usage.  It is not necessary to use a Buffer;
+// the global functions Marshal and Unmarshal create a
+// temporary Buffer and are fine for most applications.
+type Buffer struct {
+	buf       []byte     // encode/decode byte stream
+	index     int        // write point
+	freelist  [10][]byte // list of available buffers
+	nfreelist int        // number of free buffers
+	ptr       uintptr    // scratch area for pointers
+}
+
+// NewBuffer allocates a new Buffer and initializes its internal data to
+// the contents of the argument slice.
+func NewBuffer(e []byte) *Buffer {
+	p := new(Buffer)
+	if e == nil {
+		e = p.bufalloc()
+	}
+	p.buf = e
+	p.index = 0
+	return p
+}
+
+// Reset resets the Buffer, ready for marshaling a new protocol buffer.
+func (p *Buffer) Reset() {
+	if p.buf == nil {
+		p.buf = p.bufalloc()
+	}
+	p.buf = p.buf[0:0] // for reading/writing
+	p.index = 0        // for reading
+}
+
+// SetBuf replaces the internal buffer with the slice,
+// ready for unmarshaling the contents of the slice.
+func (p *Buffer) SetBuf(s []byte) {
+	p.buf = s
+	p.index = 0
+}
+
+// Bytes returns the contents of the Buffer.
+func (p *Buffer) Bytes() []byte { return p.buf }
+
+// Allocate a buffer for the Buffer.
+func (p *Buffer) bufalloc() []byte {
+	if p.nfreelist > 0 {
+		// reuse an old one
+		p.nfreelist--
+		s := p.freelist[p.nfreelist]
+		return s[0:0]
+	}
+	// make a new one
+	s := make([]byte, 0, 16)
+	return s
+}
+
+// Free (and remember in freelist) a byte buffer for the Buffer.
+func (p *Buffer) buffree(s []byte) {
+	if p.nfreelist < len(p.freelist) {
+		// Take next slot.
+		p.freelist[p.nfreelist] = s
+		p.nfreelist++
+		return
+	}
+
+	// Find the smallest.
+	besti := -1
+	bestl := len(s)
+	for i, b := range p.freelist {
+		if len(b) < bestl {
+			besti = i
+			bestl = len(b)
+		}
+	}
+
+	// Overwrite the smallest.
+	if besti >= 0 {
+		p.freelist[besti] = s
+	}
+}
+
+/*
+ * Helper routines for simplifying the creation of optional fields of basic type.
+ */
+
+// Bool is a helper routine that allocates a new bool value
+// to store v and returns a pointer to it.
+func Bool(v bool) *bool {
+	p := new(bool)
+	*p = v
+	return p
+}
+
+// Int32 is a helper routine that allocates a new int32 value
+// to store v and returns a pointer to it.
+func Int32(v int32) *int32 {
+	p := new(int32)
+	*p = v
+	return p
+}
+
+// Int is a helper routine that allocates a new int32 value
+// to store v and returns a pointer to it, but unlike Int32
+// its argument value is an int.
+func Int(v int) *int32 {
+	p := new(int32)
+	*p = int32(v)
+	return p
+}
+
+// Int64 is a helper routine that allocates a new int64 value
+// to store v and returns a pointer to it.
+func Int64(v int64) *int64 {
+	p := new(int64)
+	*p = v
+	return p
+}
+
+// Float32 is a helper routine that allocates a new float32 value
+// to store v and returns a pointer to it.
+func Float32(v float32) *float32 {
+	p := new(float32)
+	*p = v
+	return p
+}
+
+// Float64 is a helper routine that allocates a new float64 value
+// to store v and returns a pointer to it.
+func Float64(v float64) *float64 {
+	p := new(float64)
+	*p = v
+	return p
+}
+
+// Uint32 is a helper routine that allocates a new uint32 value
+// to store v and returns a pointer to it.
+func Uint32(v uint32) *uint32 {
+	p := new(uint32)
+	*p = v
+	return p
+}
+
+// Uint64 is a helper routine that allocates a new uint64 value
+// to store v and returns a pointer to it.
+func Uint64(v uint64) *uint64 {
+	p := new(uint64)
+	*p = v
+	return p
+}
+
+// String is a helper routine that allocates a new string value
+// to store v and returns a pointer to it.
+func String(v string) *string {
+	p := new(string)
+	*p = v
+	return p
+}
+
+/*
+ * Helper routines for simplifying the fetching of optional fields of basic type.
+ * If the field is missing, they return the zero for the type.
+ */
+
+// GetBool is a helper routine that returns an optional bool value.
+func GetBool(p *bool) bool {
+	if p == nil {
+		return false
+	}
+	return *p
+}
+
+// GetInt32 is a helper routine that returns an optional int32 value.
+func GetInt32(p *int32) int32 {
+	if p == nil {
+		return 0
+	}
+	return *p
+}
+
+// GetInt64 is a helper routine that returns an optional int64 value.
+func GetInt64(p *int64) int64 {
+	if p == nil {
+		return 0
+	}
+	return *p
+}
+
+// GetFloat32 is a helper routine that returns an optional float32 value.
+func GetFloat32(p *float32) float32 {
+	if p == nil {
+		return 0
+	}
+	return *p
+}
+
+// GetFloat64 is a helper routine that returns an optional float64 value.
+func GetFloat64(p *float64) float64 {
+	if p == nil {
+		return 0
+	}
+	return *p
+}
+
+// GetUint32 is a helper routine that returns an optional uint32 value.
+func GetUint32(p *uint32) uint32 {
+	if p == nil {
+		return 0
+	}
+	return *p
+}
+
+// GetUint64 is a helper routine that returns an optional uint64 value.
+func GetUint64(p *uint64) uint64 {
+	if p == nil {
+		return 0
+	}
+	return *p
+}
+
+// GetString is a helper routine that returns an optional string value.
+func GetString(p *string) string {
+	if p == nil {
+		return ""
+	}
+	return *p
+}
+
+// EnumName is a helper function to simplify printing protocol buffer enums
+// by name.  Given an enum map and a value, it returns a useful string.
+func EnumName(m map[int32]string, v int32) string {
+	s, ok := m[v]
+	if ok {
+		return s
+	}
+	return "unknown_enum_" + strconv.Itoa(int(v))
+}
+
+// DebugPrint dumps the encoded data in b in a debugging format with a header
+// including the string s. Used in testing but made available for general debugging.
+func (o *Buffer) DebugPrint(s string, b []byte) {
+	var u uint64
+
+	obuf := o.buf
+	index := o.index
+	o.buf = b
+	o.index = 0
+	depth := 0
+
+	fmt.Printf("\n--- %s ---\n", s)
+
+out:
+	for {
+		for i := 0; i < depth; i++ {
+			fmt.Print("  ")
+		}
+
+		index := o.index
+		if index == len(o.buf) {
+			break
+		}
+
+		op, err := o.DecodeVarint()
+		if err != nil {
+			fmt.Printf("%3d: fetching op err %v\n", index, err)
+			break out
+		}
+		tag := op >> 3
+		wire := op & 7
+
+		switch wire {
+		default:
+			fmt.Printf("%3d: t=%3d unknown wire=%d\n",
+				index, tag, wire)
+			break out
+
+		case WireBytes:
+			var r []byte
+
+			r, err = o.DecodeRawBytes(false)
+			if err != nil {
+				break out
+			}
+			fmt.Printf("%3d: t=%3d bytes [%d]", index, tag, len(r))
+			if len(r) <= 6 {
+				for i := 0; i < len(r); i++ {
+					fmt.Printf(" %.2x", r[i])
+				}
+			} else {
+				for i := 0; i < 3; i++ {
+					fmt.Printf(" %.2x", r[i])
+				}
+				fmt.Printf(" ..")
+				for i := len(r) - 3; i < len(r); i++ {
+					fmt.Printf(" %.2x", r[i])
+				}
+			}
+			fmt.Printf("\n")
+
+		case WireFixed32:
+			u, err = o.DecodeFixed32()
+			if err != nil {
+				fmt.Printf("%3d: t=%3d fix32 err %v\n", index, tag, err)
+				break out
+			}
+			fmt.Printf("%3d: t=%3d fix32 %d\n", index, tag, u)
+
+		case WireFixed64:
+			u, err = o.DecodeFixed64()
+			if err != nil {
+				fmt.Printf("%3d: t=%3d fix64 err %v\n", index, tag, err)
+				break out
+			}
+			fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u)
+			break
+
+		case WireVarint:
+			u, err = o.DecodeVarint()
+			if err != nil {
+				fmt.Printf("%3d: t=%3d varint err %v\n", index, tag, err)
+				break out
+			}
+			fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u)
+
+		case WireStartGroup:
+			if err != nil {
+				fmt.Printf("%3d: t=%3d start err %v\n", index, tag, err)
+				break out
+			}
+			fmt.Printf("%3d: t=%3d start\n", index, tag)
+			depth++
+
+		case WireEndGroup:
+			depth--
+			if err != nil {
+				fmt.Printf("%3d: t=%3d end err %v\n", index, tag, err)
+				break out
+			}
+			fmt.Printf("%3d: t=%3d end\n", index, tag)
+		}
+	}
+
+	if depth != 0 {
+		fmt.Printf("%3d: start-end not balanced %d\n", o.index, depth)
+	}
+	fmt.Printf("\n")
+
+	o.buf = obuf
+	o.index = index
+}
diff --git a/proto/properties.go b/proto/properties.go
new file mode 100644
index 0000000..65fd2fe
--- /dev/null
+++ b/proto/properties.go
@@ -0,0 +1,515 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto
+
+/*
+ * Routines for encoding data into the wire format for protocol buffers.
+ */
+
+import (
+	"fmt"
+	"os"
+	"reflect"
+	"runtime"
+	"strconv"
+	"strings"
+	"sync"
+	"unsafe"
+)
+
+const debug bool = false
+
+// Constants that identify the encoding of a value on the wire.
+const (
+	WireVarint     = 0
+	WireFixed64    = 1
+	WireBytes      = 2
+	WireStartGroup = 3
+	WireEndGroup   = 4
+	WireFixed32    = 5
+)
+
+const startSize = 10 // initial slice/string sizes
+
+// Encoders are defined in encoder.go
+// An encoder outputs the full representation of a field, including its
+// tag and encoder type.
+type encoder func(p *Buffer, prop *Properties, base uintptr) os.Error
+
+// A valueEncoder encodes a single integer in a particular encoding.
+type valueEncoder func(o *Buffer, x uint64) os.Error
+
+// Decoders are defined in decode.go
+// A decoder creates a value from its wire representation.
+// Unrecognized subelements are saved in unrec.
+type decoder func(p *Buffer, prop *Properties, base uintptr, sbase uintptr) os.Error
+
+// A valueDecoder decodes a single integer in a particular encoding.
+type valueDecoder func(o *Buffer) (x uint64, err os.Error)
+
+// StructProperties represents properties for all the fields of a struct.
+type StructProperties struct {
+	Prop     []*Properties // properties for each field
+	reqCount int           // required count
+	tags     map[int]int   // map from proto tag to struct field number
+	nscratch uintptr       // size of scratch space
+}
+
+// Properties represents the protocol-specific behavior of a single struct field.
+type Properties struct {
+	Name       string // name of the field, for error messages
+	OrigName   string // original name before protocol compiler (always set)
+	Wire       string
+	WireType   int
+	Tag        int
+	Required   bool
+	Optional   bool
+	Repeated   bool
+	Enum       string // set for enum types only
+	Default    string // default value
+	def_uint64 uint64
+
+	enc     encoder
+	valEnc  valueEncoder // set for bool and numeric types only
+	offset  uintptr
+	tagcode []byte // encoding of EncodeVarint((Tag<<3)|WireType)
+	tagbuf  [8]byte
+	stype   *reflect.PtrType
+
+	dec     decoder
+	valDec  valueDecoder // set for bool and numeric types only
+	scratch uintptr
+	sizeof  int // calculations of scratch space
+	alignof int
+}
+
+// String formats the properties in the "PB(...)" struct tag style.
+func (p *Properties) String() string {
+	s := p.Wire
+	s = ","
+	s += strconv.Itoa(p.Tag)
+	if p.Required {
+		s += ",req"
+	}
+	if p.Optional {
+		s += ",opt"
+	}
+	if p.Repeated {
+		s += ",rep"
+	}
+	if p.OrigName != p.Name {
+		s += ",name=" + p.OrigName
+	}
+	if len(p.Enum) > 0 {
+		s += ",enum=" + p.Enum
+	}
+	if len(p.Default) > 0 {
+		s += ",def=" + p.Default
+	}
+	return s
+}
+
+// Parse populates p by parsing a string in the "PB(...)" struct tag style.
+func (p *Properties) Parse(s string) {
+	// "bytes,49,opt,def=hello!,name=foo"
+	fields := strings.Split(s, ",", 0) // breaks def=, but handled below.
+	if len(fields) < 2 {
+		fmt.Fprintf(os.Stderr, "proto: tag has too few fields: %q\n", s)
+		return
+	}
+
+	p.Wire = fields[0]
+	switch p.Wire {
+	case "varint":
+		p.WireType = WireVarint
+		p.valEnc = (*Buffer).EncodeVarint
+		p.valDec = (*Buffer).DecodeVarint
+	case "fixed32":
+		p.WireType = WireFixed32
+		p.valEnc = (*Buffer).EncodeFixed32
+		p.valDec = (*Buffer).DecodeFixed32
+	case "fixed64":
+		p.WireType = WireFixed64
+		p.valEnc = (*Buffer).EncodeFixed64
+		p.valDec = (*Buffer).DecodeFixed64
+	case "zigzag32":
+		p.WireType = WireVarint
+		p.valEnc = (*Buffer).EncodeZigzag32
+		p.valDec = (*Buffer).DecodeZigzag32
+	case "zigzag64":
+		p.WireType = WireVarint
+		p.valEnc = (*Buffer).EncodeZigzag64
+		p.valDec = (*Buffer).DecodeZigzag64
+	case "bytes", "group":
+		p.WireType = WireBytes
+		// no numeric converter for non-numeric types
+	default:
+		fmt.Fprintf(os.Stderr, "proto: tag has unknown wire type: %q\n", s)
+		return
+	}
+
+	var err os.Error
+	p.Tag, err = strconv.Atoi(fields[1])
+	if err != nil {
+		return
+	}
+
+	for i := 2; i < len(fields); i++ {
+		f := fields[i]
+		switch {
+		case f == "req":
+			p.Required = true
+		case f == "opt":
+			p.Optional = true
+		case f == "rep":
+			p.Repeated = true
+		case len(f) >= 5 && f[0:5] == "name=":
+			p.OrigName = f[5:len(f)]
+		case len(f) >= 5 && f[0:5] == "enum=":
+			p.Enum = f[5:len(f)]
+		case len(f) >= 4 && f[0:4] == "def=":
+			p.Default = f[4:len(f)] // rest of string
+			if i+1 < len(fields) {
+				// Commas aren't escaped, and def is always last.
+				p.Default += "," + strings.Join(fields[i+1:len(fields)], ",")
+				break
+			}
+		}
+	}
+}
+
+// Initialize the fields for encoding and decoding.
+func (p *Properties) setEncAndDec(typ reflect.Type) {
+	var vbool bool
+	var vbyte byte
+	var vint32 int32
+	var vint64 int64
+	var vfloat32 float32
+	var vfloat64 float64
+	var vstring string
+	var vslice []byte
+
+	p.enc = nil
+	p.dec = nil
+
+	switch t1 := typ.(type) {
+	default:
+		fmt.Fprintf(os.Stderr, "proto: no coders for %T\n", t1)
+		break
+
+	case *reflect.PtrType:
+		switch t2 := t1.Elem().(type) {
+		default:
+			fmt.Fprintf(os.Stderr, "proto: no encoder function for %T -> %T\n", t1, t2)
+			break
+		case *reflect.BoolType:
+			p.enc = (*Buffer).enc_bool
+			p.dec = (*Buffer).dec_bool
+			p.alignof = unsafe.Alignof(vbool)
+			p.sizeof = unsafe.Sizeof(vbool)
+		case *reflect.Int32Type, *reflect.Uint32Type:
+			p.enc = (*Buffer).enc_int32
+			p.dec = (*Buffer).dec_int32
+			p.alignof = unsafe.Alignof(vint32)
+			p.sizeof = unsafe.Sizeof(vint32)
+		case *reflect.Int64Type, *reflect.Uint64Type:
+			p.enc = (*Buffer).enc_int64
+			p.dec = (*Buffer).dec_int64
+			p.alignof = unsafe.Alignof(vint64)
+			p.sizeof = unsafe.Sizeof(vint64)
+		case *reflect.Float32Type:
+			p.enc = (*Buffer).enc_int32 // can just treat them as bits
+			p.dec = (*Buffer).dec_int32
+			p.alignof = unsafe.Alignof(vfloat32)
+			p.sizeof = unsafe.Sizeof(vfloat32)
+		case *reflect.Float64Type:
+			p.enc = (*Buffer).enc_int64 // can just treat them as bits
+			p.dec = (*Buffer).dec_int64
+			p.alignof = unsafe.Alignof(vfloat64)
+			p.sizeof = unsafe.Sizeof(vfloat64)
+		case *reflect.StringType:
+			p.enc = (*Buffer).enc_string
+			p.dec = (*Buffer).dec_string
+			p.alignof = unsafe.Alignof(vstring)
+			p.sizeof = unsafe.Sizeof(vstring) + startSize*unsafe.Sizeof(vbyte)
+		case *reflect.StructType:
+			p.stype = t1
+			if p.Wire == "bytes" {
+				p.enc = (*Buffer).enc_struct_message
+				p.dec = (*Buffer).dec_struct_message
+			} else {
+				p.enc = (*Buffer).enc_struct_group
+				p.dec = (*Buffer).dec_struct_group
+			}
+		}
+
+	case *reflect.SliceType:
+		switch t2 := t1.Elem().(type) {
+		default:
+			fmt.Fprintf(os.Stderr, "proto: no oenc for %T -> %T\n", t1, t2)
+			break
+		case *reflect.Uint8Type:
+			p.enc = (*Buffer).enc_slice_byte
+			p.dec = (*Buffer).dec_slice_byte
+			p.alignof = unsafe.Alignof(vbyte)
+			p.sizeof = startSize * unsafe.Sizeof(vbyte)
+		case *reflect.BoolType:
+			p.enc = (*Buffer).enc_slice_bool
+			p.dec = (*Buffer).dec_slice_bool
+			p.alignof = unsafe.Alignof(vbool)
+			p.sizeof = startSize * unsafe.Sizeof(vbool)
+		case *reflect.Int32Type, *reflect.Uint32Type:
+			p.enc = (*Buffer).enc_slice_int32
+			p.dec = (*Buffer).dec_slice_int32
+			p.alignof = unsafe.Alignof(vint32)
+			p.sizeof = startSize * unsafe.Sizeof(vint32)
+		case *reflect.Int64Type, *reflect.Uint64Type:
+			p.enc = (*Buffer).enc_slice_int64
+			p.dec = (*Buffer).dec_slice_int64
+			p.alignof = unsafe.Alignof(vint64)
+			p.sizeof = startSize * unsafe.Sizeof(vint64)
+		case *reflect.Float32Type:
+			p.enc = (*Buffer).enc_slice_int32 // can just treat them as bits
+			p.dec = (*Buffer).dec_slice_int32
+			p.alignof = unsafe.Alignof(vfloat32)
+			p.sizeof = startSize * unsafe.Sizeof(vfloat32)
+		case *reflect.Float64Type:
+			p.enc = (*Buffer).enc_slice_int64 // can just treat them as bits
+			p.dec = (*Buffer).dec_slice_int64
+			p.alignof = unsafe.Alignof(vfloat64)
+			p.sizeof = startSize * unsafe.Sizeof(vfloat64)
+		case *reflect.StringType:
+			p.enc = (*Buffer).enc_slice_string
+			p.dec = (*Buffer).dec_slice_string
+			p.alignof = unsafe.Alignof(vstring)
+			p.sizeof = startSize * unsafe.Sizeof(vstring)
+		case *reflect.PtrType:
+			switch t3 := t2.Elem().(type) {
+			default:
+				fmt.Fprintf(os.Stderr, "proto: no oenc for %T -> %T -> %T\n", t1, t2, t3)
+				break
+			case *reflect.StructType:
+				p.stype = t2
+				p.enc = (*Buffer).enc_slice_struct_group
+				p.dec = (*Buffer).dec_slice_struct_group
+				if p.Wire == "bytes" {
+					p.enc = (*Buffer).enc_slice_struct_message
+					p.dec = (*Buffer).dec_slice_struct_message
+				}
+				p.alignof = unsafe.Alignof(vslice)
+				p.sizeof = startSize * unsafe.Sizeof(vslice)
+			}
+		case *reflect.SliceType:
+			switch t3 := t2.Elem().(type) {
+			default:
+				fmt.Fprintf(os.Stderr, "proto: no oenc for %T -> %T -> %T\n", t1, t2, t3)
+				break
+			case *reflect.Uint8Type:
+				p.enc = (*Buffer).enc_slice_slice_byte
+				p.dec = (*Buffer).dec_slice_slice_byte
+				p.alignof = unsafe.Alignof(vslice)
+				p.sizeof = startSize * unsafe.Sizeof(vslice)
+			}
+		}
+	}
+
+	// precalculate tag code
+	x := p.Tag<<3 | p.WireType
+	i := 0
+	for i = 0; x > 127; i++ {
+		p.tagbuf[i] = 0x80 | uint8(x&0x7F)
+		x >>= 7
+	}
+	p.tagbuf[i] = uint8(x)
+	p.tagcode = p.tagbuf[0 : i+1]
+}
+
+// Init populates the properties from a protocol buffer struct field.
+func (p *Properties) Init(typ reflect.Type, name, tag string, offset uintptr) {
+	// "PB(bytes,49,opt,def=hello!)"
+	// TODO: should not assume the only thing is PB(...)
+	p.Name = name
+	p.OrigName = name
+	p.offset = offset
+
+	if len(tag) < 4 || tag[0:3] != "PB(" || tag[len(tag)-1] != ')' {
+		return
+	}
+	p.Parse(tag[3 : len(tag)-1])
+	p.setEncAndDec(typ)
+}
+
+var (
+	mutex         sync.Mutex
+	propertiesMap = make(map[*reflect.StructType]*StructProperties)
+)
+
+// GetProperties returns the list of properties for the type represented by t.
+func GetProperties(t *reflect.StructType) *StructProperties {
+	mutex.Lock()
+	if prop, ok := propertiesMap[t]; ok {
+		mutex.Unlock()
+		stats.Chit++
+		return prop
+	}
+	stats.Cmiss++
+
+	prop := new(StructProperties)
+
+	// build properties
+	prop.Prop = make([]*Properties, t.NumField())
+	for i := 0; i < t.NumField(); i++ {
+		f := t.Field(i)
+		p := new(Properties)
+		p.Init(f.Type, f.Name, f.Tag, f.Offset)
+		if f.Name == "XXX_extensions" { // special case
+			var vmap map[int32][]byte
+			p.enc = (*Buffer).enc_map
+			p.dec = nil // not needed
+			p.alignof = unsafe.Alignof(vmap)
+			p.sizeof = unsafe.Sizeof(vmap)
+		}
+		prop.Prop[i] = p
+		if debug {
+			print(i, " ", f.Name, " ", t.String(), " ")
+			if p.Tag > 0 {
+				print(p.String())
+			}
+			print("\n")
+		}
+		if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
+			fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
+		}
+	}
+
+	// build required counts
+	// build scratch offsets
+	// build tags
+	reqCount := 0
+	scratch := uintptr(0)
+	prop.tags = make(map[int]int)
+	for i, p := range prop.Prop {
+		if p.Required {
+			reqCount++
+		}
+		scratch = align(scratch, p.alignof)
+		p.scratch = scratch
+		scratch += uintptr(p.sizeof)
+		prop.tags[p.Tag] = i
+	}
+	prop.reqCount = reqCount
+	prop.nscratch = scratch
+
+	propertiesMap[t] = prop
+	mutex.Unlock()
+	return prop
+}
+
+// Alignment of the data in the scratch area.  It doesn't have to be
+// exact, just conservative.  Returns the first number >= o that divides s.
+func align(o uintptr, s int) uintptr {
+	if s != 0 {
+		for o%uintptr(s) != 0 {
+			o++
+		}
+	}
+	return o
+}
+
+// Return the field index of the named field.
+// Returns nil if there is no such field.
+func fieldIndex(t *reflect.StructType, name string) []int {
+	if field, ok := t.FieldByName(name); ok {
+		return field.Index
+	}
+	return nil
+}
+
+// Return the Properties object for the x[0]'th field of the structure.
+func propByIndex(t *reflect.StructType, x []int) *Properties {
+	if len(x) != 1 {
+		fmt.Fprintf(os.Stderr, "proto: field index dimension %d (not 1) for type %s\n", len(x), t)
+		return nil
+	}
+	prop := GetProperties(t)
+	return prop.Prop[x[0]]
+}
+
+// Get the address and type of a pointer to the structure from an interface.
+// unsafe.Reflect can do this, but does multiple mallocs.
+func getbase(pb interface{}) (t *reflect.PtrType, b uintptr, err os.Error) {
+	// get pointer
+	x := *(*[2]uintptr)(unsafe.Pointer(&pb))
+	b = x[1]
+	if b == 0 {
+		err = ErrNil
+		return
+	}
+
+	// get the reflect type of the struct.
+	t1 := unsafe.Typeof(pb).(*runtime.PtrType)
+	t = (*reflect.PtrType)(unsafe.Pointer(t1))
+	return
+}
+
+// Allocate the aux space containing all the decoded data.  The structure
+// handed into Unmarshal is filled with pointers to this newly allocated
+// data.
+func getsbase(prop *StructProperties) uintptr {
+	var vbyteptr *byte
+	if prop.nscratch == 0 {
+		return 0
+	}
+
+	// allocate the decode space as pointers
+	// so that the GC will scan it for pointers
+	n := uintptr(unsafe.Sizeof(vbyteptr))
+	b := make([]*byte, (prop.nscratch+n-1)/n)
+	sbase := uintptr(unsafe.Pointer(&b[0]))
+	return sbase
+}
+
+// A global registry of enum types.
+// The generated code will register the generated maps by calling RegisterEnum.
+
+var enumNameMaps = make(map[string]map[int32]string)
+var enumValueMaps = make(map[string]map[string]int32)
+
+// RegisterEnum is called from the generated code to install the enum descriptor
+// maps into the global table to aid parsing ASCII protocol buffers.
+func RegisterEnum(typeName string, nameMap map[int32]string, valueMap map[string]int32) {
+	if _, ok := enumNameMaps[typeName]; ok {
+		panicln("proto: duplicate enum registered: ", typeName)
+	}
+	enumNameMaps[typeName] = nameMap
+	enumValueMaps[typeName] = valueMap
+}
diff --git a/proto/testdata/Makefile b/proto/testdata/Makefile
new file mode 100644
index 0000000..d0e00c1
--- /dev/null
+++ b/proto/testdata/Makefile
@@ -0,0 +1,53 @@
+# Go support for Protocol Buffers - Google's data interchange format
+#
+# Copyright 2010 Google Inc.  All rights reserved.
+# http://code.google.com/p/goprotobuf/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+include $(GOROOT)/src/Make.$(GOARCH)
+include $(GOROOT)/src/pkg/goprotobuf.googlecode.com/hg/Make.protobuf
+
+TARG=test_proto
+GOFILES=\
+	test.pb.go\
+
+include $(GOROOT)/src/Make.pkg
+
+CLEANFILES+=test.pb.go
+
+# These rules are just aids to development. Not needed for testing.
+regenerate:
+	rm test.pb.go
+	make test.pb.go
+
+restore:
+	cp test.pb.go.golden test.pb.go
+
+preserve:
+	cp test.pb.go test.pb.go.golden
diff --git a/proto/testdata/test.pb.go b/proto/testdata/test.pb.go
new file mode 100644
index 0000000..b237996
--- /dev/null
+++ b/proto/testdata/test.pb.go
@@ -0,0 +1,334 @@
+// Code generated by protoc-gen-go from "test.proto"
+// DO NOT EDIT!
+
+package test_proto
+
+import "goprotobuf.googlecode.com/hg/proto"
+
+type FOO int32
+const (
+	FOO_FOO1 = 1
+)
+var FOO_name = map[int32] string {
+	1: "FOO1",
+}
+var FOO_value = map[string] int32 {
+	"FOO1": 1,
+}
+func NewFOO(x int32) *FOO {
+	e := FOO(x)
+	return &e
+}
+
+type GoTest_KIND int32
+const (
+	GoTest_VOID = 0
+	GoTest_BOOL = 1
+	GoTest_BYTES = 2
+	GoTest_FINGERPRINT = 3
+	GoTest_FLOAT = 4
+	GoTest_INT = 5
+	GoTest_STRING = 6
+	GoTest_TIME = 7
+	GoTest_TUPLE = 8
+	GoTest_ARRAY = 9
+	GoTest_MAP = 10
+	GoTest_TABLE = 11
+	GoTest_FUNCTION = 12
+)
+var GoTest_KIND_name = map[int32] string {
+	0: "VOID",
+	1: "BOOL",
+	2: "BYTES",
+	3: "FINGERPRINT",
+	4: "FLOAT",
+	5: "INT",
+	6: "STRING",
+	7: "TIME",
+	8: "TUPLE",
+	9: "ARRAY",
+	10: "MAP",
+	11: "TABLE",
+	12: "FUNCTION",
+}
+var GoTest_KIND_value = map[string] int32 {
+	"VOID": 0,
+	"BOOL": 1,
+	"BYTES": 2,
+	"FINGERPRINT": 3,
+	"FLOAT": 4,
+	"INT": 5,
+	"STRING": 6,
+	"TIME": 7,
+	"TUPLE": 8,
+	"ARRAY": 9,
+	"MAP": 10,
+	"TABLE": 11,
+	"FUNCTION": 12,
+}
+func NewGoTest_KIND(x int32) *GoTest_KIND {
+	e := GoTest_KIND(x)
+	return &e
+}
+
+type MyMessage_Color int32
+const (
+	MyMessage_RED = 0
+	MyMessage_GREEN = 1
+	MyMessage_BLUE = 2
+)
+var MyMessage_Color_name = map[int32] string {
+	0: "RED",
+	1: "GREEN",
+	2: "BLUE",
+}
+var MyMessage_Color_value = map[string] int32 {
+	"RED": 0,
+	"GREEN": 1,
+	"BLUE": 2,
+}
+func NewMyMessage_Color(x int32) *MyMessage_Color {
+	e := MyMessage_Color(x)
+	return &e
+}
+
+type GoEnum struct {
+	Foo	*FOO	"PB(varint,1,req,name=foo,enum=test_proto.FOO)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoEnum) Reset() {
+	*this = GoEnum{}
+}
+func NewGoEnum() *GoEnum {
+	return new(GoEnum)
+}
+
+type GoTestField struct {
+	Label	*string	"PB(bytes,1,req)"
+	Type	*string	"PB(bytes,2,req)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoTestField) Reset() {
+	*this = GoTestField{}
+}
+func NewGoTestField() *GoTestField {
+	return new(GoTestField)
+}
+
+type GoTest struct {
+	Kind	*int32	"PB(varint,1,req)"
+	Table	*string	"PB(bytes,2,opt)"
+	Param	*int32	"PB(varint,3,opt)"
+	RequiredField	*GoTestField	"PB(bytes,4,req)"
+	RepeatedField	[]*GoTestField	"PB(bytes,5,rep)"
+	OptionalField	*GoTestField	"PB(bytes,6,opt)"
+	F_BoolRequired	*bool	"PB(varint,10,req,name=F_Bool_required)"
+	F_Int32Required	*int32	"PB(varint,11,req,name=F_Int32_required)"
+	F_Int64Required	*int64	"PB(varint,12,req,name=F_Int64_required)"
+	F_Fixed32Required	*uint32	"PB(fixed32,13,req,name=F_Fixed32_required)"
+	F_Fixed64Required	*uint64	"PB(fixed64,14,req,name=F_Fixed64_required)"
+	F_Uint32Required	*uint32	"PB(varint,15,req,name=F_Uint32_required)"
+	F_Uint64Required	*uint64	"PB(varint,16,req,name=F_Uint64_required)"
+	F_FloatRequired	*float32	"PB(fixed32,17,req,name=F_Float_required)"
+	F_DoubleRequired	*float64	"PB(fixed64,18,req,name=F_Double_required)"
+	F_StringRequired	*string	"PB(bytes,19,req,name=F_String_required)"
+	F_BytesRequired	[]byte	"PB(bytes,101,req,name=F_Bytes_required)"
+	F_Sint32Required	*int32	"PB(zigzag32,102,req,name=F_Sint32_required)"
+	F_Sint64Required	*int64	"PB(zigzag64,103,req,name=F_Sint64_required)"
+	F_BoolRepeated	[]bool	"PB(varint,20,rep,name=F_Bool_repeated)"
+	F_Int32Repeated	[]int32	"PB(varint,21,rep,name=F_Int32_repeated)"
+	F_Int64Repeated	[]int64	"PB(varint,22,rep,name=F_Int64_repeated)"
+	F_Fixed32Repeated	[]uint32	"PB(fixed32,23,rep,name=F_Fixed32_repeated)"
+	F_Fixed64Repeated	[]uint64	"PB(fixed64,24,rep,name=F_Fixed64_repeated)"
+	F_Uint32Repeated	[]uint32	"PB(varint,25,rep,name=F_Uint32_repeated)"
+	F_Uint64Repeated	[]uint64	"PB(varint,26,rep,name=F_Uint64_repeated)"
+	F_FloatRepeated	[]float32	"PB(fixed32,27,rep,name=F_Float_repeated)"
+	F_DoubleRepeated	[]float64	"PB(fixed64,28,rep,name=F_Double_repeated)"
+	F_StringRepeated	[]string	"PB(bytes,29,rep,name=F_String_repeated)"
+	F_BytesRepeated	[][]byte	"PB(bytes,201,rep,name=F_Bytes_repeated)"
+	F_Sint32Repeated	[]int32	"PB(zigzag32,202,rep,name=F_Sint32_repeated)"
+	F_Sint64Repeated	[]int64	"PB(zigzag64,203,rep,name=F_Sint64_repeated)"
+	F_BoolOptional	*bool	"PB(varint,30,opt,name=F_Bool_optional)"
+	F_Int32Optional	*int32	"PB(varint,31,opt,name=F_Int32_optional)"
+	F_Int64Optional	*int64	"PB(varint,32,opt,name=F_Int64_optional)"
+	F_Fixed32Optional	*uint32	"PB(fixed32,33,opt,name=F_Fixed32_optional)"
+	F_Fixed64Optional	*uint64	"PB(fixed64,34,opt,name=F_Fixed64_optional)"
+	F_Uint32Optional	*uint32	"PB(varint,35,opt,name=F_Uint32_optional)"
+	F_Uint64Optional	*uint64	"PB(varint,36,opt,name=F_Uint64_optional)"
+	F_FloatOptional	*float32	"PB(fixed32,37,opt,name=F_Float_optional)"
+	F_DoubleOptional	*float64	"PB(fixed64,38,opt,name=F_Double_optional)"
+	F_StringOptional	*string	"PB(bytes,39,opt,name=F_String_optional)"
+	F_BytesOptional	[]byte	"PB(bytes,301,opt,name=F_Bytes_optional)"
+	F_Sint32Optional	*int32	"PB(zigzag32,302,opt,name=F_Sint32_optional)"
+	F_Sint64Optional	*int64	"PB(zigzag64,303,opt,name=F_Sint64_optional)"
+	F_BoolDefaulted	*bool	"PB(varint,40,opt,name=F_Bool_defaulted,def=1)"
+	F_Int32Defaulted	*int32	"PB(varint,41,opt,name=F_Int32_defaulted,def=32)"
+	F_Int64Defaulted	*int64	"PB(varint,42,opt,name=F_Int64_defaulted,def=64)"
+	F_Fixed32Defaulted	*uint32	"PB(fixed32,43,opt,name=F_Fixed32_defaulted,def=320)"
+	F_Fixed64Defaulted	*uint64	"PB(fixed64,44,opt,name=F_Fixed64_defaulted,def=640)"
+	F_Uint32Defaulted	*uint32	"PB(varint,45,opt,name=F_Uint32_defaulted,def=3200)"
+	F_Uint64Defaulted	*uint64	"PB(varint,46,opt,name=F_Uint64_defaulted,def=6400)"
+	F_FloatDefaulted	*float32	"PB(fixed32,47,opt,name=F_Float_defaulted,def=314159)"
+	F_DoubleDefaulted	*float64	"PB(fixed64,48,opt,name=F_Double_defaulted,def=271828)"
+	F_StringDefaulted	*string	"PB(bytes,49,opt,name=F_String_defaulted,def=hello, \\\"world!\\\"\\n)"
+	F_BytesDefaulted	[]byte	"PB(bytes,401,opt,name=F_Bytes_defaulted,def=Bignose)"
+	F_Sint32Defaulted	*int32	"PB(zigzag32,402,opt,name=F_Sint32_defaulted,def=-32)"
+	F_Sint64Defaulted	*int64	"PB(zigzag64,403,opt,name=F_Sint64_defaulted,def=-64)"
+	Requiredgroup	*GoTest_RequiredGroup	"PB(group,70,req,name=requiredgroup)"
+	Repeatedgroup	[]*GoTest_RepeatedGroup	"PB(group,80,rep,name=repeatedgroup)"
+	Optionalgroup	*GoTest_OptionalGroup	"PB(group,90,opt,name=optionalgroup)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoTest) Reset() {
+	*this = GoTest{}
+}
+func NewGoTest() *GoTest {
+	return new(GoTest)
+}
+const Default_GoTest_F_BoolDefaulted bool = true
+const Default_GoTest_F_Int32Defaulted int32 = 32
+const Default_GoTest_F_Int64Defaulted int64 = 64
+const Default_GoTest_F_Fixed32Defaulted uint32 = 320
+const Default_GoTest_F_Fixed64Defaulted uint64 = 640
+const Default_GoTest_F_Uint32Defaulted uint32 = 3200
+const Default_GoTest_F_Uint64Defaulted uint64 = 6400
+const Default_GoTest_F_FloatDefaulted float32 = 314159
+const Default_GoTest_F_DoubleDefaulted float64 = 271828
+const Default_GoTest_F_StringDefaulted string = "hello, \"world!\"\n"
+var Default_GoTest_F_BytesDefaulted []byte = []byte("Bignose")
+const Default_GoTest_F_Sint32Defaulted int32 = -32
+const Default_GoTest_F_Sint64Defaulted int64 = -64
+
+type GoTest_RequiredGroup struct {
+	RequiredField	*string	"PB(bytes,71,req)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoTest_RequiredGroup) Reset() {
+	*this = GoTest_RequiredGroup{}
+}
+func NewGoTest_RequiredGroup() *GoTest_RequiredGroup {
+	return new(GoTest_RequiredGroup)
+}
+
+type GoTest_RepeatedGroup struct {
+	RequiredField	*string	"PB(bytes,81,req)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoTest_RepeatedGroup) Reset() {
+	*this = GoTest_RepeatedGroup{}
+}
+func NewGoTest_RepeatedGroup() *GoTest_RepeatedGroup {
+	return new(GoTest_RepeatedGroup)
+}
+
+type GoTest_OptionalGroup struct {
+	RequiredField	*string	"PB(bytes,91,req)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoTest_OptionalGroup) Reset() {
+	*this = GoTest_OptionalGroup{}
+}
+func NewGoTest_OptionalGroup() *GoTest_OptionalGroup {
+	return new(GoTest_OptionalGroup)
+}
+
+type GoSkipTest struct {
+	SkipInt32	*int32	"PB(varint,11,req,name=skip_int32)"
+	SkipFixed32	*uint32	"PB(fixed32,12,req,name=skip_fixed32)"
+	SkipFixed64	*uint64	"PB(fixed64,13,req,name=skip_fixed64)"
+	SkipString	*string	"PB(bytes,14,req,name=skip_string)"
+	Skipgroup	*GoSkipTest_SkipGroup	"PB(group,15,req,name=skipgroup)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoSkipTest) Reset() {
+	*this = GoSkipTest{}
+}
+func NewGoSkipTest() *GoSkipTest {
+	return new(GoSkipTest)
+}
+
+type GoSkipTest_SkipGroup struct {
+	GroupInt32	*int32	"PB(varint,16,req,name=group_int32)"
+	GroupString	*string	"PB(bytes,17,req,name=group_string)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoSkipTest_SkipGroup) Reset() {
+	*this = GoSkipTest_SkipGroup{}
+}
+func NewGoSkipTest_SkipGroup() *GoSkipTest_SkipGroup {
+	return new(GoSkipTest_SkipGroup)
+}
+
+type InnerMessage struct {
+	Host	*string	"PB(bytes,1,req,name=host)"
+	Port	*int32	"PB(varint,2,opt,name=port,def=4000)"
+	Connected	*bool	"PB(varint,3,opt,name=connected)"
+	XXX_unrecognized	[]byte
+}
+func (this *InnerMessage) Reset() {
+	*this = InnerMessage{}
+}
+func NewInnerMessage() *InnerMessage {
+	return new(InnerMessage)
+}
+const Default_InnerMessage_Port int32 = 4000
+
+type OtherMessage struct {
+	Key	*int64	"PB(varint,1,opt,name=key)"
+	Value	[]byte	"PB(bytes,2,opt,name=value)"
+	Weight	*float32	"PB(fixed32,3,opt,name=weight)"
+	Inner	*InnerMessage	"PB(bytes,4,opt,name=inner)"
+	XXX_unrecognized	[]byte
+}
+func (this *OtherMessage) Reset() {
+	*this = OtherMessage{}
+}
+func NewOtherMessage() *OtherMessage {
+	return new(OtherMessage)
+}
+
+type MyMessage struct {
+	Count	*int32	"PB(varint,1,req,name=count)"
+	Name	*string	"PB(bytes,2,opt,name=name)"
+	Quote	*string	"PB(bytes,3,opt,name=quote)"
+	Pet	[]string	"PB(bytes,4,rep,name=pet)"
+	Inner	*InnerMessage	"PB(bytes,5,opt,name=inner)"
+	Others	[]*OtherMessage	"PB(bytes,6,rep,name=others)"
+	Bikeshed	*MyMessage_Color	"PB(varint,7,opt,name=bikeshed,enum=test_proto.MyMessage_Color)"
+	XXX_unrecognized	[]byte
+}
+func (this *MyMessage) Reset() {
+	*this = MyMessage{}
+}
+func NewMyMessage() *MyMessage {
+	return new(MyMessage)
+}
+
+type MessageList struct {
+	Message	[]*MessageList_Message	"PB(group,1,rep,name=message)"
+	XXX_unrecognized	[]byte
+}
+func (this *MessageList) Reset() {
+	*this = MessageList{}
+}
+func NewMessageList() *MessageList {
+	return new(MessageList)
+}
+
+type MessageList_Message struct {
+	Name	*string	"PB(bytes,2,req,name=name)"
+	Count	*int32	"PB(varint,3,req,name=count)"
+	XXX_unrecognized	[]byte
+}
+func (this *MessageList_Message) Reset() {
+	*this = MessageList_Message{}
+}
+func NewMessageList_Message() *MessageList_Message {
+	return new(MessageList_Message)
+}
+
+func init() {
+	proto.RegisterEnum("test_proto.FOO", FOO_name, FOO_value)
+	proto.RegisterEnum("test_proto.GoTest_KIND", GoTest_KIND_name, GoTest_KIND_value)
+	proto.RegisterEnum("test_proto.MyMessage_Color", MyMessage_Color_name, MyMessage_Color_value)
+}
diff --git a/proto/testdata/test.pb.go.golden b/proto/testdata/test.pb.go.golden
new file mode 100644
index 0000000..b237996
--- /dev/null
+++ b/proto/testdata/test.pb.go.golden
@@ -0,0 +1,334 @@
+// Code generated by protoc-gen-go from "test.proto"
+// DO NOT EDIT!
+
+package test_proto
+
+import "goprotobuf.googlecode.com/hg/proto"
+
+type FOO int32
+const (
+	FOO_FOO1 = 1
+)
+var FOO_name = map[int32] string {
+	1: "FOO1",
+}
+var FOO_value = map[string] int32 {
+	"FOO1": 1,
+}
+func NewFOO(x int32) *FOO {
+	e := FOO(x)
+	return &e
+}
+
+type GoTest_KIND int32
+const (
+	GoTest_VOID = 0
+	GoTest_BOOL = 1
+	GoTest_BYTES = 2
+	GoTest_FINGERPRINT = 3
+	GoTest_FLOAT = 4
+	GoTest_INT = 5
+	GoTest_STRING = 6
+	GoTest_TIME = 7
+	GoTest_TUPLE = 8
+	GoTest_ARRAY = 9
+	GoTest_MAP = 10
+	GoTest_TABLE = 11
+	GoTest_FUNCTION = 12
+)
+var GoTest_KIND_name = map[int32] string {
+	0: "VOID",
+	1: "BOOL",
+	2: "BYTES",
+	3: "FINGERPRINT",
+	4: "FLOAT",
+	5: "INT",
+	6: "STRING",
+	7: "TIME",
+	8: "TUPLE",
+	9: "ARRAY",
+	10: "MAP",
+	11: "TABLE",
+	12: "FUNCTION",
+}
+var GoTest_KIND_value = map[string] int32 {
+	"VOID": 0,
+	"BOOL": 1,
+	"BYTES": 2,
+	"FINGERPRINT": 3,
+	"FLOAT": 4,
+	"INT": 5,
+	"STRING": 6,
+	"TIME": 7,
+	"TUPLE": 8,
+	"ARRAY": 9,
+	"MAP": 10,
+	"TABLE": 11,
+	"FUNCTION": 12,
+}
+func NewGoTest_KIND(x int32) *GoTest_KIND {
+	e := GoTest_KIND(x)
+	return &e
+}
+
+type MyMessage_Color int32
+const (
+	MyMessage_RED = 0
+	MyMessage_GREEN = 1
+	MyMessage_BLUE = 2
+)
+var MyMessage_Color_name = map[int32] string {
+	0: "RED",
+	1: "GREEN",
+	2: "BLUE",
+}
+var MyMessage_Color_value = map[string] int32 {
+	"RED": 0,
+	"GREEN": 1,
+	"BLUE": 2,
+}
+func NewMyMessage_Color(x int32) *MyMessage_Color {
+	e := MyMessage_Color(x)
+	return &e
+}
+
+type GoEnum struct {
+	Foo	*FOO	"PB(varint,1,req,name=foo,enum=test_proto.FOO)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoEnum) Reset() {
+	*this = GoEnum{}
+}
+func NewGoEnum() *GoEnum {
+	return new(GoEnum)
+}
+
+type GoTestField struct {
+	Label	*string	"PB(bytes,1,req)"
+	Type	*string	"PB(bytes,2,req)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoTestField) Reset() {
+	*this = GoTestField{}
+}
+func NewGoTestField() *GoTestField {
+	return new(GoTestField)
+}
+
+type GoTest struct {
+	Kind	*int32	"PB(varint,1,req)"
+	Table	*string	"PB(bytes,2,opt)"
+	Param	*int32	"PB(varint,3,opt)"
+	RequiredField	*GoTestField	"PB(bytes,4,req)"
+	RepeatedField	[]*GoTestField	"PB(bytes,5,rep)"
+	OptionalField	*GoTestField	"PB(bytes,6,opt)"
+	F_BoolRequired	*bool	"PB(varint,10,req,name=F_Bool_required)"
+	F_Int32Required	*int32	"PB(varint,11,req,name=F_Int32_required)"
+	F_Int64Required	*int64	"PB(varint,12,req,name=F_Int64_required)"
+	F_Fixed32Required	*uint32	"PB(fixed32,13,req,name=F_Fixed32_required)"
+	F_Fixed64Required	*uint64	"PB(fixed64,14,req,name=F_Fixed64_required)"
+	F_Uint32Required	*uint32	"PB(varint,15,req,name=F_Uint32_required)"
+	F_Uint64Required	*uint64	"PB(varint,16,req,name=F_Uint64_required)"
+	F_FloatRequired	*float32	"PB(fixed32,17,req,name=F_Float_required)"
+	F_DoubleRequired	*float64	"PB(fixed64,18,req,name=F_Double_required)"
+	F_StringRequired	*string	"PB(bytes,19,req,name=F_String_required)"
+	F_BytesRequired	[]byte	"PB(bytes,101,req,name=F_Bytes_required)"
+	F_Sint32Required	*int32	"PB(zigzag32,102,req,name=F_Sint32_required)"
+	F_Sint64Required	*int64	"PB(zigzag64,103,req,name=F_Sint64_required)"
+	F_BoolRepeated	[]bool	"PB(varint,20,rep,name=F_Bool_repeated)"
+	F_Int32Repeated	[]int32	"PB(varint,21,rep,name=F_Int32_repeated)"
+	F_Int64Repeated	[]int64	"PB(varint,22,rep,name=F_Int64_repeated)"
+	F_Fixed32Repeated	[]uint32	"PB(fixed32,23,rep,name=F_Fixed32_repeated)"
+	F_Fixed64Repeated	[]uint64	"PB(fixed64,24,rep,name=F_Fixed64_repeated)"
+	F_Uint32Repeated	[]uint32	"PB(varint,25,rep,name=F_Uint32_repeated)"
+	F_Uint64Repeated	[]uint64	"PB(varint,26,rep,name=F_Uint64_repeated)"
+	F_FloatRepeated	[]float32	"PB(fixed32,27,rep,name=F_Float_repeated)"
+	F_DoubleRepeated	[]float64	"PB(fixed64,28,rep,name=F_Double_repeated)"
+	F_StringRepeated	[]string	"PB(bytes,29,rep,name=F_String_repeated)"
+	F_BytesRepeated	[][]byte	"PB(bytes,201,rep,name=F_Bytes_repeated)"
+	F_Sint32Repeated	[]int32	"PB(zigzag32,202,rep,name=F_Sint32_repeated)"
+	F_Sint64Repeated	[]int64	"PB(zigzag64,203,rep,name=F_Sint64_repeated)"
+	F_BoolOptional	*bool	"PB(varint,30,opt,name=F_Bool_optional)"
+	F_Int32Optional	*int32	"PB(varint,31,opt,name=F_Int32_optional)"
+	F_Int64Optional	*int64	"PB(varint,32,opt,name=F_Int64_optional)"
+	F_Fixed32Optional	*uint32	"PB(fixed32,33,opt,name=F_Fixed32_optional)"
+	F_Fixed64Optional	*uint64	"PB(fixed64,34,opt,name=F_Fixed64_optional)"
+	F_Uint32Optional	*uint32	"PB(varint,35,opt,name=F_Uint32_optional)"
+	F_Uint64Optional	*uint64	"PB(varint,36,opt,name=F_Uint64_optional)"
+	F_FloatOptional	*float32	"PB(fixed32,37,opt,name=F_Float_optional)"
+	F_DoubleOptional	*float64	"PB(fixed64,38,opt,name=F_Double_optional)"
+	F_StringOptional	*string	"PB(bytes,39,opt,name=F_String_optional)"
+	F_BytesOptional	[]byte	"PB(bytes,301,opt,name=F_Bytes_optional)"
+	F_Sint32Optional	*int32	"PB(zigzag32,302,opt,name=F_Sint32_optional)"
+	F_Sint64Optional	*int64	"PB(zigzag64,303,opt,name=F_Sint64_optional)"
+	F_BoolDefaulted	*bool	"PB(varint,40,opt,name=F_Bool_defaulted,def=1)"
+	F_Int32Defaulted	*int32	"PB(varint,41,opt,name=F_Int32_defaulted,def=32)"
+	F_Int64Defaulted	*int64	"PB(varint,42,opt,name=F_Int64_defaulted,def=64)"
+	F_Fixed32Defaulted	*uint32	"PB(fixed32,43,opt,name=F_Fixed32_defaulted,def=320)"
+	F_Fixed64Defaulted	*uint64	"PB(fixed64,44,opt,name=F_Fixed64_defaulted,def=640)"
+	F_Uint32Defaulted	*uint32	"PB(varint,45,opt,name=F_Uint32_defaulted,def=3200)"
+	F_Uint64Defaulted	*uint64	"PB(varint,46,opt,name=F_Uint64_defaulted,def=6400)"
+	F_FloatDefaulted	*float32	"PB(fixed32,47,opt,name=F_Float_defaulted,def=314159)"
+	F_DoubleDefaulted	*float64	"PB(fixed64,48,opt,name=F_Double_defaulted,def=271828)"
+	F_StringDefaulted	*string	"PB(bytes,49,opt,name=F_String_defaulted,def=hello, \\\"world!\\\"\\n)"
+	F_BytesDefaulted	[]byte	"PB(bytes,401,opt,name=F_Bytes_defaulted,def=Bignose)"
+	F_Sint32Defaulted	*int32	"PB(zigzag32,402,opt,name=F_Sint32_defaulted,def=-32)"
+	F_Sint64Defaulted	*int64	"PB(zigzag64,403,opt,name=F_Sint64_defaulted,def=-64)"
+	Requiredgroup	*GoTest_RequiredGroup	"PB(group,70,req,name=requiredgroup)"
+	Repeatedgroup	[]*GoTest_RepeatedGroup	"PB(group,80,rep,name=repeatedgroup)"
+	Optionalgroup	*GoTest_OptionalGroup	"PB(group,90,opt,name=optionalgroup)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoTest) Reset() {
+	*this = GoTest{}
+}
+func NewGoTest() *GoTest {
+	return new(GoTest)
+}
+const Default_GoTest_F_BoolDefaulted bool = true
+const Default_GoTest_F_Int32Defaulted int32 = 32
+const Default_GoTest_F_Int64Defaulted int64 = 64
+const Default_GoTest_F_Fixed32Defaulted uint32 = 320
+const Default_GoTest_F_Fixed64Defaulted uint64 = 640
+const Default_GoTest_F_Uint32Defaulted uint32 = 3200
+const Default_GoTest_F_Uint64Defaulted uint64 = 6400
+const Default_GoTest_F_FloatDefaulted float32 = 314159
+const Default_GoTest_F_DoubleDefaulted float64 = 271828
+const Default_GoTest_F_StringDefaulted string = "hello, \"world!\"\n"
+var Default_GoTest_F_BytesDefaulted []byte = []byte("Bignose")
+const Default_GoTest_F_Sint32Defaulted int32 = -32
+const Default_GoTest_F_Sint64Defaulted int64 = -64
+
+type GoTest_RequiredGroup struct {
+	RequiredField	*string	"PB(bytes,71,req)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoTest_RequiredGroup) Reset() {
+	*this = GoTest_RequiredGroup{}
+}
+func NewGoTest_RequiredGroup() *GoTest_RequiredGroup {
+	return new(GoTest_RequiredGroup)
+}
+
+type GoTest_RepeatedGroup struct {
+	RequiredField	*string	"PB(bytes,81,req)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoTest_RepeatedGroup) Reset() {
+	*this = GoTest_RepeatedGroup{}
+}
+func NewGoTest_RepeatedGroup() *GoTest_RepeatedGroup {
+	return new(GoTest_RepeatedGroup)
+}
+
+type GoTest_OptionalGroup struct {
+	RequiredField	*string	"PB(bytes,91,req)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoTest_OptionalGroup) Reset() {
+	*this = GoTest_OptionalGroup{}
+}
+func NewGoTest_OptionalGroup() *GoTest_OptionalGroup {
+	return new(GoTest_OptionalGroup)
+}
+
+type GoSkipTest struct {
+	SkipInt32	*int32	"PB(varint,11,req,name=skip_int32)"
+	SkipFixed32	*uint32	"PB(fixed32,12,req,name=skip_fixed32)"
+	SkipFixed64	*uint64	"PB(fixed64,13,req,name=skip_fixed64)"
+	SkipString	*string	"PB(bytes,14,req,name=skip_string)"
+	Skipgroup	*GoSkipTest_SkipGroup	"PB(group,15,req,name=skipgroup)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoSkipTest) Reset() {
+	*this = GoSkipTest{}
+}
+func NewGoSkipTest() *GoSkipTest {
+	return new(GoSkipTest)
+}
+
+type GoSkipTest_SkipGroup struct {
+	GroupInt32	*int32	"PB(varint,16,req,name=group_int32)"
+	GroupString	*string	"PB(bytes,17,req,name=group_string)"
+	XXX_unrecognized	[]byte
+}
+func (this *GoSkipTest_SkipGroup) Reset() {
+	*this = GoSkipTest_SkipGroup{}
+}
+func NewGoSkipTest_SkipGroup() *GoSkipTest_SkipGroup {
+	return new(GoSkipTest_SkipGroup)
+}
+
+type InnerMessage struct {
+	Host	*string	"PB(bytes,1,req,name=host)"
+	Port	*int32	"PB(varint,2,opt,name=port,def=4000)"
+	Connected	*bool	"PB(varint,3,opt,name=connected)"
+	XXX_unrecognized	[]byte
+}
+func (this *InnerMessage) Reset() {
+	*this = InnerMessage{}
+}
+func NewInnerMessage() *InnerMessage {
+	return new(InnerMessage)
+}
+const Default_InnerMessage_Port int32 = 4000
+
+type OtherMessage struct {
+	Key	*int64	"PB(varint,1,opt,name=key)"
+	Value	[]byte	"PB(bytes,2,opt,name=value)"
+	Weight	*float32	"PB(fixed32,3,opt,name=weight)"
+	Inner	*InnerMessage	"PB(bytes,4,opt,name=inner)"
+	XXX_unrecognized	[]byte
+}
+func (this *OtherMessage) Reset() {
+	*this = OtherMessage{}
+}
+func NewOtherMessage() *OtherMessage {
+	return new(OtherMessage)
+}
+
+type MyMessage struct {
+	Count	*int32	"PB(varint,1,req,name=count)"
+	Name	*string	"PB(bytes,2,opt,name=name)"
+	Quote	*string	"PB(bytes,3,opt,name=quote)"
+	Pet	[]string	"PB(bytes,4,rep,name=pet)"
+	Inner	*InnerMessage	"PB(bytes,5,opt,name=inner)"
+	Others	[]*OtherMessage	"PB(bytes,6,rep,name=others)"
+	Bikeshed	*MyMessage_Color	"PB(varint,7,opt,name=bikeshed,enum=test_proto.MyMessage_Color)"
+	XXX_unrecognized	[]byte
+}
+func (this *MyMessage) Reset() {
+	*this = MyMessage{}
+}
+func NewMyMessage() *MyMessage {
+	return new(MyMessage)
+}
+
+type MessageList struct {
+	Message	[]*MessageList_Message	"PB(group,1,rep,name=message)"
+	XXX_unrecognized	[]byte
+}
+func (this *MessageList) Reset() {
+	*this = MessageList{}
+}
+func NewMessageList() *MessageList {
+	return new(MessageList)
+}
+
+type MessageList_Message struct {
+	Name	*string	"PB(bytes,2,req,name=name)"
+	Count	*int32	"PB(varint,3,req,name=count)"
+	XXX_unrecognized	[]byte
+}
+func (this *MessageList_Message) Reset() {
+	*this = MessageList_Message{}
+}
+func NewMessageList_Message() *MessageList_Message {
+	return new(MessageList_Message)
+}
+
+func init() {
+	proto.RegisterEnum("test_proto.FOO", FOO_name, FOO_value)
+	proto.RegisterEnum("test_proto.GoTest_KIND", GoTest_KIND_name, GoTest_KIND_value)
+	proto.RegisterEnum("test_proto.MyMessage_Color", MyMessage_Color_name, MyMessage_Color_value)
+}
diff --git a/proto/testdata/test.proto b/proto/testdata/test.proto
new file mode 100644
index 0000000..474ec39
--- /dev/null
+++ b/proto/testdata/test.proto
@@ -0,0 +1,209 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// A feature-rich test file for the protocol compiler and libraries.
+
+syntax = "proto2";
+
+package test_proto;
+
+enum FOO { FOO1 = 1; };
+
+message GoEnum {
+  required FOO foo = 1;
+}
+
+message GoTestField {
+  required string Label = 1;
+  required string Type = 2;
+}
+
+message GoTest {
+  // An enum, for completeness.
+  enum KIND {
+    VOID = 0;
+
+    // Basic types
+    BOOL = 1;
+    BYTES = 2;
+    FINGERPRINT = 3;
+    FLOAT = 4;
+    INT = 5;
+    STRING = 6;
+    TIME = 7;
+
+    // Groupings
+    TUPLE = 8;
+    ARRAY = 9;
+    MAP = 10;
+
+    // Table types
+    TABLE = 11;
+
+    // Functions
+    FUNCTION = 12;  // last tag
+  };
+
+  // Some typical parameters
+  required int32 Kind = 1;
+  optional string Table = 2;
+  optional int32 Param = 3;
+
+  // Required, repeated and optional foreign fields.
+  required GoTestField RequiredField = 4;
+  repeated GoTestField RepeatedField = 5;
+  optional GoTestField OptionalField = 6;
+
+  // Required fields of all basic types
+  required bool F_Bool_required = 10;
+  required int32 F_Int32_required = 11;
+  required int64 F_Int64_required = 12;
+  required fixed32 F_Fixed32_required = 13;
+  required fixed64 F_Fixed64_required = 14;
+  required uint32 F_Uint32_required = 15;
+  required uint64 F_Uint64_required = 16;
+  required float F_Float_required = 17;
+  required double F_Double_required = 18;
+  required string F_String_required = 19;
+  required bytes F_Bytes_required = 101;
+  required sint32 F_Sint32_required = 102;
+  required sint64 F_Sint64_required = 103;
+
+  // Repeated fields of all basic types
+  repeated bool F_Bool_repeated = 20;
+  repeated int32 F_Int32_repeated = 21;
+  repeated int64 F_Int64_repeated = 22;
+  repeated fixed32 F_Fixed32_repeated = 23;
+  repeated fixed64 F_Fixed64_repeated = 24;
+  repeated uint32 F_Uint32_repeated = 25;
+  repeated uint64 F_Uint64_repeated = 26;
+  repeated float F_Float_repeated = 27;
+  repeated double F_Double_repeated = 28;
+  repeated string F_String_repeated = 29;
+  repeated bytes F_Bytes_repeated = 201;
+  repeated sint32 F_Sint32_repeated = 202;
+  repeated sint64 F_Sint64_repeated = 203;
+
+  // Optional fields of all basic types
+  optional bool F_Bool_optional = 30;
+  optional int32 F_Int32_optional = 31;
+  optional int64 F_Int64_optional = 32;
+  optional fixed32 F_Fixed32_optional = 33;
+  optional fixed64 F_Fixed64_optional = 34;
+  optional uint32 F_Uint32_optional = 35;
+  optional uint64 F_Uint64_optional = 36;
+  optional float F_Float_optional = 37;
+  optional double F_Double_optional = 38;
+  optional string F_String_optional = 39;
+  optional bytes F_Bytes_optional = 301;
+  optional sint32 F_Sint32_optional = 302;
+  optional sint64 F_Sint64_optional = 303;
+
+  // Default-valued fields of all basic types
+  optional bool F_Bool_defaulted = 40 [default=true];
+  optional int32 F_Int32_defaulted = 41 [default=32];
+  optional int64 F_Int64_defaulted = 42 [default=64];
+  optional fixed32 F_Fixed32_defaulted = 43 [default=320];
+  optional fixed64 F_Fixed64_defaulted = 44 [default=640];
+  optional uint32 F_Uint32_defaulted = 45 [default=3200];
+  optional uint64 F_Uint64_defaulted = 46 [default=6400];
+  optional float F_Float_defaulted = 47 [default=314159.];
+  optional double F_Double_defaulted = 48 [default=271828.];
+  optional string F_String_defaulted = 49 [default="hello, \"world!\"\n"];
+  optional bytes F_Bytes_defaulted = 401 [default="Bignose"];
+  optional sint32 F_Sint32_defaulted = 402 [default = -32];
+  optional sint64 F_Sint64_defaulted = 403 [default = -64];
+
+  // Required, repeated, and optional groups.
+  required group RequiredGroup = 70 {
+    required string RequiredField = 71;
+  };
+
+  repeated group RepeatedGroup = 80 {
+    required string RequiredField = 81;
+  };
+
+  optional group OptionalGroup = 90 {
+    required string RequiredField = 91;
+  };
+};
+
+// For testing skipping of unrecognized fields.
+// Numbers are all big, larger than tag numbers in GoTestField,
+// the message used in the corresponding test.
+message GoSkipTest {
+  required int32 skip_int32 = 11;
+  required fixed32 skip_fixed32 = 12;
+  required fixed64 skip_fixed64 = 13;
+  required string skip_string = 14;
+  required group SkipGroup = 15 {
+    required int32 group_int32 = 16;
+    required string group_string = 17;
+  }
+}
+
+// Smaller tests for ASCII formatting.
+
+message InnerMessage {
+  required string host = 1;
+  optional int32 port = 2 [default=4000];
+  optional bool connected = 3;
+}
+
+message OtherMessage {
+  optional int64 key = 1;
+  optional bytes value = 2;
+  optional float weight = 3;
+  optional InnerMessage inner = 4;
+}
+
+message MyMessage {
+  required int32 count = 1;
+  optional string name = 2;
+  optional string quote = 3;
+  repeated string pet = 4;
+  optional InnerMessage inner = 5;
+  repeated OtherMessage others = 6;
+
+  enum Color {
+    RED = 0;
+    GREEN = 1;
+    BLUE = 2;
+  };
+  optional Color bikeshed = 7;
+}
+
+message MessageList {
+  repeated group Message = 1 {
+    required string name = 2;
+    required int32 count = 3;
+  };
+};
diff --git a/proto/text.go b/proto/text.go
new file mode 100644
index 0000000..ccb8ae5
--- /dev/null
+++ b/proto/text.go
@@ -0,0 +1,221 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto
+
+// Functions for writing the Text protocol buffer format.
+// TODO:
+//	- groups.
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"strconv"
+	"strings"
+)
+
+// An io.Writer wrapper that tracks its indentation level.
+type textWriter struct {
+	indent_level int
+	complete     bool // if the current position is a complete line
+	compact      bool // whether to write out as a one-liner
+	writer       io.Writer
+}
+
+func (w *textWriter) Write(p []byte) (n int, err os.Error) {
+	n, err = len(p), nil
+
+	frags := strings.Split(string(p), "\n", 0)
+	if w.compact {
+		w.writer.Write([]byte(strings.Join(frags, " ")))
+		return
+	}
+
+	for i := 0; i < len(frags); i++ {
+		if w.complete {
+			for j := 0; j < w.indent_level; j++ {
+				w.writer.Write([]byte{' ', ' '})
+			}
+			w.complete = false
+		}
+
+		w.writer.Write([]byte(frags[i]))
+		if i+1 < len(frags) {
+			w.writer.Write([]byte{'\n'})
+		}
+	}
+	w.complete = len(frags[len(frags)-1]) == 0
+
+	return
+}
+
+func (w *textWriter) indent() { w.indent_level++ }
+
+func (w *textWriter) unindent() {
+	if w.indent_level == 0 {
+		fmt.Fprintln(os.Stderr, "proto: textWriter unindented too far!")
+	} else {
+		w.indent_level--
+	}
+}
+
+func writeStruct(w *textWriter, sv *reflect.StructValue) {
+	st := sv.Type().(*reflect.StructType)
+	sprops := GetProperties(st)
+	for i := 0; i < sv.NumField(); i++ {
+		if strings.HasPrefix(st.Field(i).Name, "XXX_") {
+			continue
+		}
+		props := sprops.Prop[i]
+		fv := sv.Field(i)
+		if pv, ok := fv.(*reflect.PtrValue); ok && pv.IsNil() {
+			// Field not filled in. This could be an optional field or
+			// a required field that wasn't filled in. Either way, there
+			// isn't anything we can show for it.
+			continue
+		}
+		if av, ok := fv.(*reflect.SliceValue); ok && av.IsNil() {
+			// Repeated field that is empty, or a bytes field that is unused.
+			continue
+		}
+
+		if props.Repeated {
+			if av, ok := fv.(*reflect.SliceValue); ok {
+				// Repeated field.
+				for j := 0; j < av.Len(); j++ {
+					fmt.Fprintf(w, "%v:", props.OrigName)
+					if !w.compact {
+						w.Write([]byte{' '})
+					}
+					writeAny(w, av.Elem(j))
+					fmt.Fprint(w, "\n")
+				}
+				continue
+			}
+		}
+
+		fmt.Fprintf(w, "%v:", props.OrigName)
+		if !w.compact {
+			w.Write([]byte{' '})
+		}
+		if len(props.Enum) == 0 || !tryWriteEnum(w, props.Enum, fv) {
+			writeAny(w, fv)
+		}
+		fmt.Fprint(w, "\n")
+	}
+}
+
+func tryWriteEnum(w *textWriter, enum string, v reflect.Value) bool {
+	val, ok := reflect.Indirect(v).(*reflect.Int32Value)
+	if !ok {
+		return false
+	}
+	m, ok := enumNameMaps[enum]
+	if !ok {
+		return false
+	}
+	str, ok := m[val.Get()]
+	if !ok {
+		return false
+	}
+	fmt.Fprintf(w, str)
+	return true
+}
+
+func writeAny(w *textWriter, v reflect.Value) {
+	v = reflect.Indirect(v)
+
+	// We don't attempt to serialise every possible value type; only those
+	// that can occur in protocol buffers, plus a few extra that were easy.
+	switch val := v.(type) {
+	case *reflect.SliceValue:
+		// Should only be a []byte; repeated fields are handled in writeStruct.
+		// TODO: Handle other cases cleaner.
+		bytes := make([]byte, val.Len())
+		for i := 0; i < val.Len(); i++ {
+			bytes[i] = val.Elem(i).(*reflect.Uint8Value).Get()
+		}
+		// TODO: Should be strconv.QuoteC, which doesn't exist yet
+		fmt.Fprint(w, strconv.Quote(string(bytes)))
+	case *reflect.StringValue:
+		// TODO: Should be strconv.QuoteC, which doesn't exist yet
+		fmt.Fprint(w, strconv.Quote(val.Get()))
+	case *reflect.StructValue:
+		// Required/optional group/message.
+		// TODO: groups use { } instead of < >, and no colon.
+		if !w.compact {
+			fmt.Fprint(w, "<\n")
+		} else {
+			fmt.Fprint(w, "<")
+		}
+		w.indent()
+		writeStruct(w, val)
+		w.unindent()
+		fmt.Fprint(w, ">")
+	default:
+		fmt.Fprint(w, val.Interface())
+	}
+}
+
+func marshalText(w io.Writer, pb interface{}, compact bool) {
+	aw := new(textWriter)
+	aw.writer = w
+	aw.complete = true
+	aw.compact = compact
+
+	v := reflect.NewValue(pb)
+	// We should normally be passed a struct, or a pointer to a struct,
+	// and we don't want the outer < and > in that case.
+	v = reflect.Indirect(v)
+	if sv, ok := v.(*reflect.StructValue); ok {
+		writeStruct(aw, sv)
+	} else {
+		writeAny(aw, v)
+	}
+}
+
+// MarshalText writes a given protobuffer in Text format.
+// Non-protobuffers can also be written, but their formatting is not guaranteed.
+func MarshalText(w io.Writer, pb interface{}) { marshalText(w, pb, false) }
+
+// CompactText writes a given protobuffer in compact Text format (one line).
+// Non-protobuffers can also be written, but their formatting is not guaranteed.
+func CompactText(w io.Writer, pb interface{}) { marshalText(w, pb, true) }
+
+// CompactTextString is the same as CompactText, but returns the string directly.
+func CompactTextString(pb interface{}) string {
+	buf := new(bytes.Buffer)
+	marshalText(buf, pb, true)
+	return buf.String()
+}
diff --git a/proto/text_parser.go b/proto/text_parser.go
new file mode 100644
index 0000000..e1c0832
--- /dev/null
+++ b/proto/text_parser.go
@@ -0,0 +1,473 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto
+
+// Functions for parsing the Text protocol buffer format.
+// TODO:
+//     - groups.
+
+import (
+	"fmt"
+	"os"
+	"reflect"
+	"strconv"
+)
+
+// ParseError satisfies the os.Error interface.
+type ParseError struct {
+	Message string
+	Line    int // 1-based line number
+	Offset  int // 0-based byte offset from start of input
+}
+
+func (p *ParseError) String() string {
+	if p.Line == 1 {
+		// show offset only for first line
+		return fmt.Sprintf("line 1.%d: %v", p.Offset, p.Message)
+	}
+	return fmt.Sprintf("line %d: %v", p.Line, p.Message)
+}
+
+type token struct {
+	value    string
+	err      *ParseError
+	line     int    // line number
+	offset   int    // byte number from start of input, not start of line
+	unquoted string // the unquoted version of value, if it was a quoted string
+}
+
+func (t *token) String() string {
+	if t.err == nil {
+		return fmt.Sprintf("%q (line=%d, offset=%d)", t.value, t.line, t.offset)
+	}
+	return fmt.Sprintf("parse error: %v", t.err)
+}
+
+type textParser struct {
+	s            string // remaining input
+	done         bool   // whether the parsing is finished (success or error)
+	backed       bool   // whether back() was called
+	offset, line int
+	cur          token
+}
+
+func newTextParser(s string) *textParser {
+	p := new(textParser)
+	p.s = s
+	p.line = 1
+	p.cur.line = 1
+	return p
+}
+
+func (p *textParser) error(format string, a ...interface{}) *ParseError {
+	pe := &ParseError{fmt.Sprintf(format, a), p.cur.line, p.cur.offset}
+	p.cur.err = pe
+	p.done = true
+	return pe
+}
+
+// Numbers and identifiers are matched by [-+._A-Za-z0-9]
+func isIdentOrNumberChar(c byte) bool {
+	switch {
+	case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z':
+		return true
+	case '0' <= c && c <= '9':
+		return true
+	}
+	switch c {
+	case '-', '+', '.', '_':
+		return true
+	}
+	return false
+}
+
+func isWhitespace(c byte) bool {
+	switch c {
+	case ' ', '\t', '\n', '\r':
+		return true
+	}
+	return false
+}
+
+func (p *textParser) skipWhitespace() {
+	i := 0
+	for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
+		if p.s[i] == '#' {
+			// comment; skip to end of line or input
+			for i < len(p.s) && p.s[i] != '\n' {
+				i++
+			}
+			if i == len(p.s) {
+				break
+			}
+		}
+		if p.s[i] == '\n' {
+			p.line++
+		}
+		i++
+	}
+	p.offset += i
+	p.s = p.s[i:len(p.s)]
+	if len(p.s) == 0 {
+		p.done = true
+	}
+}
+
+func (p *textParser) advance() {
+	// Skip whitespace
+	p.skipWhitespace()
+	if p.done {
+		return
+	}
+
+	// Start of non-whitespace
+	p.cur.err = nil
+	p.cur.offset, p.cur.line = p.offset, p.line
+	p.cur.unquoted = ""
+	switch p.s[0] {
+	case '<', '>', '{', '}', ':':
+		// Single symbol
+		p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
+	case '"':
+		// Quoted string
+		i := 1
+		for i < len(p.s) && p.s[i] != '"' && p.s[i] != '\n' {
+			if p.s[i] == '\\' && i+1 < len(p.s) {
+				// skip escaped char
+				i++
+			}
+			i++
+		}
+		if i >= len(p.s) || p.s[i] != '"' {
+			p.error("unmatched quote")
+			return
+		}
+		// TODO: Should be UnquoteC.
+		unq, err := strconv.Unquote(p.s[0 : i+1])
+		if err != nil {
+			p.error("invalid quoted string %v", p.s[0:i+1])
+			return
+		}
+		p.cur.value, p.s = p.s[0:i+1], p.s[i+1:len(p.s)]
+		p.cur.unquoted = unq
+	default:
+		i := 0
+		for i < len(p.s) && isIdentOrNumberChar(p.s[i]) {
+			i++
+		}
+		if i == 0 {
+			p.error("unexpected byte %#x", p.s[0])
+			return
+		}
+		p.cur.value, p.s = p.s[0:i], p.s[i:len(p.s)]
+	}
+	p.offset += len(p.cur.value)
+}
+
+// Back off the parser by one token. Can only be done between calls to next().
+// It makes the next advance() a no-op.
+func (p *textParser) back() { p.backed = true }
+
+// Advances the parser and returns the new current token.
+func (p *textParser) next() *token {
+	if p.backed || p.done {
+		p.backed = false
+		return &p.cur
+	}
+	p.advance()
+	if p.done {
+		p.cur.value = ""
+	} else if len(p.cur.value) > 0 && p.cur.value[0] == '"' {
+		// Look for multiple quoted strings separated by whitespace,
+		// and concatenate them.
+		cat := p.cur
+		for {
+			p.skipWhitespace()
+			if p.done || p.s[0] != '"' {
+				break
+			}
+			p.advance()
+			if p.cur.err != nil {
+				return &p.cur
+			}
+			cat.value += " " + p.cur.value
+			cat.unquoted += p.cur.unquoted
+		}
+		p.done = false // parser may have seen EOF, but we want to return cat
+		p.cur = cat
+	}
+	return &p.cur
+}
+
+type nillable interface {
+	IsNil() bool
+}
+
+// Return an error indicating which required field was not set.
+func (p *textParser) missingRequiredFieldError(sv *reflect.StructValue) *ParseError {
+	st := sv.Type().(*reflect.StructType)
+	sprops := GetProperties(st)
+	for i := 0; i < st.NumField(); i++ {
+		// All protocol buffer fields are nillable, but let's be careful.
+		nfv, ok := sv.Field(i).(nillable)
+		if !ok || !nfv.IsNil() {
+			continue
+		}
+
+		props := sprops.Prop[i]
+		if props.Required {
+			return p.error("message %v missing required field %q", st, props.OrigName)
+		}
+	}
+	return p.error("message %v missing required field", st) // should not happen
+}
+
+// Returns the index in the struct for the named field, as well as the parsed tag properties.
+func structFieldByName(st *reflect.StructType, name string) (int, *Properties, bool) {
+	sprops := GetProperties(st)
+	for i := 0; i < st.NumField(); i++ {
+		props := sprops.Prop[i]
+		if props.OrigName == name {
+			return i, props, true
+		}
+	}
+	return -1, nil, false
+}
+
+func (p *textParser) readStruct(sv *reflect.StructValue, terminator string) *ParseError {
+	st := sv.Type().(*reflect.StructType)
+	reqCount := GetProperties(st).reqCount
+	// A struct is a sequence of "name: value", terminated by one of
+	// '>' or '}', or the end of the input.
+	for {
+		tok := p.next()
+		if tok.err != nil {
+			return tok.err
+		}
+		if tok.value == terminator {
+			break
+		}
+
+		fi, props, ok := structFieldByName(st, tok.value)
+		if !ok {
+			return p.error("unknown field name %q in %v", tok.value, st)
+		}
+
+		// Check that it's not already set if it's not a repeated field.
+		if !props.Repeated {
+			if nfv, ok := sv.Field(fi).(nillable); ok && !nfv.IsNil() {
+				return p.error("non-repeated field %q was repeated", tok.value)
+			}
+		}
+
+		tok = p.next()
+		if tok.err != nil {
+			return tok.err
+		}
+		if tok.value != ":" {
+			// Colon is optional when the field is a group or message.
+			needColon := true
+			switch props.Wire {
+			case "group":
+				needColon = false
+			case "bytes":
+				// A "bytes" field is either a message, a string, or a repeated field;
+				// those three become *T, *string and []T respectively, so we can check for
+				// this field being a pointer to a non-string.
+				typ := st.Field(fi).Type
+				pt, ok := typ.(*reflect.PtrType)
+				if !ok {
+					break
+				}
+				_, ok = pt.Elem().(*reflect.StringType)
+				if ok {
+					break
+				}
+				needColon = false
+			}
+			if needColon {
+				return p.error("expected ':', found %q", tok.value)
+			}
+			p.back()
+		}
+
+		// Parse into the field.
+		if err := p.readAny(sv.Field(fi), props); err != nil {
+			return err
+		}
+
+		if props.Required {
+			reqCount--
+		}
+	}
+
+	if reqCount > 0 {
+		return p.missingRequiredFieldError(sv)
+	}
+	return nil
+}
+
+const (
+	minInt32  = -1 << 31
+	maxInt32  = 1<<31 - 1
+	maxUint32 = 1<<32 - 1
+)
+
+func (p *textParser) readAny(v reflect.Value, props *Properties) *ParseError {
+	tok := p.next()
+	if tok.err != nil {
+		return tok.err
+	}
+	if tok.value == "" {
+		return p.error("unexpected EOF")
+	}
+
+	switch fv := v.(type) {
+	case *reflect.SliceValue:
+		at := v.Type().(*reflect.SliceType)
+		if _, ok := at.Elem().(*reflect.Uint8Type); ok {
+			// Special case for []byte
+			if tok.value[0] != '"' {
+				// Deliberately written out here, as the error after
+				// this switch statement would write "invalid []byte: ...",
+				// which is not as user-friendly.
+				return p.error("invalid string: %v", tok.value)
+			}
+			bytes := []byte(tok.unquoted)
+			fv.Set(reflect.NewValue(bytes).(*reflect.SliceValue))
+			return nil
+		}
+		// Repeated field. May already exist.
+		cnt := fv.Len()
+		nav := reflect.MakeSlice(at, cnt, cnt+1)
+		reflect.ArrayCopy(nav, fv)
+		fv.Set(nav)
+		fv.SetLen(cnt + 1)
+
+		// Read one.
+		p.back()
+		return p.readAny(fv.Elem(cnt), nil) // TODO: pass properties?
+	case *reflect.BoolValue:
+		// Either "true", "false", 1 or 0.
+		switch tok.value {
+		case "true", "1":
+			fv.Set(true)
+			return nil
+		case "false", "0":
+			fv.Set(false)
+			return nil
+		}
+	case *reflect.Float32Value:
+		if f, err := strconv.Atof32(tok.value); err == nil {
+			fv.Set(f)
+			return nil
+		}
+	case *reflect.Float64Value:
+		if f, err := strconv.Atof64(tok.value); err == nil {
+			fv.Set(f)
+			return nil
+		}
+	case *reflect.Int32Value:
+		if x, err := strconv.Atoi64(tok.value); err == nil && minInt32 <= x && x <= maxInt32 {
+			fv.Set(int32(x))
+			return nil
+		}
+		if len(props.Enum) == 0 {
+			break
+		}
+		m, ok := enumValueMaps[props.Enum]
+		if !ok {
+			break
+		}
+		x, ok := m[tok.value]
+		if !ok {
+			break
+		}
+		fv.Set(x)
+		return nil
+	case *reflect.Int64Value:
+		if x, err := strconv.Atoi64(tok.value); err == nil {
+			fv.Set(x)
+			return nil
+		}
+	case *reflect.PtrValue:
+		// A basic field (indirected through pointer), or a repeated message/group
+		p.back()
+		fv.PointTo(reflect.MakeZero(fv.Type().(*reflect.PtrType).Elem()))
+		return p.readAny(fv.Elem(), props)
+	case *reflect.StringValue:
+		if tok.value[0] == '"' {
+			fv.Set(tok.unquoted)
+			return nil
+		}
+	case *reflect.StructValue:
+		var terminator string
+		switch tok.value {
+		case "{":
+			terminator = "}"
+		case "<":
+			terminator = ">"
+		default:
+			return p.error("expected '{' or '<', found %q", tok.value)
+		}
+		return p.readStruct(fv, terminator)
+	case *reflect.Uint32Value:
+		if x, err := strconv.Atoui64(tok.value); err == nil && x <= maxUint32 {
+			fv.Set(uint32(x))
+			return nil
+		}
+	case *reflect.Uint64Value:
+		if x, err := strconv.Atoui64(tok.value); err == nil {
+			fv.Set(x)
+			return nil
+		}
+	}
+	return p.error("invalid %v: %v", v.Type(), tok.value)
+}
+
+var notPtrStruct os.Error = &ParseError{"destination is not a pointer to a struct", 0, 0}
+
+// UnmarshalText reads a protobuffer in Text format.
+func UnmarshalText(s string, pb interface{}) os.Error {
+	pv, ok := reflect.NewValue(pb).(*reflect.PtrValue)
+	if !ok {
+		return notPtrStruct
+	}
+	sv, ok := pv.Elem().(*reflect.StructValue)
+	if !ok {
+		return notPtrStruct
+	}
+	if pe := newTextParser(s).readStruct(sv, ""); pe != nil {
+		return pe
+	}
+	return nil
+}
diff --git a/proto/text_parser_test.go b/proto/text_parser_test.go
new file mode 100644
index 0000000..7017dc0
--- /dev/null
+++ b/proto/text_parser_test.go
@@ -0,0 +1,244 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto_test
+
+import (
+	. "goprotobuf.googlecode.com/hg/proto"
+	. "./testdata/_obj/test_proto"
+	"reflect"
+	"testing"
+)
+
+type UnmarshalTextTest struct {
+	in    string
+	error string // if "", no error expected
+	out   *MyMessage
+}
+
+var unMarshalTextTests = []UnmarshalTextTest{
+	// Basic
+	UnmarshalTextTest{
+		in: " count:42\n  name:\"Dave\" ",
+		out: &MyMessage{
+			Count: Int32(42),
+			Name: String("Dave"),
+		},
+	},
+
+	// Empty quoted string
+	UnmarshalTextTest{
+		in: `count:42 name:""`,
+		out: &MyMessage{
+			Count: Int32(42),
+			Name: String(""),
+		},
+	},
+
+	// Quoted string concatenation
+	UnmarshalTextTest{
+		in: `count:42 name: "My name is "` + "\n" + `"elsewhere"`,
+		out: &MyMessage{
+			Count: Int32(42),
+			Name: String("My name is elsewhere"),
+		},
+	},
+
+	// Bad quoted string
+	UnmarshalTextTest{
+		in: `inner: < host: "\0" >` + "\n",
+		error: `line 1.15: invalid quoted string "\0"`,
+	},
+
+	// Number too large for int64
+	UnmarshalTextTest{
+		in: "count: 123456789012345678901",
+		error: "line 1.7: invalid int32: 123456789012345678901",
+	},
+
+	// Number too large for int32
+	UnmarshalTextTest{
+		in: "count: 1234567890123",
+		error: "line 1.7: invalid int32: 1234567890123",
+	},
+
+	// Number too large for float32
+	UnmarshalTextTest{
+		in: "others:< weight: 12345678901234567890123456789012345678901234567890 >",
+		error: "line 1.17: invalid float32: 12345678901234567890123456789012345678901234567890",
+	},
+
+	// Number posing as a quoted string
+	UnmarshalTextTest{
+		in: `inner: < host: 12 >` + "\n",
+		error: `line 1.15: invalid string: 12`,
+	},
+
+	// Quoted string posing as int32
+	UnmarshalTextTest{
+		in: `count: "12"`,
+		error: `line 1.7: invalid int32: "12"`,
+	},
+
+	// Quoted string posing a float32
+	UnmarshalTextTest{
+		in: `others:< weight: "17.4" >`,
+		error: `line 1.17: invalid float32: "17.4"`,
+	},
+
+	// Enum
+	UnmarshalTextTest{
+		in: `count:42 bikeshed: BLUE`,
+		out: &MyMessage{
+			Count: Int32(42),
+			Bikeshed: NewMyMessage_Color(MyMessage_BLUE),
+		},
+	},
+
+	// Repeated field
+	UnmarshalTextTest{
+		in: `count:42 pet: "horsey" pet:"bunny"`,
+		out: &MyMessage{
+			Count: Int32(42),
+			Pet: []string{"horsey", "bunny"},
+		},
+	},
+
+	// Missing colon for inner message
+	UnmarshalTextTest{
+		in: `count:42 inner < host: "cauchy.syd" >`,
+		out: &MyMessage{
+			Count: Int32(42),
+			Inner: &InnerMessage{
+				Host: String("cauchy.syd"),
+			},
+		},
+	},
+
+	// Missing colon for string field
+	UnmarshalTextTest{
+		in: `name "Dave"`,
+		error: `line 1.5: expected ':', found "\"Dave\""`,
+	},
+
+	// Missing colon for int32 field
+	UnmarshalTextTest{
+		in: `count 42`,
+		error: `line 1.6: expected ':', found "42"`,
+	},
+
+	// Missing required field
+	UnmarshalTextTest{
+		in: ``,
+		error: `line 1.0: message test_proto.MyMessage missing required field "count"`,
+	},
+
+	// Repeated non-repeated field
+	UnmarshalTextTest{
+		in: `name: "Rob" name: "Russ"`,
+		error: `line 1.12: non-repeated field "name" was repeated`,
+	},
+
+	// Big all-in-one
+	UnmarshalTextTest{
+		in: "count:42  # Meaning\n" +
+			`name:"Dave" ` +
+			`quote:"\"I didn't want to go.\"" ` +
+			`pet:"bunny" ` +
+			`pet:"kitty" ` +
+			`pet:"horsey" ` +
+			`inner:<` +
+			`  host:"footrest.syd" ` +
+			`  port:7001 ` +
+			`  connected:true ` +
+			`> ` +
+			`others:<` +
+			`  key:3735928559 ` +
+			`  value:"\x01A\a\f" ` +
+			`> ` +
+			`others:<` +
+			"  weight:58.9  # Atomic weight of Co\n" +
+			`  inner:<` +
+			`    host:"lesha.mtv" ` +
+			`    port:8002 ` +
+			`  >` +
+			`>`,
+		out: &MyMessage{
+			Count: Int32(42),
+			Name: String("Dave"),
+			Quote: String(`"I didn't want to go."`),
+			Pet: []string{"bunny", "kitty", "horsey"},
+			Inner: &InnerMessage{
+				Host: String("footrest.syd"),
+				Port: Int32(7001),
+				Connected: Bool(true),
+			},
+			Others: []*OtherMessage{
+				&OtherMessage{
+					Key: Int64(3735928559),
+					Value: []byte{0x1, 'A', '\a', '\f'},
+				},
+				&OtherMessage{
+					Weight: Float32(58.9),
+					Inner: &InnerMessage{
+						Host: String("lesha.mtv"),
+						Port: Int32(8002),
+					},
+				},
+			},
+		},
+	},
+}
+
+func TestUnmarshalText(t *testing.T) {
+	for i, test := range unMarshalTextTests {
+		pb := new(MyMessage)
+		err := UnmarshalText(test.in, pb)
+		if test.error == "" {
+			// We don't expect failure.
+			if err != nil {
+				t.Errorf("Test %d: Unexpected error: %v", i, err)
+			} else if !reflect.DeepEqual(pb, test.out) {
+				t.Errorf("Test %d: Incorrect populated \n"+
+					"Have: %v\nWant: %v",
+					i, CompactTextString(pb), CompactTextString(test.out))
+			}
+		} else {
+			// We do expect failure.
+			if err == nil {
+				t.Errorf("Test %d: Didn't get expected error: %v", i, test.error)
+			} else if err.String() != test.error {
+				t.Errorf("Test %d: Incorrect error.\nHave: %v\nWant: %v",
+					i, err.String(), test.error)
+			}
+		}
+	}
+}
diff --git a/proto/text_test.go b/proto/text_test.go
new file mode 100644
index 0000000..40a4df8
--- /dev/null
+++ b/proto/text_test.go
@@ -0,0 +1,139 @@
+// Go support for Protocol Buffers - Google's data interchange format
+//
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/goprotobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package proto_test
+
+import (
+	"bytes"
+	. "goprotobuf.googlecode.com/hg/proto"
+	. "./testdata/_obj/test_proto"
+	"testing"
+)
+
+func newTestMessage() *MyMessage {
+	return &MyMessage{
+		Count: Int32(42),
+		Name: String("Dave"),
+		Quote: String(`"I didn't want to go."`),
+		Pet: []string{"bunny", "kitty", "horsey"},
+		Inner: &InnerMessage{
+			Host: String("footrest.syd"),
+			Port: Int32(7001),
+			Connected: Bool(true),
+		},
+		Others: []*OtherMessage{
+			&OtherMessage{
+				Key: Int64(0xdeadbeef),
+				Value: []byte{1, 65, 7, 12},
+			},
+			&OtherMessage{
+				Weight: Float32(6.022),
+				Inner: &InnerMessage{
+					Host: String("lesha.mtv"),
+					Port: Int32(8002),
+				},
+			},
+		},
+		Bikeshed: NewMyMessage_Color(MyMessage_BLUE),
+	}
+}
+
+const text = `count: 42
+name: "Dave"
+quote: "\"I didn't want to go.\""
+pet: "bunny"
+pet: "kitty"
+pet: "horsey"
+inner: <
+  host: "footrest.syd"
+  port: 7001
+  connected: true
+>
+others: <
+  key: 3735928559
+  value: "\x01A\a\f"
+>
+others: <
+  weight: 6.022
+  inner: <
+    host: "lesha.mtv"
+    port: 8002
+  >
+>
+bikeshed: BLUE
+`
+
+func TestMarshalTextFull(t *testing.T) {
+	buf := new(bytes.Buffer)
+	MarshalText(buf, newTestMessage())
+	s := buf.String()
+	if s != text {
+		t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, text)
+	}
+}
+
+func compact(src string) string {
+	// ,s/[ \n]+/ /g; s/ $//;
+	dst := make([]byte, len(src))
+	space := false
+	j := 0
+	for i := 0; i < len(src); i++ {
+		c := src[i]
+		if c == ' ' || c == '\n' {
+			space = true
+			continue
+		}
+		if j > 0 && (dst[j-1] == ':' || dst[j-1] == '<') {
+			space = false
+		}
+		if space {
+			dst[j] = ' '
+			j++
+			space = false
+		}
+		dst[j] = c
+		j++
+	}
+	if space {
+		dst[j] = ' '
+		j++
+	}
+	return string(dst[0:j])
+}
+
+var compactText = compact(text)
+
+func TestCompactText(t *testing.T) {
+	s := CompactTextString(newTestMessage())
+	if s != compactText {
+		t.Errorf("Got:\n===\n%v===\nExpected:\n===\n%v===\n", s, compactText)
+	}
+}