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/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()
+}