encoding/textpb: initial implementation of textproto marshaling

This initial implementation covers marshaling Message without use
of extensions, Any expansion, weak yet.

Change-Id: Ic787939c1d2a4e70e40c3a1654c6e7073052b7d3
Reviewed-on: https://go-review.googlesource.com/c/151677
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/encoding/textpb/encode.go b/encoding/textpb/encode.go
new file mode 100644
index 0000000..1b11e66
--- /dev/null
+++ b/encoding/textpb/encode.go
@@ -0,0 +1,250 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textpb
+
+import (
+	"sort"
+
+	"github.com/golang/protobuf/v2/internal/encoding/text"
+	"github.com/golang/protobuf/v2/internal/errors"
+	"github.com/golang/protobuf/v2/internal/pragma"
+	"github.com/golang/protobuf/v2/proto"
+	pref "github.com/golang/protobuf/v2/reflect/protoreflect"
+)
+
+// Marshal marshals a proto.Message in text format using default options.
+// TODO: may want to describe when Marshal returns error.
+func Marshal(m proto.Message) ([]byte, error) {
+	return MarshalOptions{}.Marshal(m)
+}
+
+// MarshalOptions is a configurable text format marshaler.
+type MarshalOptions struct {
+	pragma.NoUnkeyedLiterals
+
+	// Set Compact to true to have output in a single line with no line breaks.
+	Compact bool
+}
+
+// Marshal returns the given proto.Message in text format using options in MarshalOptions object.
+func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
+	var nerr errors.NonFatal
+	var v text.Value
+
+	if m == nil {
+		// TODO: Make sure this is consistent with jsonpb and binary serialization.
+		v = text.ValueOf([][2]text.Value{})
+	} else {
+		var err error
+		v, err = o.marshalMessage(m.ProtoReflect())
+		if !nerr.Merge(err) {
+			return nil, err
+		}
+	}
+
+	indent := "  "
+	if o.Compact {
+		indent = ""
+	}
+	delims := [2]byte{'{', '}'}
+
+	const outputASCII = false
+	b, err := text.Marshal(v, indent, delims, outputASCII)
+	if !nerr.Merge(err) {
+		return nil, err
+	}
+	return b, nerr.E
+}
+
+// marshalMessage converts a protoreflect.Message to a text.Value.
+func (o MarshalOptions) marshalMessage(m pref.Message) (text.Value, error) {
+	var nerr errors.NonFatal
+	var msgFields [][2]text.Value
+
+	// Handle known fields.
+	msgType := m.Type()
+	fieldDescs := msgType.Fields()
+	knownFields := m.KnownFields()
+	size := fieldDescs.Len()
+	for i := 0; i < size; i++ {
+		fieldDesc := fieldDescs.Get(i)
+		fieldNum := fieldDesc.Number()
+
+		if !knownFields.Has(fieldNum) {
+			if fieldDesc.Cardinality() == pref.Required {
+				// Treat unset required fields as a non-fatal error.
+				nerr.AppendRequiredNotSet(string(fieldDesc.FullName()))
+			}
+			continue
+		}
+
+		txtName := text.ValueOf(fieldDesc.Name())
+		value := knownFields.Get(fieldNum)
+
+		if fieldDesc.Cardinality() == pref.Repeated {
+			// Map or repeated fields.
+			var items []text.Value
+			var err error
+			if fieldDesc.IsMap() {
+				items, err = o.marshalMap(value.Map(), fieldDesc)
+				if !nerr.Merge(err) {
+					return text.Value{}, err
+				}
+			} else {
+				items, err = o.marshalList(value.List(), fieldDesc)
+				if !nerr.Merge(err) {
+					return text.Value{}, err
+				}
+			}
+
+			// Add each item as key: value field.
+			for _, item := range items {
+				msgFields = append(msgFields, [2]text.Value{txtName, item})
+			}
+		} else {
+			// Required or optional fields.
+			txtValue, err := o.marshalSingular(value, fieldDesc)
+			if !nerr.Merge(err) {
+				return text.Value{}, err
+			}
+			msgFields = append(msgFields, [2]text.Value{txtName, txtValue})
+		}
+
+	}
+
+	// TODO: Handle extensions, unknowns and Any.
+
+	return text.ValueOf(msgFields), nerr.E
+}
+
+// marshalSingular converts a non-repeated field value to text.Value.
+// This includes all scalar types, enums, messages, and groups.
+func (o MarshalOptions) marshalSingular(val pref.Value, fd pref.FieldDescriptor) (text.Value, error) {
+	kind := fd.Kind()
+	switch kind {
+	case pref.BoolKind,
+		pref.Int32Kind, pref.Sint32Kind, pref.Uint32Kind,
+		pref.Int64Kind, pref.Sint64Kind, pref.Uint64Kind,
+		pref.Sfixed32Kind, pref.Fixed32Kind,
+		pref.Sfixed64Kind, pref.Fixed64Kind,
+		pref.FloatKind, pref.DoubleKind,
+		pref.StringKind, pref.BytesKind:
+		return text.ValueOf(val.Interface()), nil
+
+	case pref.EnumKind:
+		num := val.Enum()
+		if desc := fd.EnumType().Values().ByNumber(num); desc != nil {
+			return text.ValueOf(desc.Name()), nil
+		}
+		// Use numeric value if there is no enum description.
+		return text.ValueOf(int32(num)), nil
+
+	case pref.MessageKind, pref.GroupKind:
+		return o.marshalMessage(val.Message())
+	}
+
+	return text.Value{}, errors.New("%v has unknown kind: %v", fd.FullName(), kind)
+}
+
+// marshalList converts a protoreflect.List to []text.Value.
+func (o MarshalOptions) marshalList(list pref.List, fd pref.FieldDescriptor) ([]text.Value, error) {
+	var nerr errors.NonFatal
+	size := list.Len()
+	values := make([]text.Value, 0, size)
+
+	for i := 0; i < size; i++ {
+		item := list.Get(i)
+		val, err := o.marshalSingular(item, fd)
+		if !nerr.Merge(err) {
+			// Return already marshaled values.
+			return values, err
+		}
+		values = append(values, val)
+	}
+
+	return values, nerr.E
+}
+
+var (
+	mapKeyName   = text.ValueOf(pref.Name("key"))
+	mapValueName = text.ValueOf(pref.Name("value"))
+)
+
+// marshalMap converts a protoreflect.Map to []text.Value.
+func (o MarshalOptions) marshalMap(mmap pref.Map, fd pref.FieldDescriptor) ([]text.Value, error) {
+	var nerr errors.NonFatal
+	// values is a list of messages.
+	values := make([]text.Value, 0, mmap.Len())
+	msgFields := fd.MessageType().Fields()
+	keyType := msgFields.ByNumber(1)
+	valType := msgFields.ByNumber(2)
+
+	mmap.Range(func(key pref.MapKey, val pref.Value) bool {
+		keyTxtVal, err := o.marshalSingular(key.Value(), keyType)
+		if !nerr.Merge(err) {
+			return false
+		}
+		valTxtVal, err := o.marshalSingular(val, valType)
+		if !nerr.Merge(err) {
+			return false
+		}
+		// Map entry (message) contains 2 fields, first field for key and second field for value.
+		msg := text.ValueOf([][2]text.Value{
+			{mapKeyName, keyTxtVal},
+			{mapValueName, valTxtVal},
+		})
+		values = append(values, msg)
+		return true
+	})
+
+	sortMap(keyType.Kind(), values)
+	return values, nerr.E
+}
+
+// sortMap orders list based on value of key field for deterministic output.
+// TODO: Improve sort comparison of text.Value for map keys.
+func sortMap(keyKind pref.Kind, values []text.Value) {
+	less := func(i, j int) bool {
+		mi := values[i].Message()
+		mj := values[j].Message()
+		return mi[0][1].String() < mj[0][1].String()
+	}
+	switch keyKind {
+	case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
+		less = func(i, j int) bool {
+			mi := values[i].Message()
+			mj := values[j].Message()
+			ni, _ := mi[0][1].Int(false)
+			nj, _ := mj[0][1].Int(false)
+			return ni < nj
+		}
+	case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
+		less = func(i, j int) bool {
+			mi := values[i].Message()
+			mj := values[j].Message()
+			ni, _ := mi[0][1].Int(true)
+			nj, _ := mj[0][1].Int(true)
+			return ni < nj
+		}
+
+	case pref.Uint32Kind, pref.Fixed32Kind:
+		less = func(i, j int) bool {
+			mi := values[i].Message()
+			mj := values[j].Message()
+			ni, _ := mi[0][1].Uint(false)
+			nj, _ := mj[0][1].Uint(false)
+			return ni < nj
+		}
+	case pref.Uint64Kind, pref.Fixed64Kind:
+		less = func(i, j int) bool {
+			mi := values[i].Message()
+			mj := values[j].Message()
+			ni, _ := mi[0][1].Uint(true)
+			nj, _ := mj[0][1].Uint(true)
+			return ni < nj
+		}
+	}
+	sort.Slice(values, less)
+}
diff --git a/encoding/textpb/encode_test.go b/encoding/textpb/encode_test.go
new file mode 100644
index 0000000..28beaf4
--- /dev/null
+++ b/encoding/textpb/encode_test.go
@@ -0,0 +1,933 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package textpb_test
+
+import (
+	"math"
+	"strings"
+	"testing"
+
+	"github.com/golang/protobuf/v2/encoding/textpb"
+	"github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb2"
+	"github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb3"
+	"github.com/golang/protobuf/v2/internal/detrand"
+	"github.com/golang/protobuf/v2/internal/impl"
+	"github.com/golang/protobuf/v2/internal/scalar"
+	"github.com/golang/protobuf/v2/proto"
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+
+	anypb "github.com/golang/protobuf/ptypes/any"
+	durpb "github.com/golang/protobuf/ptypes/duration"
+	emptypb "github.com/golang/protobuf/ptypes/empty"
+	stpb "github.com/golang/protobuf/ptypes/struct"
+	tspb "github.com/golang/protobuf/ptypes/timestamp"
+	wpb "github.com/golang/protobuf/ptypes/wrappers"
+)
+
+func init() {
+	// Disable detrand to enable direct comparisons on outputs.
+	detrand.Disable()
+}
+
+func M(m interface{}) proto.Message {
+	return impl.MessageOf(m).Interface()
+}
+
+// splitLines is a cmpopts.Option for comparing strings with line breaks.
+var splitLines = cmpopts.AcyclicTransformer("SplitLines", func(s string) []string {
+	return strings.Split(s, "\n")
+})
+
+func TestMarshal(t *testing.T) {
+	tests := []struct {
+		desc    string
+		input   proto.Message
+		want    string
+		wantErr bool
+	}{{
+		desc: "nil message",
+		want: "\n",
+	}, {
+		desc:  "proto2 optional scalar fields not set",
+		input: M(&pb2.Scalars{}),
+		want:  "\n",
+	}, {
+		desc:  "proto3 scalar fields not set",
+		input: M(&pb3.Scalars{}),
+		want:  "\n",
+	}, {
+		desc: "proto2 optional scalar fields set to zero values",
+		input: M(&pb2.Scalars{
+			OptBool:     scalar.Bool(false),
+			OptInt32:    scalar.Int32(0),
+			OptInt64:    scalar.Int64(0),
+			OptUint32:   scalar.Uint32(0),
+			OptUint64:   scalar.Uint64(0),
+			OptSint32:   scalar.Int32(0),
+			OptSint64:   scalar.Int64(0),
+			OptFixed32:  scalar.Uint32(0),
+			OptFixed64:  scalar.Uint64(0),
+			OptSfixed32: scalar.Int32(0),
+			OptSfixed64: scalar.Int64(0),
+			OptFloat:    scalar.Float32(0),
+			OptDouble:   scalar.Float64(0),
+			OptBytes:    []byte{},
+			OptString:   scalar.String(""),
+		}),
+		want: `opt_bool: false
+opt_int32: 0
+opt_int64: 0
+opt_uint32: 0
+opt_uint64: 0
+opt_sint32: 0
+opt_sint64: 0
+opt_fixed32: 0
+opt_fixed64: 0
+opt_sfixed32: 0
+opt_sfixed64: 0
+opt_float: 0
+opt_double: 0
+opt_bytes: ""
+opt_string: ""
+`,
+	}, {
+		desc: "proto3 scalar fields set to zero values",
+		input: M(&pb3.Scalars{
+			SBool:     false,
+			SInt32:    0,
+			SInt64:    0,
+			SUint32:   0,
+			SUint64:   0,
+			SSint32:   0,
+			SSint64:   0,
+			SFixed32:  0,
+			SFixed64:  0,
+			SSfixed32: 0,
+			SSfixed64: 0,
+			SFloat:    0,
+			SDouble:   0,
+			SBytes:    []byte{},
+			SString:   "",
+		}),
+		want: "\n",
+	}, {
+		desc: "proto2 optional scalar fields set to some values",
+		input: M(&pb2.Scalars{
+			OptBool:     scalar.Bool(true),
+			OptInt32:    scalar.Int32(0xff),
+			OptInt64:    scalar.Int64(0xdeadbeef),
+			OptUint32:   scalar.Uint32(47),
+			OptUint64:   scalar.Uint64(0xdeadbeef),
+			OptSint32:   scalar.Int32(-1001),
+			OptSint64:   scalar.Int64(-0xffff),
+			OptFixed64:  scalar.Uint64(64),
+			OptSfixed32: scalar.Int32(-32),
+			// TODO: Update encoder to output same decimals.
+			OptFloat:  scalar.Float32(1.02),
+			OptDouble: scalar.Float64(1.23e100),
+			// TODO: Update encoder to not output UTF8 for bytes.
+			OptBytes:  []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
+			OptString: scalar.String("谷歌"),
+		}),
+		want: `opt_bool: true
+opt_int32: 255
+opt_int64: 3735928559
+opt_uint32: 47
+opt_uint64: 3735928559
+opt_sint32: -1001
+opt_sint64: -65535
+opt_fixed64: 64
+opt_sfixed32: -32
+opt_float: 1.0199999809265137
+opt_double: 1.23e+100
+opt_bytes: "谷歌"
+opt_string: "谷歌"
+`,
+	}, {
+		desc:  "proto3 enum empty message",
+		input: M(&pb3.Enums{}),
+		want:  "\n",
+	}, {
+		desc: "proto3 enum",
+		input: M(&pb3.Enums{
+			SEnum:         pb3.Enum_ONE,
+			RptEnum:       []pb3.Enum{pb3.Enum_ONE, 10, 0, 21, -1},
+			SNestedEnum:   pb3.Enums_DIEZ,
+			RptNestedEnum: []pb3.Enums_NestedEnum{21, pb3.Enums_CERO, -7, 10},
+		}),
+		want: `s_enum: ONE
+rpt_enum: ONE
+rpt_enum: TEN
+rpt_enum: ZERO
+rpt_enum: 21
+rpt_enum: -1
+s_nested_enum: DIEZ
+rpt_nested_enum: 21
+rpt_nested_enum: CERO
+rpt_nested_enum: -7
+rpt_nested_enum: DIEZ
+`,
+	}, {
+		desc: "float32 nan",
+		input: M(&pb3.Scalars{
+			SFloat: float32(math.NaN()),
+		}),
+		want: "s_float: nan\n",
+	}, {
+		desc: "float32 positive infinity",
+		input: M(&pb3.Scalars{
+			SFloat: float32(math.Inf(1)),
+		}),
+		want: "s_float: inf\n",
+	}, {
+		desc: "float32 negative infinity",
+		input: M(&pb3.Scalars{
+			SFloat: float32(math.Inf(-1)),
+		}),
+		want: "s_float: -inf\n",
+	}, {
+		desc: "float64 nan",
+		input: M(&pb3.Scalars{
+			SDouble: math.NaN(),
+		}),
+		want: "s_double: nan\n",
+	}, {
+		desc: "float64 positive infinity",
+		input: M(&pb3.Scalars{
+			SDouble: math.Inf(1),
+		}),
+		want: "s_double: inf\n",
+	}, {
+		desc: "float64 negative infinity",
+		input: M(&pb3.Scalars{
+			SDouble: math.Inf(-1),
+		}),
+		want: "s_double: -inf\n",
+	}, {
+		desc: "proto2 bytes set to empty string",
+		input: M(&pb2.Scalars{
+			OptBytes: []byte(""),
+		}),
+		want: "opt_bytes: \"\"\n",
+	}, {
+		desc: "proto3 bytes set to empty string",
+		input: M(&pb3.Scalars{
+			SBytes: []byte(""),
+		}),
+		want: "\n",
+	}, {
+		desc:  "proto2 repeated not set",
+		input: M(&pb2.Repeats{}),
+		want:  "\n",
+	}, {
+		desc: "proto2 repeated set to empty slices",
+		input: M(&pb2.Repeats{
+			RptBool:   []bool{},
+			RptInt32:  []int32{},
+			RptInt64:  []int64{},
+			RptUint32: []uint32{},
+			RptUint64: []uint64{},
+			RptFloat:  []float32{},
+			RptDouble: []float64{},
+			RptBytes:  [][]byte{},
+		}),
+		want: "\n",
+	}, {
+		desc: "proto2 repeated set to some values",
+		input: M(&pb2.Repeats{
+			RptBool:   []bool{true, false, true, true},
+			RptInt32:  []int32{1, 6, 0, 0},
+			RptInt64:  []int64{-64, 47},
+			RptUint32: []uint32{0xff, 0xffff},
+			RptUint64: []uint64{0xdeadbeef},
+			// TODO: add float32 examples.
+			RptDouble: []float64{math.NaN(), math.Inf(1), math.Inf(-1), 1.23e-308},
+			RptString: []string{"hello", "世界"},
+			RptBytes: [][]byte{
+				[]byte("hello"),
+				[]byte("\xe4\xb8\x96\xe7\x95\x8c"),
+			},
+		}),
+		want: `rpt_bool: true
+rpt_bool: false
+rpt_bool: true
+rpt_bool: true
+rpt_int32: 1
+rpt_int32: 6
+rpt_int32: 0
+rpt_int32: 0
+rpt_int64: -64
+rpt_int64: 47
+rpt_uint32: 255
+rpt_uint32: 65535
+rpt_uint64: 3735928559
+rpt_double: nan
+rpt_double: inf
+rpt_double: -inf
+rpt_double: 1.23e-308
+rpt_string: "hello"
+rpt_string: "世界"
+rpt_bytes: "hello"
+rpt_bytes: "世界"
+`,
+	}, {
+		desc:  "proto2 enum fields not set",
+		input: M(&pb2.Enums{}),
+		want:  "\n",
+	}, {
+		desc: "proto2 enum fields",
+		input: M(&pb2.Enums{
+			OptEnum:       pb2.Enum_FIRST.Enum(),
+			RptEnum:       []pb2.Enum{pb2.Enum_FIRST, 2, pb2.Enum_TENTH, 42},
+			OptNestedEnum: pb2.Enums_UNO.Enum(),
+			RptNestedEnum: []pb2.Enums_NestedEnum{2, 47, 10},
+		}),
+		want: `opt_enum: FIRST
+rpt_enum: FIRST
+rpt_enum: SECOND
+rpt_enum: TENTH
+rpt_enum: 42
+opt_nested_enum: UNO
+rpt_nested_enum: DOS
+rpt_nested_enum: 47
+rpt_nested_enum: DIEZ
+`,
+	}, {
+		desc: "proto3 enum fields set to zero value",
+		input: M(&pb3.Enums{
+			SEnum:         pb3.Enum_ZERO,
+			RptEnum:       []pb3.Enum{},
+			SNestedEnum:   pb3.Enums_CERO,
+			RptNestedEnum: []pb3.Enums_NestedEnum{},
+		}),
+		want: "\n",
+	}, {
+		desc: "proto3 enum fields",
+		input: M(&pb3.Enums{
+			SEnum:         pb3.Enum_TWO,
+			RptEnum:       []pb3.Enum{1, 0, 0},
+			SNestedEnum:   pb3.Enums_DOS,
+			RptNestedEnum: []pb3.Enums_NestedEnum{101, pb3.Enums_DIEZ, 10},
+		}),
+		want: `s_enum: TWO
+rpt_enum: ONE
+rpt_enum: ZERO
+rpt_enum: ZERO
+s_nested_enum: DOS
+rpt_nested_enum: 101
+rpt_nested_enum: DIEZ
+rpt_nested_enum: DIEZ
+`,
+	}, {
+		desc:  "proto2 nested message not set",
+		input: M(&pb2.Nests{}),
+		want:  "\n",
+	}, {
+		desc: "proto2 nested message set to empty",
+		input: M(&pb2.Nests{
+			OptNested: &pb2.Nested{},
+			Optgroup:  &pb2.Nests_OptGroup{},
+			RptNested: []*pb2.Nested{},
+			Rptgroup:  []*pb2.Nests_RptGroup{},
+		}),
+		want: `opt_nested: {}
+optgroup: {}
+`,
+	}, {
+		desc: "proto2 nested messages",
+		input: M(&pb2.Nests{
+			OptNested: &pb2.Nested{
+				OptString: scalar.String("nested message"),
+				OptNested: &pb2.Nested{
+					OptString: scalar.String("another nested message"),
+				},
+			},
+			RptNested: []*pb2.Nested{
+				{
+					OptString: scalar.String("repeat nested one"),
+				},
+				{
+					OptString: scalar.String("repeat nested two"),
+					OptNested: &pb2.Nested{
+						OptString: scalar.String("inside repeat nested two"),
+					},
+				},
+				{},
+			},
+		}),
+		want: `opt_nested: {
+  opt_string: "nested message"
+  opt_nested: {
+    opt_string: "another nested message"
+  }
+}
+rpt_nested: {
+  opt_string: "repeat nested one"
+}
+rpt_nested: {
+  opt_string: "repeat nested two"
+  opt_nested: {
+    opt_string: "inside repeat nested two"
+  }
+}
+rpt_nested: {}
+`,
+	}, {
+		desc: "proto2 group fields",
+		input: M(&pb2.Nests{
+			Optgroup: &pb2.Nests_OptGroup{
+				OptBool:   scalar.Bool(true),
+				OptString: scalar.String("inside a group"),
+				OptNested: &pb2.Nested{
+					OptString: scalar.String("nested message inside a group"),
+				},
+				Optnestedgroup: &pb2.Nests_OptGroup_OptNestedGroup{
+					OptEnum: pb2.Enum_TENTH.Enum(),
+				},
+			},
+			Rptgroup: []*pb2.Nests_RptGroup{
+				{
+					RptBool: []bool{true, false},
+				},
+				{},
+			},
+		}),
+		want: `optgroup: {
+  opt_bool: true
+  opt_string: "inside a group"
+  opt_nested: {
+    opt_string: "nested message inside a group"
+  }
+  optnestedgroup: {
+    opt_enum: TENTH
+  }
+}
+rptgroup: {
+  rpt_bool: true
+  rpt_bool: false
+}
+rptgroup: {}
+`,
+	}, {
+		desc:  "proto3 nested message not set",
+		input: M(&pb3.Nests{}),
+		want:  "\n",
+	}, {
+		desc: "proto3 nested message",
+		input: M(&pb3.Nests{
+			SNested: &pb3.Nested{
+				SString: "nested message",
+				SNested: &pb3.Nested{
+					SString: "another nested message",
+				},
+			},
+			RptNested: []*pb3.Nested{
+				{
+					SString: "repeated nested one",
+					SNested: &pb3.Nested{
+						SString: "inside repeated nested one",
+					},
+				},
+				{
+					SString: "repeated nested two",
+				},
+				{},
+			},
+		}),
+		want: `s_nested: {
+  s_string: "nested message"
+  s_nested: {
+    s_string: "another nested message"
+  }
+}
+rpt_nested: {
+  s_string: "repeated nested one"
+  s_nested: {
+    s_string: "inside repeated nested one"
+  }
+}
+rpt_nested: {
+  s_string: "repeated nested two"
+}
+rpt_nested: {}
+`,
+	}, {
+		desc:    "proto2 required fields not set",
+		input:   M(&pb2.Requireds{}),
+		want:    "\n",
+		wantErr: true,
+	}, {
+		desc: "proto2 required fields partially set",
+		input: M(&pb2.Requireds{
+			ReqBool:     scalar.Bool(false),
+			ReqFixed32:  scalar.Uint32(47),
+			ReqSfixed64: scalar.Int64(0xbeefcafe),
+			ReqDouble:   scalar.Float64(math.NaN()),
+			ReqString:   scalar.String("hello"),
+			ReqEnum:     pb2.Enum_FIRST.Enum(),
+		}),
+		want: `req_bool: false
+req_fixed32: 47
+req_sfixed64: 3203386110
+req_double: nan
+req_string: "hello"
+req_enum: FIRST
+`,
+		wantErr: true,
+	}, {
+		desc: "proto2 required fields all set",
+		input: M(&pb2.Requireds{
+			ReqBool:     scalar.Bool(false),
+			ReqFixed32:  scalar.Uint32(0),
+			ReqFixed64:  scalar.Uint64(0),
+			ReqSfixed32: scalar.Int32(0),
+			ReqSfixed64: scalar.Int64(0),
+			ReqFloat:    scalar.Float32(0),
+			ReqDouble:   scalar.Float64(0),
+			ReqString:   scalar.String(""),
+			ReqEnum:     pb2.Enum_UNKNOWN.Enum(),
+			ReqBytes:    []byte{},
+			ReqNested:   &pb2.Nested{},
+		}),
+		want: `req_bool: false
+req_fixed32: 0
+req_fixed64: 0
+req_sfixed32: 0
+req_sfixed64: 0
+req_float: 0
+req_double: 0
+req_string: ""
+req_bytes: ""
+req_enum: UNKNOWN
+req_nested: {}
+`,
+	}, {
+		desc:  "oneof fields",
+		input: M(&pb2.Oneofs{}),
+		want:  "\n",
+	}, {
+		desc: "oneof field set to empty string",
+		input: M(&pb2.Oneofs{
+			Union: &pb2.Oneofs_Str{},
+		}),
+		want: "str: \"\"\n",
+	}, {
+		desc: "oneof field set to string",
+		input: M(&pb2.Oneofs{
+			Union: &pb2.Oneofs_Str{
+				Str: "hello",
+			},
+		}),
+		want: "str: \"hello\"\n",
+	}, {
+		desc: "oneof field set to empty message",
+		input: M(&pb2.Oneofs{
+			Union: &pb2.Oneofs_Msg{
+				Msg: &pb2.Nested{},
+			},
+		}),
+		want: "msg: {}\n",
+	}, {
+		desc: "oneof field set to message",
+		input: M(&pb2.Oneofs{
+			Union: &pb2.Oneofs_Msg{
+				Msg: &pb2.Nested{
+					OptString: scalar.String("nested message"),
+				},
+			},
+		}),
+		want: `msg: {
+  opt_string: "nested message"
+}
+`,
+	}, {
+		desc:  "map fields empty",
+		input: M(&pb2.Maps{}),
+		want:  "\n",
+	}, {
+		desc: "map fields set to empty maps",
+		input: M(&pb2.Maps{
+			Int32ToStr:     map[int32]string{},
+			Sfixed64ToBool: map[int64]bool{},
+			BoolToUint32:   map[bool]uint32{},
+			Uint64ToEnum:   map[uint64]pb2.Enum{},
+			StrToNested:    map[string]*pb2.Nested{},
+			StrToOneofs:    map[string]*pb2.Oneofs{},
+		}),
+		want: "\n",
+	}, {
+		desc: "map fields 1",
+		input: M(&pb2.Maps{
+			Int32ToStr: map[int32]string{
+				-101: "-101",
+				0xff: "0xff",
+				0:    "zero",
+			},
+			Sfixed64ToBool: map[int64]bool{
+				0xcafe: true,
+				0:      false,
+			},
+			BoolToUint32: map[bool]uint32{
+				true:  42,
+				false: 101,
+			},
+		}),
+		want: `int32_to_str: {
+  key: -101
+  value: "-101"
+}
+int32_to_str: {
+  key: 0
+  value: "zero"
+}
+int32_to_str: {
+  key: 255
+  value: "0xff"
+}
+sfixed64_to_bool: {
+  key: 0
+  value: false
+}
+sfixed64_to_bool: {
+  key: 51966
+  value: true
+}
+bool_to_uint32: {
+  key: false
+  value: 101
+}
+bool_to_uint32: {
+  key: true
+  value: 42
+}
+`,
+	}, {
+		desc: "map fields 2",
+		input: M(&pb2.Maps{
+			Uint64ToEnum: map[uint64]pb2.Enum{
+				1:  pb2.Enum_FIRST,
+				2:  pb2.Enum_SECOND,
+				10: pb2.Enum_TENTH,
+			},
+		}),
+		want: `uint64_to_enum: {
+  key: 1
+  value: FIRST
+}
+uint64_to_enum: {
+  key: 2
+  value: SECOND
+}
+uint64_to_enum: {
+  key: 10
+  value: TENTH
+}
+`,
+	}, {
+		desc: "map fields 3",
+		input: M(&pb2.Maps{
+			StrToNested: map[string]*pb2.Nested{
+				"nested_one": &pb2.Nested{
+					OptString: scalar.String("nested in a map"),
+				},
+			},
+		}),
+		want: `str_to_nested: {
+  key: "nested_one"
+  value: {
+    opt_string: "nested in a map"
+  }
+}
+`,
+	}, {
+		desc: "map fields 4",
+		input: M(&pb2.Maps{
+			StrToOneofs: map[string]*pb2.Oneofs{
+				"string": &pb2.Oneofs{
+					Union: &pb2.Oneofs_Str{
+						Str: "hello",
+					},
+				},
+				"nested": &pb2.Oneofs{
+					Union: &pb2.Oneofs_Msg{
+						Msg: &pb2.Nested{
+							OptString: scalar.String("nested oneof in map field value"),
+						},
+					},
+				},
+			},
+		}),
+		want: `str_to_oneofs: {
+  key: "nested"
+  value: {
+    msg: {
+      opt_string: "nested oneof in map field value"
+    }
+  }
+}
+str_to_oneofs: {
+  key: "string"
+  value: {
+    str: "hello"
+  }
+}
+`,
+	}, {
+		desc:  "well-known type fields not set",
+		input: M(&pb2.KnownTypes{}),
+		want:  "\n",
+	}, {
+		desc: "well-known type fields set to empty messages",
+		input: M(&pb2.KnownTypes{
+			OptBool:      &wpb.BoolValue{},
+			OptInt32:     &wpb.Int32Value{},
+			OptInt64:     &wpb.Int64Value{},
+			OptUint32:    &wpb.UInt32Value{},
+			OptUint64:    &wpb.UInt64Value{},
+			OptFloat:     &wpb.FloatValue{},
+			OptDouble:    &wpb.DoubleValue{},
+			OptString:    &wpb.StringValue{},
+			OptBytes:     &wpb.BytesValue{},
+			OptDuration:  &durpb.Duration{},
+			OptTimestamp: &tspb.Timestamp{},
+			OptStruct:    &stpb.Struct{},
+			OptList:      &stpb.ListValue{},
+			OptValue:     &stpb.Value{},
+			OptEmpty:     &emptypb.Empty{},
+			OptAny:       &anypb.Any{},
+		}),
+		want: `opt_bool: {}
+opt_int32: {}
+opt_int64: {}
+opt_uint32: {}
+opt_uint64: {}
+opt_float: {}
+opt_double: {}
+opt_string: {}
+opt_bytes: {}
+opt_duration: {}
+opt_timestamp: {}
+opt_struct: {}
+opt_list: {}
+opt_value: {}
+opt_empty: {}
+opt_any: {}
+`,
+	}, {
+		desc: "well-known type scalar fields",
+		input: M(&pb2.KnownTypes{
+			OptBool: &wpb.BoolValue{
+				Value: true,
+			},
+			OptInt32: &wpb.Int32Value{
+				Value: -42,
+			},
+			OptInt64: &wpb.Int64Value{
+				Value: -42,
+			},
+			OptUint32: &wpb.UInt32Value{
+				Value: 0xff,
+			},
+			OptUint64: &wpb.UInt64Value{
+				Value: 0xffff,
+			},
+			OptFloat: &wpb.FloatValue{
+				Value: 1.234,
+			},
+			OptDouble: &wpb.DoubleValue{
+				Value: 1.23e308,
+			},
+			OptString: &wpb.StringValue{
+				Value: "谷歌",
+			},
+			OptBytes: &wpb.BytesValue{
+				Value: []byte("\xe8\xb0\xb7\xe6\xad\x8c"),
+			},
+		}),
+		want: `opt_bool: {
+  value: true
+}
+opt_int32: {
+  value: -42
+}
+opt_int64: {
+  value: -42
+}
+opt_uint32: {
+  value: 255
+}
+opt_uint64: {
+  value: 65535
+}
+opt_float: {
+  value: 1.2339999675750732
+}
+opt_double: {
+  value: 1.23e+308
+}
+opt_string: {
+  value: "谷歌"
+}
+opt_bytes: {
+  value: "谷歌"
+}
+`,
+	}, {
+		desc: "well-known type time-related fields",
+		input: M(&pb2.KnownTypes{
+			OptDuration: &durpb.Duration{
+				Seconds: -3600,
+				Nanos:   -123,
+			},
+			OptTimestamp: &tspb.Timestamp{
+				Seconds: 1257894000,
+				Nanos:   123,
+			},
+		}),
+		want: `opt_duration: {
+  seconds: -3600
+  nanos: -123
+}
+opt_timestamp: {
+  seconds: 1257894000
+  nanos: 123
+}
+`,
+	}, {
+		desc: "well-known type struct field and different Value types",
+		input: M(&pb2.KnownTypes{
+			OptStruct: &stpb.Struct{
+				Fields: map[string]*stpb.Value{
+					"bool": &stpb.Value{
+						Kind: &stpb.Value_BoolValue{
+							BoolValue: true,
+						},
+					},
+					"double": &stpb.Value{
+						Kind: &stpb.Value_NumberValue{
+							NumberValue: 3.1415,
+						},
+					},
+					"null": &stpb.Value{
+						Kind: &stpb.Value_NullValue{
+							NullValue: stpb.NullValue_NULL_VALUE,
+						},
+					},
+					"string": &stpb.Value{
+						Kind: &stpb.Value_StringValue{
+							StringValue: "string",
+						},
+					},
+					"struct": &stpb.Value{
+						Kind: &stpb.Value_StructValue{
+							StructValue: &stpb.Struct{
+								Fields: map[string]*stpb.Value{
+									"bool": &stpb.Value{
+										Kind: &stpb.Value_BoolValue{
+											BoolValue: false,
+										},
+									},
+								},
+							},
+						},
+					},
+					"list": &stpb.Value{
+						Kind: &stpb.Value_ListValue{
+							ListValue: &stpb.ListValue{
+								Values: []*stpb.Value{
+									{
+										Kind: &stpb.Value_BoolValue{
+											BoolValue: false,
+										},
+									},
+									{
+										Kind: &stpb.Value_StringValue{
+											StringValue: "hello",
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		}),
+		want: `opt_struct: {
+  fields: {
+    key: "bool"
+    value: {
+      bool_value: true
+    }
+  }
+  fields: {
+    key: "double"
+    value: {
+      number_value: 3.1415
+    }
+  }
+  fields: {
+    key: "list"
+    value: {
+      list_value: {
+        values: {
+          bool_value: false
+        }
+        values: {
+          string_value: "hello"
+        }
+      }
+    }
+  }
+  fields: {
+    key: "null"
+    value: {
+      null_value: NULL_VALUE
+    }
+  }
+  fields: {
+    key: "string"
+    value: {
+      string_value: "string"
+    }
+  }
+  fields: {
+    key: "struct"
+    value: {
+      struct_value: {
+        fields: {
+          key: "bool"
+          value: {
+            bool_value: false
+          }
+        }
+      }
+    }
+  }
+}
+`,
+	}}
+
+	for _, tt := range tests {
+		tt := tt
+		t.Run(tt.desc, func(t *testing.T) {
+			t.Parallel()
+			want := tt.want
+			b, err := textpb.Marshal(tt.input)
+			if err != nil && !tt.wantErr {
+				t.Errorf("Marshal() returned error: %v\n\n", err)
+			}
+			if tt.wantErr && err == nil {
+				t.Errorf("Marshal() got nil error, want error\n\n")
+			}
+			if got := string(b); got != want {
+				t.Errorf("Marshal()\n<got>\n%v\n<want>\n%v\n", got, want)
+				if diff := cmp.Diff(want, got, splitLines); diff != "" {
+					t.Errorf("Marshal() diff -want +got\n%v\n", diff)
+				}
+			}
+		})
+	}
+}
diff --git a/encoding/textpb/testprotos/pb2/test.pb.go b/encoding/textpb/testprotos/pb2/test.pb.go
new file mode 100644
index 0000000..e06f5f3
--- /dev/null
+++ b/encoding/textpb/testprotos/pb2/test.pb.go
@@ -0,0 +1,1319 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: encoding/textpb/testprotos/pb2/test.proto
+
+package pb2
+
+import (
+	fmt "fmt"
+	proto "github.com/golang/protobuf/proto"
+	any "github.com/golang/protobuf/ptypes/any"
+	duration "github.com/golang/protobuf/ptypes/duration"
+	empty "github.com/golang/protobuf/ptypes/empty"
+	_struct "github.com/golang/protobuf/ptypes/struct"
+	timestamp "github.com/golang/protobuf/ptypes/timestamp"
+	wrappers "github.com/golang/protobuf/ptypes/wrappers"
+	math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+type Enum int32
+
+const (
+	Enum_UNKNOWN Enum = 0
+	Enum_FIRST   Enum = 1
+	Enum_SECOND  Enum = 2
+	Enum_TENTH   Enum = 10
+)
+
+var Enum_name = map[int32]string{
+	0:  "UNKNOWN",
+	1:  "FIRST",
+	2:  "SECOND",
+	10: "TENTH",
+}
+
+var Enum_value = map[string]int32{
+	"UNKNOWN": 0,
+	"FIRST":   1,
+	"SECOND":  2,
+	"TENTH":   10,
+}
+
+func (x Enum) Enum() *Enum {
+	p := new(Enum)
+	*p = x
+	return p
+}
+
+func (x Enum) String() string {
+	return proto.EnumName(Enum_name, int32(x))
+}
+
+func (x *Enum) UnmarshalJSON(data []byte) error {
+	value, err := proto.UnmarshalJSONEnum(Enum_value, data, "Enum")
+	if err != nil {
+		return err
+	}
+	*x = Enum(value)
+	return nil
+}
+
+func (Enum) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{0}
+}
+
+type Enums_NestedEnum int32
+
+const (
+	Enums_UNO  Enums_NestedEnum = 1
+	Enums_DOS  Enums_NestedEnum = 2
+	Enums_DIEZ Enums_NestedEnum = 10
+)
+
+var Enums_NestedEnum_name = map[int32]string{
+	1:  "UNO",
+	2:  "DOS",
+	10: "DIEZ",
+}
+
+var Enums_NestedEnum_value = map[string]int32{
+	"UNO":  1,
+	"DOS":  2,
+	"DIEZ": 10,
+}
+
+func (x Enums_NestedEnum) Enum() *Enums_NestedEnum {
+	p := new(Enums_NestedEnum)
+	*p = x
+	return p
+}
+
+func (x Enums_NestedEnum) String() string {
+	return proto.EnumName(Enums_NestedEnum_name, int32(x))
+}
+
+func (x *Enums_NestedEnum) UnmarshalJSON(data []byte) error {
+	value, err := proto.UnmarshalJSONEnum(Enums_NestedEnum_value, data, "Enums_NestedEnum")
+	if err != nil {
+		return err
+	}
+	*x = Enums_NestedEnum(value)
+	return nil
+}
+
+func (Enums_NestedEnum) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{2, 0}
+}
+
+// Scalars contains optional scalar fields.
+type Scalars struct {
+	OptBool              *bool    `protobuf:"varint,1,opt,name=opt_bool,json=optBool" json:"opt_bool,omitempty"`
+	OptInt32             *int32   `protobuf:"varint,2,opt,name=opt_int32,json=optInt32" json:"opt_int32,omitempty"`
+	OptInt64             *int64   `protobuf:"varint,3,opt,name=opt_int64,json=optInt64" json:"opt_int64,omitempty"`
+	OptUint32            *uint32  `protobuf:"varint,4,opt,name=opt_uint32,json=optUint32" json:"opt_uint32,omitempty"`
+	OptUint64            *uint64  `protobuf:"varint,5,opt,name=opt_uint64,json=optUint64" json:"opt_uint64,omitempty"`
+	OptSint32            *int32   `protobuf:"zigzag32,6,opt,name=opt_sint32,json=optSint32" json:"opt_sint32,omitempty"`
+	OptSint64            *int64   `protobuf:"zigzag64,7,opt,name=opt_sint64,json=optSint64" json:"opt_sint64,omitempty"`
+	OptFixed32           *uint32  `protobuf:"fixed32,8,opt,name=opt_fixed32,json=optFixed32" json:"opt_fixed32,omitempty"`
+	OptFixed64           *uint64  `protobuf:"fixed64,9,opt,name=opt_fixed64,json=optFixed64" json:"opt_fixed64,omitempty"`
+	OptSfixed32          *int32   `protobuf:"fixed32,10,opt,name=opt_sfixed32,json=optSfixed32" json:"opt_sfixed32,omitempty"`
+	OptSfixed64          *int64   `protobuf:"fixed64,11,opt,name=opt_sfixed64,json=optSfixed64" json:"opt_sfixed64,omitempty"`
+	OptFloat             *float32 `protobuf:"fixed32,20,opt,name=opt_float,json=optFloat" json:"opt_float,omitempty"`
+	OptDouble            *float64 `protobuf:"fixed64,21,opt,name=opt_double,json=optDouble" json:"opt_double,omitempty"`
+	OptBytes             []byte   `protobuf:"bytes,14,opt,name=opt_bytes,json=optBytes" json:"opt_bytes,omitempty"`
+	OptString            *string  `protobuf:"bytes,13,opt,name=opt_string,json=optString" json:"opt_string,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *Scalars) Reset()         { *m = Scalars{} }
+func (m *Scalars) String() string { return proto.CompactTextString(m) }
+func (*Scalars) ProtoMessage()    {}
+func (*Scalars) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{0}
+}
+
+func (m *Scalars) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Scalars.Unmarshal(m, b)
+}
+func (m *Scalars) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Scalars.Marshal(b, m, deterministic)
+}
+func (m *Scalars) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Scalars.Merge(m, src)
+}
+func (m *Scalars) XXX_Size() int {
+	return xxx_messageInfo_Scalars.Size(m)
+}
+func (m *Scalars) XXX_DiscardUnknown() {
+	xxx_messageInfo_Scalars.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Scalars proto.InternalMessageInfo
+
+func (m *Scalars) GetOptBool() bool {
+	if m != nil && m.OptBool != nil {
+		return *m.OptBool
+	}
+	return false
+}
+
+func (m *Scalars) GetOptInt32() int32 {
+	if m != nil && m.OptInt32 != nil {
+		return *m.OptInt32
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptInt64() int64 {
+	if m != nil && m.OptInt64 != nil {
+		return *m.OptInt64
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptUint32() uint32 {
+	if m != nil && m.OptUint32 != nil {
+		return *m.OptUint32
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptUint64() uint64 {
+	if m != nil && m.OptUint64 != nil {
+		return *m.OptUint64
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptSint32() int32 {
+	if m != nil && m.OptSint32 != nil {
+		return *m.OptSint32
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptSint64() int64 {
+	if m != nil && m.OptSint64 != nil {
+		return *m.OptSint64
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptFixed32() uint32 {
+	if m != nil && m.OptFixed32 != nil {
+		return *m.OptFixed32
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptFixed64() uint64 {
+	if m != nil && m.OptFixed64 != nil {
+		return *m.OptFixed64
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptSfixed32() int32 {
+	if m != nil && m.OptSfixed32 != nil {
+		return *m.OptSfixed32
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptSfixed64() int64 {
+	if m != nil && m.OptSfixed64 != nil {
+		return *m.OptSfixed64
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptFloat() float32 {
+	if m != nil && m.OptFloat != nil {
+		return *m.OptFloat
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptDouble() float64 {
+	if m != nil && m.OptDouble != nil {
+		return *m.OptDouble
+	}
+	return 0
+}
+
+func (m *Scalars) GetOptBytes() []byte {
+	if m != nil {
+		return m.OptBytes
+	}
+	return nil
+}
+
+func (m *Scalars) GetOptString() string {
+	if m != nil && m.OptString != nil {
+		return *m.OptString
+	}
+	return ""
+}
+
+// Message contains repeated fields.
+type Repeats struct {
+	RptBool              []bool    `protobuf:"varint,1,rep,name=rpt_bool,json=rptBool" json:"rpt_bool,omitempty"`
+	RptInt32             []int32   `protobuf:"varint,2,rep,name=rpt_int32,json=rptInt32" json:"rpt_int32,omitempty"`
+	RptInt64             []int64   `protobuf:"varint,3,rep,name=rpt_int64,json=rptInt64" json:"rpt_int64,omitempty"`
+	RptUint32            []uint32  `protobuf:"varint,4,rep,name=rpt_uint32,json=rptUint32" json:"rpt_uint32,omitempty"`
+	RptUint64            []uint64  `protobuf:"varint,5,rep,name=rpt_uint64,json=rptUint64" json:"rpt_uint64,omitempty"`
+	RptFloat             []float32 `protobuf:"fixed32,6,rep,name=rpt_float,json=rptFloat" json:"rpt_float,omitempty"`
+	RptDouble            []float64 `protobuf:"fixed64,7,rep,name=rpt_double,json=rptDouble" json:"rpt_double,omitempty"`
+	RptString            []string  `protobuf:"bytes,15,rep,name=rpt_string,json=rptString" json:"rpt_string,omitempty"`
+	RptBytes             [][]byte  `protobuf:"bytes,14,rep,name=rpt_bytes,json=rptBytes" json:"rpt_bytes,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}  `json:"-"`
+	XXX_unrecognized     []byte    `json:"-"`
+	XXX_sizecache        int32     `json:"-"`
+}
+
+func (m *Repeats) Reset()         { *m = Repeats{} }
+func (m *Repeats) String() string { return proto.CompactTextString(m) }
+func (*Repeats) ProtoMessage()    {}
+func (*Repeats) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{1}
+}
+
+func (m *Repeats) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Repeats.Unmarshal(m, b)
+}
+func (m *Repeats) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Repeats.Marshal(b, m, deterministic)
+}
+func (m *Repeats) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Repeats.Merge(m, src)
+}
+func (m *Repeats) XXX_Size() int {
+	return xxx_messageInfo_Repeats.Size(m)
+}
+func (m *Repeats) XXX_DiscardUnknown() {
+	xxx_messageInfo_Repeats.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Repeats proto.InternalMessageInfo
+
+func (m *Repeats) GetRptBool() []bool {
+	if m != nil {
+		return m.RptBool
+	}
+	return nil
+}
+
+func (m *Repeats) GetRptInt32() []int32 {
+	if m != nil {
+		return m.RptInt32
+	}
+	return nil
+}
+
+func (m *Repeats) GetRptInt64() []int64 {
+	if m != nil {
+		return m.RptInt64
+	}
+	return nil
+}
+
+func (m *Repeats) GetRptUint32() []uint32 {
+	if m != nil {
+		return m.RptUint32
+	}
+	return nil
+}
+
+func (m *Repeats) GetRptUint64() []uint64 {
+	if m != nil {
+		return m.RptUint64
+	}
+	return nil
+}
+
+func (m *Repeats) GetRptFloat() []float32 {
+	if m != nil {
+		return m.RptFloat
+	}
+	return nil
+}
+
+func (m *Repeats) GetRptDouble() []float64 {
+	if m != nil {
+		return m.RptDouble
+	}
+	return nil
+}
+
+func (m *Repeats) GetRptString() []string {
+	if m != nil {
+		return m.RptString
+	}
+	return nil
+}
+
+func (m *Repeats) GetRptBytes() [][]byte {
+	if m != nil {
+		return m.RptBytes
+	}
+	return nil
+}
+
+// Message contains enum fields.
+type Enums struct {
+	OptEnum              *Enum              `protobuf:"varint,1,opt,name=opt_enum,json=optEnum,enum=pb2.Enum" json:"opt_enum,omitempty"`
+	RptEnum              []Enum             `protobuf:"varint,2,rep,name=rpt_enum,json=rptEnum,enum=pb2.Enum" json:"rpt_enum,omitempty"`
+	OptNestedEnum        *Enums_NestedEnum  `protobuf:"varint,3,opt,name=opt_nested_enum,json=optNestedEnum,enum=pb2.Enums_NestedEnum" json:"opt_nested_enum,omitempty"`
+	RptNestedEnum        []Enums_NestedEnum `protobuf:"varint,4,rep,name=rpt_nested_enum,json=rptNestedEnum,enum=pb2.Enums_NestedEnum" json:"rpt_nested_enum,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
+	XXX_unrecognized     []byte             `json:"-"`
+	XXX_sizecache        int32              `json:"-"`
+}
+
+func (m *Enums) Reset()         { *m = Enums{} }
+func (m *Enums) String() string { return proto.CompactTextString(m) }
+func (*Enums) ProtoMessage()    {}
+func (*Enums) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{2}
+}
+
+func (m *Enums) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Enums.Unmarshal(m, b)
+}
+func (m *Enums) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Enums.Marshal(b, m, deterministic)
+}
+func (m *Enums) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Enums.Merge(m, src)
+}
+func (m *Enums) XXX_Size() int {
+	return xxx_messageInfo_Enums.Size(m)
+}
+func (m *Enums) XXX_DiscardUnknown() {
+	xxx_messageInfo_Enums.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Enums proto.InternalMessageInfo
+
+func (m *Enums) GetOptEnum() Enum {
+	if m != nil && m.OptEnum != nil {
+		return *m.OptEnum
+	}
+	return Enum_UNKNOWN
+}
+
+func (m *Enums) GetRptEnum() []Enum {
+	if m != nil {
+		return m.RptEnum
+	}
+	return nil
+}
+
+func (m *Enums) GetOptNestedEnum() Enums_NestedEnum {
+	if m != nil && m.OptNestedEnum != nil {
+		return *m.OptNestedEnum
+	}
+	return Enums_UNO
+}
+
+func (m *Enums) GetRptNestedEnum() []Enums_NestedEnum {
+	if m != nil {
+		return m.RptNestedEnum
+	}
+	return nil
+}
+
+// Message contains message and group fields.
+type Nests struct {
+	OptNested            *Nested           `protobuf:"bytes,1,opt,name=opt_nested,json=optNested" json:"opt_nested,omitempty"`
+	Optgroup             *Nests_OptGroup   `protobuf:"group,2,opt,name=OptGroup,json=optgroup" json:"optgroup,omitempty"`
+	RptNested            []*Nested         `protobuf:"bytes,3,rep,name=rpt_nested,json=rptNested" json:"rpt_nested,omitempty"`
+	Rptgroup             []*Nests_RptGroup `protobuf:"group,4,rep,name=RptGroup,json=rptgroup" json:"rptgroup,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}          `json:"-"`
+	XXX_unrecognized     []byte            `json:"-"`
+	XXX_sizecache        int32             `json:"-"`
+}
+
+func (m *Nests) Reset()         { *m = Nests{} }
+func (m *Nests) String() string { return proto.CompactTextString(m) }
+func (*Nests) ProtoMessage()    {}
+func (*Nests) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{3}
+}
+
+func (m *Nests) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Nests.Unmarshal(m, b)
+}
+func (m *Nests) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Nests.Marshal(b, m, deterministic)
+}
+func (m *Nests) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Nests.Merge(m, src)
+}
+func (m *Nests) XXX_Size() int {
+	return xxx_messageInfo_Nests.Size(m)
+}
+func (m *Nests) XXX_DiscardUnknown() {
+	xxx_messageInfo_Nests.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Nests proto.InternalMessageInfo
+
+func (m *Nests) GetOptNested() *Nested {
+	if m != nil {
+		return m.OptNested
+	}
+	return nil
+}
+
+func (m *Nests) GetOptgroup() *Nests_OptGroup {
+	if m != nil {
+		return m.Optgroup
+	}
+	return nil
+}
+
+func (m *Nests) GetRptNested() []*Nested {
+	if m != nil {
+		return m.RptNested
+	}
+	return nil
+}
+
+func (m *Nests) GetRptgroup() []*Nests_RptGroup {
+	if m != nil {
+		return m.Rptgroup
+	}
+	return nil
+}
+
+type Nests_OptGroup struct {
+	OptBool              *bool                          `protobuf:"varint,1,opt,name=opt_bool,json=optBool" json:"opt_bool,omitempty"`
+	OptString            *string                        `protobuf:"bytes,2,opt,name=opt_string,json=optString" json:"opt_string,omitempty"`
+	OptNested            *Nested                        `protobuf:"bytes,3,opt,name=opt_nested,json=optNested" json:"opt_nested,omitempty"`
+	Optnestedgroup       *Nests_OptGroup_OptNestedGroup `protobuf:"group,4,opt,name=OptNestedGroup,json=optnestedgroup" json:"optnestedgroup,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}                       `json:"-"`
+	XXX_unrecognized     []byte                         `json:"-"`
+	XXX_sizecache        int32                          `json:"-"`
+}
+
+func (m *Nests_OptGroup) Reset()         { *m = Nests_OptGroup{} }
+func (m *Nests_OptGroup) String() string { return proto.CompactTextString(m) }
+func (*Nests_OptGroup) ProtoMessage()    {}
+func (*Nests_OptGroup) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{3, 0}
+}
+
+func (m *Nests_OptGroup) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Nests_OptGroup.Unmarshal(m, b)
+}
+func (m *Nests_OptGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Nests_OptGroup.Marshal(b, m, deterministic)
+}
+func (m *Nests_OptGroup) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Nests_OptGroup.Merge(m, src)
+}
+func (m *Nests_OptGroup) XXX_Size() int {
+	return xxx_messageInfo_Nests_OptGroup.Size(m)
+}
+func (m *Nests_OptGroup) XXX_DiscardUnknown() {
+	xxx_messageInfo_Nests_OptGroup.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Nests_OptGroup proto.InternalMessageInfo
+
+func (m *Nests_OptGroup) GetOptBool() bool {
+	if m != nil && m.OptBool != nil {
+		return *m.OptBool
+	}
+	return false
+}
+
+func (m *Nests_OptGroup) GetOptString() string {
+	if m != nil && m.OptString != nil {
+		return *m.OptString
+	}
+	return ""
+}
+
+func (m *Nests_OptGroup) GetOptNested() *Nested {
+	if m != nil {
+		return m.OptNested
+	}
+	return nil
+}
+
+func (m *Nests_OptGroup) GetOptnestedgroup() *Nests_OptGroup_OptNestedGroup {
+	if m != nil {
+		return m.Optnestedgroup
+	}
+	return nil
+}
+
+type Nests_OptGroup_OptNestedGroup struct {
+	OptEnum              *Enum    `protobuf:"varint,1,opt,name=opt_enum,json=optEnum,enum=pb2.Enum" json:"opt_enum,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *Nests_OptGroup_OptNestedGroup) Reset()         { *m = Nests_OptGroup_OptNestedGroup{} }
+func (m *Nests_OptGroup_OptNestedGroup) String() string { return proto.CompactTextString(m) }
+func (*Nests_OptGroup_OptNestedGroup) ProtoMessage()    {}
+func (*Nests_OptGroup_OptNestedGroup) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{3, 0, 0}
+}
+
+func (m *Nests_OptGroup_OptNestedGroup) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Nests_OptGroup_OptNestedGroup.Unmarshal(m, b)
+}
+func (m *Nests_OptGroup_OptNestedGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Nests_OptGroup_OptNestedGroup.Marshal(b, m, deterministic)
+}
+func (m *Nests_OptGroup_OptNestedGroup) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Nests_OptGroup_OptNestedGroup.Merge(m, src)
+}
+func (m *Nests_OptGroup_OptNestedGroup) XXX_Size() int {
+	return xxx_messageInfo_Nests_OptGroup_OptNestedGroup.Size(m)
+}
+func (m *Nests_OptGroup_OptNestedGroup) XXX_DiscardUnknown() {
+	xxx_messageInfo_Nests_OptGroup_OptNestedGroup.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Nests_OptGroup_OptNestedGroup proto.InternalMessageInfo
+
+func (m *Nests_OptGroup_OptNestedGroup) GetOptEnum() Enum {
+	if m != nil && m.OptEnum != nil {
+		return *m.OptEnum
+	}
+	return Enum_UNKNOWN
+}
+
+type Nests_RptGroup struct {
+	RptBool              []bool   `protobuf:"varint,1,rep,name=rpt_bool,json=rptBool" json:"rpt_bool,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *Nests_RptGroup) Reset()         { *m = Nests_RptGroup{} }
+func (m *Nests_RptGroup) String() string { return proto.CompactTextString(m) }
+func (*Nests_RptGroup) ProtoMessage()    {}
+func (*Nests_RptGroup) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{3, 1}
+}
+
+func (m *Nests_RptGroup) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Nests_RptGroup.Unmarshal(m, b)
+}
+func (m *Nests_RptGroup) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Nests_RptGroup.Marshal(b, m, deterministic)
+}
+func (m *Nests_RptGroup) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Nests_RptGroup.Merge(m, src)
+}
+func (m *Nests_RptGroup) XXX_Size() int {
+	return xxx_messageInfo_Nests_RptGroup.Size(m)
+}
+func (m *Nests_RptGroup) XXX_DiscardUnknown() {
+	xxx_messageInfo_Nests_RptGroup.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Nests_RptGroup proto.InternalMessageInfo
+
+func (m *Nests_RptGroup) GetRptBool() []bool {
+	if m != nil {
+		return m.RptBool
+	}
+	return nil
+}
+
+// Message type used as submessage.
+type Nested struct {
+	OptString            *string  `protobuf:"bytes,1,opt,name=opt_string,json=optString" json:"opt_string,omitempty"`
+	OptNested            *Nested  `protobuf:"bytes,2,opt,name=opt_nested,json=optNested" json:"opt_nested,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *Nested) Reset()         { *m = Nested{} }
+func (m *Nested) String() string { return proto.CompactTextString(m) }
+func (*Nested) ProtoMessage()    {}
+func (*Nested) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{4}
+}
+
+func (m *Nested) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Nested.Unmarshal(m, b)
+}
+func (m *Nested) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Nested.Marshal(b, m, deterministic)
+}
+func (m *Nested) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Nested.Merge(m, src)
+}
+func (m *Nested) XXX_Size() int {
+	return xxx_messageInfo_Nested.Size(m)
+}
+func (m *Nested) XXX_DiscardUnknown() {
+	xxx_messageInfo_Nested.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Nested proto.InternalMessageInfo
+
+func (m *Nested) GetOptString() string {
+	if m != nil && m.OptString != nil {
+		return *m.OptString
+	}
+	return ""
+}
+
+func (m *Nested) GetOptNested() *Nested {
+	if m != nil {
+		return m.OptNested
+	}
+	return nil
+}
+
+// Message contains required fields.
+type Requireds struct {
+	ReqBool              *bool    `protobuf:"varint,1,req,name=req_bool,json=reqBool" json:"req_bool,omitempty"`
+	ReqFixed32           *uint32  `protobuf:"fixed32,2,req,name=req_fixed32,json=reqFixed32" json:"req_fixed32,omitempty"`
+	ReqFixed64           *uint64  `protobuf:"fixed64,3,req,name=req_fixed64,json=reqFixed64" json:"req_fixed64,omitempty"`
+	ReqSfixed32          *int32   `protobuf:"fixed32,4,req,name=req_sfixed32,json=reqSfixed32" json:"req_sfixed32,omitempty"`
+	ReqSfixed64          *int64   `protobuf:"fixed64,5,req,name=req_sfixed64,json=reqSfixed64" json:"req_sfixed64,omitempty"`
+	ReqFloat             *float32 `protobuf:"fixed32,6,req,name=req_float,json=reqFloat" json:"req_float,omitempty"`
+	ReqDouble            *float64 `protobuf:"fixed64,7,req,name=req_double,json=reqDouble" json:"req_double,omitempty"`
+	ReqString            *string  `protobuf:"bytes,8,req,name=req_string,json=reqString" json:"req_string,omitempty"`
+	ReqBytes             []byte   `protobuf:"bytes,9,req,name=req_bytes,json=reqBytes" json:"req_bytes,omitempty"`
+	ReqEnum              *Enum    `protobuf:"varint,10,req,name=req_enum,json=reqEnum,enum=pb2.Enum" json:"req_enum,omitempty"`
+	ReqNested            *Nested  `protobuf:"bytes,11,req,name=req_nested,json=reqNested" json:"req_nested,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *Requireds) Reset()         { *m = Requireds{} }
+func (m *Requireds) String() string { return proto.CompactTextString(m) }
+func (*Requireds) ProtoMessage()    {}
+func (*Requireds) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{5}
+}
+
+func (m *Requireds) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Requireds.Unmarshal(m, b)
+}
+func (m *Requireds) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Requireds.Marshal(b, m, deterministic)
+}
+func (m *Requireds) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Requireds.Merge(m, src)
+}
+func (m *Requireds) XXX_Size() int {
+	return xxx_messageInfo_Requireds.Size(m)
+}
+func (m *Requireds) XXX_DiscardUnknown() {
+	xxx_messageInfo_Requireds.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Requireds proto.InternalMessageInfo
+
+func (m *Requireds) GetReqBool() bool {
+	if m != nil && m.ReqBool != nil {
+		return *m.ReqBool
+	}
+	return false
+}
+
+func (m *Requireds) GetReqFixed32() uint32 {
+	if m != nil && m.ReqFixed32 != nil {
+		return *m.ReqFixed32
+	}
+	return 0
+}
+
+func (m *Requireds) GetReqFixed64() uint64 {
+	if m != nil && m.ReqFixed64 != nil {
+		return *m.ReqFixed64
+	}
+	return 0
+}
+
+func (m *Requireds) GetReqSfixed32() int32 {
+	if m != nil && m.ReqSfixed32 != nil {
+		return *m.ReqSfixed32
+	}
+	return 0
+}
+
+func (m *Requireds) GetReqSfixed64() int64 {
+	if m != nil && m.ReqSfixed64 != nil {
+		return *m.ReqSfixed64
+	}
+	return 0
+}
+
+func (m *Requireds) GetReqFloat() float32 {
+	if m != nil && m.ReqFloat != nil {
+		return *m.ReqFloat
+	}
+	return 0
+}
+
+func (m *Requireds) GetReqDouble() float64 {
+	if m != nil && m.ReqDouble != nil {
+		return *m.ReqDouble
+	}
+	return 0
+}
+
+func (m *Requireds) GetReqString() string {
+	if m != nil && m.ReqString != nil {
+		return *m.ReqString
+	}
+	return ""
+}
+
+func (m *Requireds) GetReqBytes() []byte {
+	if m != nil {
+		return m.ReqBytes
+	}
+	return nil
+}
+
+func (m *Requireds) GetReqEnum() Enum {
+	if m != nil && m.ReqEnum != nil {
+		return *m.ReqEnum
+	}
+	return Enum_UNKNOWN
+}
+
+func (m *Requireds) GetReqNested() *Nested {
+	if m != nil {
+		return m.ReqNested
+	}
+	return nil
+}
+
+// Message contains oneof field.
+type Oneofs struct {
+	// Types that are valid to be assigned to Union:
+	//	*Oneofs_Str
+	//	*Oneofs_Msg
+	Union                isOneofs_Union `protobuf_oneof:"union"`
+	XXX_NoUnkeyedLiteral struct{}       `json:"-"`
+	XXX_unrecognized     []byte         `json:"-"`
+	XXX_sizecache        int32          `json:"-"`
+}
+
+func (m *Oneofs) Reset()         { *m = Oneofs{} }
+func (m *Oneofs) String() string { return proto.CompactTextString(m) }
+func (*Oneofs) ProtoMessage()    {}
+func (*Oneofs) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{6}
+}
+
+func (m *Oneofs) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Oneofs.Unmarshal(m, b)
+}
+func (m *Oneofs) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Oneofs.Marshal(b, m, deterministic)
+}
+func (m *Oneofs) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Oneofs.Merge(m, src)
+}
+func (m *Oneofs) XXX_Size() int {
+	return xxx_messageInfo_Oneofs.Size(m)
+}
+func (m *Oneofs) XXX_DiscardUnknown() {
+	xxx_messageInfo_Oneofs.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Oneofs proto.InternalMessageInfo
+
+type isOneofs_Union interface {
+	isOneofs_Union()
+}
+
+type Oneofs_Str struct {
+	Str string `protobuf:"bytes,1,opt,name=str,oneof"`
+}
+
+type Oneofs_Msg struct {
+	Msg *Nested `protobuf:"bytes,2,opt,name=msg,oneof"`
+}
+
+func (*Oneofs_Str) isOneofs_Union() {}
+
+func (*Oneofs_Msg) isOneofs_Union() {}
+
+func (m *Oneofs) GetUnion() isOneofs_Union {
+	if m != nil {
+		return m.Union
+	}
+	return nil
+}
+
+func (m *Oneofs) GetStr() string {
+	if x, ok := m.GetUnion().(*Oneofs_Str); ok {
+		return x.Str
+	}
+	return ""
+}
+
+func (m *Oneofs) GetMsg() *Nested {
+	if x, ok := m.GetUnion().(*Oneofs_Msg); ok {
+		return x.Msg
+	}
+	return nil
+}
+
+// XXX_OneofFuncs is for the internal use of the proto package.
+func (*Oneofs) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
+	return _Oneofs_OneofMarshaler, _Oneofs_OneofUnmarshaler, _Oneofs_OneofSizer, []interface{}{
+		(*Oneofs_Str)(nil),
+		(*Oneofs_Msg)(nil),
+	}
+}
+
+func _Oneofs_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
+	m := msg.(*Oneofs)
+	// union
+	switch x := m.Union.(type) {
+	case *Oneofs_Str:
+		b.EncodeVarint(1<<3 | proto.WireBytes)
+		b.EncodeStringBytes(x.Str)
+	case *Oneofs_Msg:
+		b.EncodeVarint(2<<3 | proto.WireBytes)
+		if err := b.EncodeMessage(x.Msg); err != nil {
+			return err
+		}
+	case nil:
+	default:
+		return fmt.Errorf("Oneofs.Union has unexpected type %T", x)
+	}
+	return nil
+}
+
+func _Oneofs_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
+	m := msg.(*Oneofs)
+	switch tag {
+	case 1: // union.str
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		x, err := b.DecodeStringBytes()
+		m.Union = &Oneofs_Str{x}
+		return true, err
+	case 2: // union.msg
+		if wire != proto.WireBytes {
+			return true, proto.ErrInternalBadWireType
+		}
+		msg := new(Nested)
+		err := b.DecodeMessage(msg)
+		m.Union = &Oneofs_Msg{msg}
+		return true, err
+	default:
+		return false, nil
+	}
+}
+
+func _Oneofs_OneofSizer(msg proto.Message) (n int) {
+	m := msg.(*Oneofs)
+	// union
+	switch x := m.Union.(type) {
+	case *Oneofs_Str:
+		n += 1 // tag and wire
+		n += proto.SizeVarint(uint64(len(x.Str)))
+		n += len(x.Str)
+	case *Oneofs_Msg:
+		s := proto.Size(x.Msg)
+		n += 1 // tag and wire
+		n += proto.SizeVarint(uint64(s))
+		n += s
+	case nil:
+	default:
+		panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
+	}
+	return n
+}
+
+// Message contains map fields.
+type Maps struct {
+	Int32ToStr           map[int32]string   `protobuf:"bytes,1,rep,name=int32_to_str,json=int32ToStr" json:"int32_to_str,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	Sfixed64ToBool       map[int64]bool     `protobuf:"bytes,2,rep,name=sfixed64_to_bool,json=sfixed64ToBool" json:"sfixed64_to_bool,omitempty" protobuf_key:"fixed64,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
+	BoolToUint32         map[bool]uint32    `protobuf:"bytes,3,rep,name=bool_to_uint32,json=boolToUint32" json:"bool_to_uint32,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value"`
+	Uint64ToEnum         map[uint64]Enum    `protobuf:"bytes,4,rep,name=uint64_to_enum,json=uint64ToEnum" json:"uint64_to_enum,omitempty" protobuf_key:"varint,1,opt,name=key" protobuf_val:"varint,2,opt,name=value,enum=pb2.Enum"`
+	StrToNested          map[string]*Nested `protobuf:"bytes,5,rep,name=str_to_nested,json=strToNested" json:"str_to_nested,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	StrToOneofs          map[string]*Oneofs `protobuf:"bytes,6,rep,name=str_to_oneofs,json=strToOneofs" json:"str_to_oneofs,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
+	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
+	XXX_unrecognized     []byte             `json:"-"`
+	XXX_sizecache        int32              `json:"-"`
+}
+
+func (m *Maps) Reset()         { *m = Maps{} }
+func (m *Maps) String() string { return proto.CompactTextString(m) }
+func (*Maps) ProtoMessage()    {}
+func (*Maps) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{7}
+}
+
+func (m *Maps) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Maps.Unmarshal(m, b)
+}
+func (m *Maps) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Maps.Marshal(b, m, deterministic)
+}
+func (m *Maps) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Maps.Merge(m, src)
+}
+func (m *Maps) XXX_Size() int {
+	return xxx_messageInfo_Maps.Size(m)
+}
+func (m *Maps) XXX_DiscardUnknown() {
+	xxx_messageInfo_Maps.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Maps proto.InternalMessageInfo
+
+func (m *Maps) GetInt32ToStr() map[int32]string {
+	if m != nil {
+		return m.Int32ToStr
+	}
+	return nil
+}
+
+func (m *Maps) GetSfixed64ToBool() map[int64]bool {
+	if m != nil {
+		return m.Sfixed64ToBool
+	}
+	return nil
+}
+
+func (m *Maps) GetBoolToUint32() map[bool]uint32 {
+	if m != nil {
+		return m.BoolToUint32
+	}
+	return nil
+}
+
+func (m *Maps) GetUint64ToEnum() map[uint64]Enum {
+	if m != nil {
+		return m.Uint64ToEnum
+	}
+	return nil
+}
+
+func (m *Maps) GetStrToNested() map[string]*Nested {
+	if m != nil {
+		return m.StrToNested
+	}
+	return nil
+}
+
+func (m *Maps) GetStrToOneofs() map[string]*Oneofs {
+	if m != nil {
+		return m.StrToOneofs
+	}
+	return nil
+}
+
+// Message contains well-known type fields.
+type KnownTypes struct {
+	OptBool              *wrappers.BoolValue   `protobuf:"bytes,1,opt,name=opt_bool,json=optBool" json:"opt_bool,omitempty"`
+	OptInt32             *wrappers.Int32Value  `protobuf:"bytes,2,opt,name=opt_int32,json=optInt32" json:"opt_int32,omitempty"`
+	OptInt64             *wrappers.Int64Value  `protobuf:"bytes,3,opt,name=opt_int64,json=optInt64" json:"opt_int64,omitempty"`
+	OptUint32            *wrappers.UInt32Value `protobuf:"bytes,4,opt,name=opt_uint32,json=optUint32" json:"opt_uint32,omitempty"`
+	OptUint64            *wrappers.UInt64Value `protobuf:"bytes,5,opt,name=opt_uint64,json=optUint64" json:"opt_uint64,omitempty"`
+	OptFloat             *wrappers.FloatValue  `protobuf:"bytes,6,opt,name=opt_float,json=optFloat" json:"opt_float,omitempty"`
+	OptDouble            *wrappers.DoubleValue `protobuf:"bytes,7,opt,name=opt_double,json=optDouble" json:"opt_double,omitempty"`
+	OptString            *wrappers.StringValue `protobuf:"bytes,8,opt,name=opt_string,json=optString" json:"opt_string,omitempty"`
+	OptBytes             *wrappers.BytesValue  `protobuf:"bytes,9,opt,name=opt_bytes,json=optBytes" json:"opt_bytes,omitempty"`
+	OptDuration          *duration.Duration    `protobuf:"bytes,20,opt,name=opt_duration,json=optDuration" json:"opt_duration,omitempty"`
+	OptTimestamp         *timestamp.Timestamp  `protobuf:"bytes,21,opt,name=opt_timestamp,json=optTimestamp" json:"opt_timestamp,omitempty"`
+	OptStruct            *_struct.Struct       `protobuf:"bytes,25,opt,name=opt_struct,json=optStruct" json:"opt_struct,omitempty"`
+	OptList              *_struct.ListValue    `protobuf:"bytes,26,opt,name=opt_list,json=optList" json:"opt_list,omitempty"`
+	OptValue             *_struct.Value        `protobuf:"bytes,27,opt,name=opt_value,json=optValue" json:"opt_value,omitempty"`
+	OptEmpty             *empty.Empty          `protobuf:"bytes,30,opt,name=opt_empty,json=optEmpty" json:"opt_empty,omitempty"`
+	OptAny               *any.Any              `protobuf:"bytes,32,opt,name=opt_any,json=optAny" json:"opt_any,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}              `json:"-"`
+	XXX_unrecognized     []byte                `json:"-"`
+	XXX_sizecache        int32                 `json:"-"`
+}
+
+func (m *KnownTypes) Reset()         { *m = KnownTypes{} }
+func (m *KnownTypes) String() string { return proto.CompactTextString(m) }
+func (*KnownTypes) ProtoMessage()    {}
+func (*KnownTypes) Descriptor() ([]byte, []int) {
+	return fileDescriptor_c8d7acc1bcec9a72, []int{8}
+}
+
+func (m *KnownTypes) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_KnownTypes.Unmarshal(m, b)
+}
+func (m *KnownTypes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_KnownTypes.Marshal(b, m, deterministic)
+}
+func (m *KnownTypes) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_KnownTypes.Merge(m, src)
+}
+func (m *KnownTypes) XXX_Size() int {
+	return xxx_messageInfo_KnownTypes.Size(m)
+}
+func (m *KnownTypes) XXX_DiscardUnknown() {
+	xxx_messageInfo_KnownTypes.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_KnownTypes proto.InternalMessageInfo
+
+func (m *KnownTypes) GetOptBool() *wrappers.BoolValue {
+	if m != nil {
+		return m.OptBool
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptInt32() *wrappers.Int32Value {
+	if m != nil {
+		return m.OptInt32
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptInt64() *wrappers.Int64Value {
+	if m != nil {
+		return m.OptInt64
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptUint32() *wrappers.UInt32Value {
+	if m != nil {
+		return m.OptUint32
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptUint64() *wrappers.UInt64Value {
+	if m != nil {
+		return m.OptUint64
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptFloat() *wrappers.FloatValue {
+	if m != nil {
+		return m.OptFloat
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptDouble() *wrappers.DoubleValue {
+	if m != nil {
+		return m.OptDouble
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptString() *wrappers.StringValue {
+	if m != nil {
+		return m.OptString
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptBytes() *wrappers.BytesValue {
+	if m != nil {
+		return m.OptBytes
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptDuration() *duration.Duration {
+	if m != nil {
+		return m.OptDuration
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptTimestamp() *timestamp.Timestamp {
+	if m != nil {
+		return m.OptTimestamp
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptStruct() *_struct.Struct {
+	if m != nil {
+		return m.OptStruct
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptList() *_struct.ListValue {
+	if m != nil {
+		return m.OptList
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptValue() *_struct.Value {
+	if m != nil {
+		return m.OptValue
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptEmpty() *empty.Empty {
+	if m != nil {
+		return m.OptEmpty
+	}
+	return nil
+}
+
+func (m *KnownTypes) GetOptAny() *any.Any {
+	if m != nil {
+		return m.OptAny
+	}
+	return nil
+}
+
+func init() {
+	proto.RegisterEnum("pb2.Enum", Enum_name, Enum_value)
+	proto.RegisterEnum("pb2.Enums_NestedEnum", Enums_NestedEnum_name, Enums_NestedEnum_value)
+	proto.RegisterType((*Scalars)(nil), "pb2.Scalars")
+	proto.RegisterType((*Repeats)(nil), "pb2.Repeats")
+	proto.RegisterType((*Enums)(nil), "pb2.Enums")
+	proto.RegisterType((*Nests)(nil), "pb2.Nests")
+	proto.RegisterType((*Nests_OptGroup)(nil), "pb2.Nests.OptGroup")
+	proto.RegisterType((*Nests_OptGroup_OptNestedGroup)(nil), "pb2.Nests.OptGroup.OptNestedGroup")
+	proto.RegisterType((*Nests_RptGroup)(nil), "pb2.Nests.RptGroup")
+	proto.RegisterType((*Nested)(nil), "pb2.Nested")
+	proto.RegisterType((*Requireds)(nil), "pb2.Requireds")
+	proto.RegisterType((*Oneofs)(nil), "pb2.Oneofs")
+	proto.RegisterType((*Maps)(nil), "pb2.Maps")
+	proto.RegisterMapType((map[bool]uint32)(nil), "pb2.Maps.BoolToUint32Entry")
+	proto.RegisterMapType((map[int32]string)(nil), "pb2.Maps.Int32ToStrEntry")
+	proto.RegisterMapType((map[int64]bool)(nil), "pb2.Maps.Sfixed64ToBoolEntry")
+	proto.RegisterMapType((map[string]*Nested)(nil), "pb2.Maps.StrToNestedEntry")
+	proto.RegisterMapType((map[string]*Oneofs)(nil), "pb2.Maps.StrToOneofsEntry")
+	proto.RegisterMapType((map[uint64]Enum)(nil), "pb2.Maps.Uint64ToEnumEntry")
+	proto.RegisterType((*KnownTypes)(nil), "pb2.KnownTypes")
+}
+
+func init() {
+	proto.RegisterFile("encoding/textpb/testprotos/pb2/test.proto", fileDescriptor_c8d7acc1bcec9a72)
+}
+
+var fileDescriptor_c8d7acc1bcec9a72 = []byte{
+	// 1521 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x58, 0xdb, 0x6e, 0xdb, 0x46,
+	0x10, 0x0d, 0x49, 0x5d, 0x57, 0xbe, 0x28, 0x4c, 0xd2, 0xd2, 0x72, 0x12, 0x33, 0x42, 0x0a, 0xb0,
+	0x01, 0x2a, 0x01, 0x8a, 0x22, 0x18, 0x75, 0x2e, 0xb0, 0x6b, 0x3b, 0xb7, 0xd6, 0x06, 0x28, 0xb9,
+	0x05, 0xf2, 0x62, 0x48, 0xf2, 0x5a, 0x15, 0x2a, 0x71, 0xa9, 0xe5, 0x32, 0x89, 0xfe, 0xa3, 0xdf,
+	0xd0, 0x9f, 0xe8, 0x9f, 0xf4, 0xa5, 0x3f, 0xd1, 0x87, 0x02, 0x7d, 0x29, 0x66, 0x96, 0x97, 0x15,
+	0x25, 0x19, 0x79, 0xd3, 0xee, 0xcc, 0x39, 0xb3, 0x33, 0xb3, 0x7b, 0x76, 0x29, 0xf2, 0x2d, 0xf5,
+	0x86, 0xec, 0x6a, 0xec, 0x8d, 0x9a, 0x82, 0x7e, 0x16, 0xfe, 0xa0, 0x29, 0x68, 0x20, 0x7c, 0xce,
+	0x04, 0x0b, 0x9a, 0xfe, 0xa0, 0x85, 0xc3, 0x06, 0x8e, 0x4d, 0xc3, 0x1f, 0xb4, 0x6a, 0x3b, 0x23,
+	0xc6, 0x46, 0x13, 0xda, 0xc4, 0xa9, 0x41, 0x78, 0xdd, 0xec, 0x7b, 0x73, 0x69, 0xaf, 0xed, 0x66,
+	0x4d, 0x74, 0xea, 0x8b, 0xd8, 0xf8, 0x30, 0x6b, 0xbc, 0x0a, 0x79, 0x5f, 0x8c, 0x99, 0x17, 0xd9,
+	0xef, 0x67, 0xed, 0x81, 0xe0, 0xe1, 0x30, 0x0a, 0x5d, 0xdb, 0xcb, 0x5a, 0xc5, 0x78, 0x4a, 0x03,
+	0xd1, 0x9f, 0xfa, 0xeb, 0xe8, 0x3f, 0xf1, 0xbe, 0xef, 0x53, 0x1e, 0x48, 0x7b, 0xfd, 0x2f, 0x83,
+	0x14, 0xbb, 0xc3, 0xfe, 0xa4, 0xcf, 0x03, 0x73, 0x87, 0x94, 0x98, 0x2f, 0x2e, 0x07, 0x8c, 0x4d,
+	0x2c, 0xcd, 0xd6, 0x9c, 0x92, 0x5b, 0x64, 0xbe, 0x38, 0x62, 0x6c, 0x62, 0xee, 0x92, 0x32, 0x98,
+	0xc6, 0x9e, 0x78, 0xda, 0xb2, 0x74, 0x5b, 0x73, 0xf2, 0x2e, 0xf8, 0xbe, 0x85, 0xb1, 0x62, 0xec,
+	0xb4, 0x2d, 0xc3, 0xd6, 0x1c, 0x23, 0x36, 0x76, 0xda, 0xe6, 0x03, 0x42, 0xc0, 0x18, 0x4a, 0x68,
+	0xce, 0xd6, 0x9c, 0x4d, 0x17, 0xdc, 0x2f, 0x70, 0x42, 0x35, 0x77, 0xda, 0x56, 0xde, 0xd6, 0x9c,
+	0x5c, 0x62, 0x4e, 0xd1, 0x81, 0x44, 0x17, 0x6c, 0xcd, 0xb9, 0x8d, 0xe6, 0xee, 0x02, 0x3a, 0x90,
+	0xe8, 0xa2, 0xad, 0x39, 0x66, 0x62, 0xee, 0xb4, 0xcd, 0x3d, 0x52, 0x01, 0xf3, 0xf5, 0xf8, 0x33,
+	0xbd, 0x7a, 0xda, 0xb2, 0x4a, 0xb6, 0xe6, 0x14, 0x5d, 0x40, 0x9c, 0xca, 0x99, 0x05, 0x87, 0x4e,
+	0xdb, 0x2a, 0xdb, 0x9a, 0x53, 0x48, 0x1d, 0x3a, 0x6d, 0xf3, 0x11, 0xd9, 0xc0, 0x00, 0x31, 0x05,
+	0xb1, 0x35, 0x67, 0xdb, 0x05, 0x50, 0x37, 0x9a, 0x5a, 0x74, 0xe9, 0xb4, 0xad, 0x8a, 0xad, 0x39,
+	0x55, 0xc5, 0xa5, 0xd3, 0x8e, 0x0b, 0x74, 0x3d, 0x61, 0x7d, 0x61, 0xdd, 0xb5, 0x35, 0x47, 0xc7,
+	0x02, 0x9d, 0xc2, 0x38, 0xce, 0xe1, 0x8a, 0x85, 0x83, 0x09, 0xb5, 0xee, 0xd9, 0x9a, 0xa3, 0x61,
+	0x0e, 0xc7, 0x38, 0x11, 0x63, 0x07, 0x73, 0x41, 0x03, 0x6b, 0xcb, 0xd6, 0x9c, 0x0d, 0xc4, 0x1e,
+	0xc1, 0x38, 0xc9, 0x5f, 0xf0, 0xb1, 0x37, 0xb2, 0x36, 0x6d, 0xcd, 0x29, 0xcb, 0xfc, 0x71, 0xa2,
+	0xfe, 0xbb, 0x4e, 0x8a, 0x2e, 0xf5, 0x69, 0x5f, 0x60, 0x73, 0x79, 0xda, 0x5c, 0x03, 0x9a, 0xcb,
+	0xd3, 0xe6, 0x72, 0xa5, 0xb9, 0x06, 0x34, 0x97, 0x2b, 0xcd, 0xe5, 0x4a, 0x73, 0x0d, 0x68, 0x2e,
+	0x57, 0x9a, 0xcb, 0xd5, 0xe6, 0x1a, 0xd0, 0x5c, 0xae, 0x36, 0x97, 0xab, 0xcd, 0x35, 0xa0, 0xb9,
+	0x3c, 0x69, 0x6e, 0x44, 0x2d, 0xcb, 0x52, 0xb0, 0x0d, 0x28, 0x0b, 0x57, 0xca, 0xc2, 0xd3, 0xb2,
+	0x14, 0x6d, 0x03, 0xca, 0xc2, 0x93, 0xb2, 0x44, 0xe6, 0x28, 0xf3, 0x6d, 0xdb, 0x80, 0xcc, 0x79,
+	0x9c, 0x79, 0x4c, 0x1d, 0x57, 0xcd, 0x80, 0xaa, 0xf1, 0xa8, 0x6a, 0xf5, 0xff, 0x34, 0x92, 0x3f,
+	0xf1, 0xc2, 0x69, 0x60, 0x3e, 0x96, 0x3b, 0x9e, 0x7a, 0xe1, 0x14, 0x77, 0xfc, 0x56, 0xab, 0xdc,
+	0xf0, 0x07, 0xad, 0x06, 0x58, 0x71, 0xf3, 0xc3, 0x0f, 0xf0, 0xe2, 0xb1, 0x17, 0x94, 0x67, 0xd1,
+	0x8b, 0x47, 0x5e, 0x2f, 0xc8, 0x36, 0x70, 0x79, 0x34, 0x10, 0xf4, 0x4a, 0x3a, 0x1b, 0x48, 0x79,
+	0x2f, 0x71, 0x0e, 0x1a, 0x67, 0x68, 0x45, 0xe0, 0x26, 0xf3, 0x45, 0x3a, 0x04, 0x38, 0xcf, 0xc0,
+	0x73, 0x18, 0x6b, 0x1d, 0x9c, 0xab, 0xf0, 0xba, 0x43, 0x88, 0x42, 0x56, 0x24, 0xc6, 0xc5, 0xd9,
+	0x79, 0x55, 0x83, 0x1f, 0xc7, 0xe7, 0xdd, 0xaa, 0x6e, 0x96, 0x48, 0xee, 0xf8, 0xed, 0xc9, 0x87,
+	0x2a, 0xa9, 0xff, 0x6d, 0x90, 0x3c, 0xb8, 0x06, 0xe6, 0x13, 0xb9, 0x7b, 0x64, 0x48, 0xcc, 0xbf,
+	0xd2, 0xaa, 0x60, 0x34, 0x49, 0x85, 0x5b, 0x49, 0xfe, 0x34, 0x9b, 0x58, 0xa9, 0x11, 0x67, 0xa1,
+	0x8f, 0xe7, 0x9f, 0xb4, 0xee, 0x24, 0x9e, 0x41, 0xe3, 0xdc, 0x17, 0xaf, 0xc1, 0xe4, 0x26, 0x4e,
+	0x40, 0x9e, 0xe6, 0x83, 0x1b, 0x27, 0x4b, 0xce, 0x55, 0x72, 0x1e, 0x93, 0x43, 0xd2, 0x8b, 0xe4,
+	0x6e, 0x42, 0x1e, 0x3b, 0xd5, 0xfe, 0xd1, 0x48, 0x29, 0x8e, 0x79, 0x93, 0x6c, 0x2d, 0x9e, 0x0f,
+	0x3d, 0x73, 0x3e, 0x32, 0x05, 0x30, 0x6e, 0x2c, 0xc0, 0x3b, 0xb2, 0xc5, 0x7c, 0x21, 0x5d, 0xe3,
+	0x95, 0x42, 0x19, 0xea, 0x2b, 0xca, 0x00, 0x3f, 0x24, 0x4c, 0x2e, 0x3c, 0x83, 0xac, 0x75, 0xc8,
+	0xd6, 0xa2, 0xc7, 0x97, 0x6d, 0xc4, 0xda, 0x37, 0xa4, 0xe4, 0x2a, 0x59, 0xaf, 0x39, 0xcf, 0xf5,
+	0x2e, 0x29, 0x44, 0x8b, 0x5e, 0xcc, 0x5f, 0xbb, 0x39, 0x7f, 0xfd, 0xa6, 0xfc, 0xeb, 0xff, 0xea,
+	0xa4, 0xec, 0xd2, 0x59, 0x38, 0xe6, 0xf4, 0x4a, 0xaa, 0x09, 0x9d, 0xc5, 0xd1, 0x75, 0x8c, 0x4e,
+	0x67, 0x58, 0xf3, 0x3d, 0x52, 0x01, 0x53, 0xac, 0x98, 0xba, 0xad, 0x83, 0xe8, 0x72, 0x3a, 0x53,
+	0x44, 0x37, 0x71, 0x40, 0x4d, 0xd1, 0x41, 0x74, 0x63, 0x07, 0x29, 0xba, 0xe0, 0x90, 0x88, 0x6e,
+	0xce, 0xd6, 0x41, 0x74, 0x39, 0x9d, 0xa9, 0xa2, 0x9b, 0xba, 0xa0, 0xb6, 0xe8, 0x20, 0xba, 0x89,
+	0x4b, 0xa4, 0x2e, 0x10, 0x26, 0x52, 0x17, 0x1d, 0xd5, 0x85, 0xce, 0x52, 0x75, 0xa1, 0xb3, 0x54,
+	0x5d, 0x74, 0x54, 0x17, 0x3a, 0x53, 0xd4, 0x05, 0xe8, 0x65, 0xdd, 0x4a, 0xb6, 0x8e, 0xea, 0x42,
+	0x67, 0x8a, 0xba, 0x40, 0xf6, 0xa8, 0x2e, 0x65, 0x5b, 0x47, 0x75, 0xa1, 0x33, 0xa9, 0xc9, 0x8f,
+	0x65, 0x69, 0xb0, 0x95, 0xc4, 0xd6, 0xb3, 0x6a, 0x41, 0x67, 0x78, 0x42, 0x9f, 0xc8, 0x08, 0x51,
+	0xe9, 0x2b, 0xb6, 0xbe, 0x7c, 0x3c, 0xe8, 0x2c, 0x2a, 0xfd, 0x29, 0x29, 0x9c, 0x7b, 0x94, 0x5d,
+	0x07, 0xa6, 0x49, 0x8c, 0x40, 0x70, 0xd9, 0xc8, 0x37, 0xb7, 0x5c, 0x18, 0x98, 0x7b, 0xc4, 0x98,
+	0x06, 0xa3, 0x15, 0xdd, 0x03, 0x87, 0x69, 0x30, 0x3a, 0x2a, 0x92, 0x7c, 0xe8, 0x8d, 0x99, 0x57,
+	0xff, 0xb3, 0x40, 0x72, 0x3f, 0xf5, 0xfd, 0xc0, 0x3c, 0x20, 0x1b, 0x28, 0xd0, 0x97, 0x82, 0x5d,
+	0x4a, 0x3e, 0x38, 0x9d, 0x3b, 0x88, 0x05, 0x87, 0x06, 0x4a, 0x7f, 0x8f, 0x75, 0x05, 0x3f, 0xf1,
+	0x04, 0x9f, 0xbb, 0x64, 0x9c, 0x4c, 0x98, 0xaf, 0x49, 0x35, 0x2e, 0x3b, 0xe0, 0x71, 0x0b, 0xe8,
+	0x48, 0xf0, 0x20, 0x25, 0x88, 0xbb, 0xd0, 0x63, 0xb0, 0x27, 0x24, 0xc9, 0x56, 0xb0, 0x30, 0x69,
+	0x1e, 0x92, 0x2d, 0x00, 0x03, 0x49, 0x74, 0x81, 0x48, 0x95, 0xd8, 0x4d, 0x69, 0xc0, 0xaf, 0xc7,
+	0xe4, 0x6d, 0x22, 0x49, 0x36, 0x06, 0xca, 0x14, 0x50, 0xc8, 0xcb, 0x05, 0x48, 0x12, 0xcd, 0x5c,
+	0xa0, 0x90, 0x77, 0x4d, 0x8f, 0x41, 0xd5, 0x23, 0x8a, 0x50, 0x99, 0x32, 0x5f, 0x92, 0xcd, 0x40,
+	0x70, 0xc0, 0x47, 0xbd, 0xc8, 0x23, 0x43, 0x4d, 0xc9, 0x45, 0xf0, 0x1e, 0x8b, 0xc5, 0x15, 0x08,
+	0x2a, 0x41, 0x3a, 0xa3, 0xe0, 0x19, 0xf6, 0x08, 0x2f, 0xb2, 0x65, 0xbc, 0x6c, 0xa0, 0x8a, 0x97,
+	0x33, 0xb5, 0x17, 0x64, 0x3b, 0x53, 0x6d, 0xb3, 0x4a, 0x8c, 0xdf, 0xe8, 0x1c, 0xbb, 0x9c, 0x77,
+	0xe1, 0xa7, 0x79, 0x97, 0xe4, 0x3f, 0xf6, 0x27, 0x21, 0x8d, 0x24, 0x4c, 0x0e, 0xbe, 0xd7, 0xf7,
+	0xb5, 0xda, 0x21, 0xb9, 0xb3, 0xa2, 0xd6, 0x2a, 0x45, 0x75, 0x05, 0x45, 0x49, 0xa5, 0x78, 0x45,
+	0x6e, 0x2f, 0xd5, 0x59, 0x25, 0x28, 0xad, 0x20, 0xd8, 0x54, 0x09, 0xde, 0x91, 0xdb, 0x4b, 0x55,
+	0x56, 0x09, 0x72, 0x92, 0x60, 0x4f, 0x25, 0x58, 0x38, 0x15, 0x0a, 0xd7, 0x7b, 0x52, 0xcd, 0xd6,
+	0x5b, 0xa5, 0x2a, 0x4b, 0xaa, 0x47, 0x2a, 0x55, 0xe6, 0xe0, 0xac, 0x20, 0x53, 0x8a, 0xff, 0xa5,
+	0x64, 0x12, 0xa2, 0x90, 0xd5, 0xff, 0x28, 0x12, 0xf2, 0xde, 0x63, 0x9f, 0xbc, 0xde, 0xdc, 0xa7,
+	0x81, 0xf9, 0x2c, 0x73, 0xeb, 0x40, 0xcb, 0xe5, 0x5b, 0xbb, 0x11, 0xbf, 0xb5, 0x71, 0xfb, 0xfe,
+	0x0c, 0x04, 0xe9, 0x8d, 0xb4, 0x9f, 0x7d, 0x48, 0xc3, 0x66, 0xcd, 0xe2, 0x70, 0x43, 0x48, 0x60,
+	0xfa, 0xca, 0xde, 0xcf, 0xbe, 0xb2, 0xd7, 0x20, 0x3b, 0xed, 0x05, 0x64, 0xa7, 0x6d, 0x1e, 0x2c,
+	0x3d, 0xc1, 0x2b, 0xad, 0xfb, 0x4b, 0xd0, 0x0b, 0x25, 0xaa, 0xf2, 0x40, 0x3f, 0x58, 0x7a, 0xa0,
+	0xaf, 0x03, 0xc7, 0x81, 0x95, 0xe7, 0xfb, 0xbe, 0xfa, 0xf0, 0x2d, 0xac, 0x59, 0x33, 0x2a, 0x72,
+	0xba, 0x66, 0x29, 0xd0, 0x07, 0x0b, 0xaf, 0xe2, 0xe2, 0x9a, 0xb0, 0x52, 0xae, 0xd3, 0xb0, 0x91,
+	0x7c, 0x1f, 0x2c, 0x5c, 0x7b, 0xa5, 0x35, 0x60, 0x29, 0xe6, 0x29, 0x38, 0x12, 0xf7, 0x7d, 0xf5,
+	0xc1, 0x5d, 0x5e, 0xb3, 0x66, 0x94, 0xfa, 0x74, 0xcd, 0x52, 0xf9, 0x9f, 0xcb, 0x2f, 0x81, 0xf8,
+	0x03, 0x0e, 0x5f, 0xfa, 0x20, 0xab, 0x4b, 0xab, 0x8e, 0x1c, 0xf0, 0x23, 0x21, 0x1e, 0x98, 0xaf,
+	0x08, 0xbc, 0x08, 0x2f, 0x93, 0x0f, 0x38, 0xfc, 0x14, 0x58, 0xb5, 0xab, 0x7a, 0xb1, 0x87, 0x0b,
+	0xe1, 0x92, 0x91, 0xd9, 0x49, 0xb2, 0x0e, 0x87, 0xc2, 0xda, 0x41, 0xf4, 0xd7, 0xab, 0xb2, 0x0e,
+	0x87, 0x22, 0x4e, 0x38, 0x1c, 0x8a, 0x78, 0x27, 0x4f, 0xc6, 0x81, 0xb0, 0x6a, 0x6b, 0x62, 0xfe,
+	0x38, 0x0e, 0x44, 0xba, 0x93, 0x61, 0x64, 0x3e, 0x95, 0x75, 0x92, 0x47, 0x67, 0x17, 0x71, 0x5f,
+	0x2d, 0xe1, 0xd2, 0x12, 0xe1, 0xaf, 0x18, 0x84, 0x1f, 0xc0, 0xd6, 0xc3, 0x35, 0xa0, 0x13, 0xb0,
+	0x22, 0x08, 0x7f, 0x99, 0xdf, 0x11, 0x08, 0x7a, 0xd9, 0xf7, 0xe6, 0x96, 0x8d, 0x90, 0xbb, 0x4b,
+	0x90, 0x43, 0x6f, 0xee, 0x16, 0x98, 0x2f, 0x0e, 0xbd, 0xf9, 0x93, 0x67, 0x24, 0x87, 0xca, 0x5e,
+	0x21, 0xc5, 0x8b, 0xb3, 0xf7, 0x67, 0xe7, 0xbf, 0x9c, 0x55, 0x6f, 0x99, 0x65, 0x92, 0x3f, 0x7d,
+	0xeb, 0x76, 0x7b, 0x55, 0xcd, 0x24, 0xa4, 0xd0, 0x3d, 0xf9, 0xe1, 0xfc, 0xec, 0xb8, 0xaa, 0xc3,
+	0x74, 0xef, 0xe4, 0xac, 0xf7, 0xa6, 0x4a, 0x8e, 0x5e, 0x7e, 0x78, 0x3e, 0x1a, 0x8b, 0x5f, 0xc3,
+	0x41, 0x63, 0xc8, 0xa6, 0xcd, 0x11, 0x9b, 0xf4, 0xbd, 0x51, 0xfa, 0xd9, 0xfc, 0xb1, 0xd5, 0xbc,
+	0xf9, 0x0f, 0x81, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x64, 0x29, 0xf9, 0x97, 0x31, 0x10, 0x00,
+	0x00,
+}
diff --git a/encoding/textpb/testprotos/pb2/test.proto b/encoding/textpb/testprotos/pb2/test.proto
new file mode 100644
index 0000000..21edaca
--- /dev/null
+++ b/encoding/textpb/testprotos/pb2/test.proto
@@ -0,0 +1,151 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test Protobuf definitions with proto2 syntax.
+syntax = "proto2";
+
+package pb2;
+option go_package = "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb2";
+
+import "google/protobuf/any.proto";
+import "google/protobuf/empty.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/struct.proto";
+import "google/protobuf/timestamp.proto";
+import "google/protobuf/wrappers.proto";
+
+// Scalars contains optional scalar fields.
+message Scalars {
+  optional bool opt_bool = 1;
+
+  optional int32 opt_int32 = 2;
+  optional int64 opt_int64 = 3;
+  optional uint32 opt_uint32 = 4;
+  optional uint64 opt_uint64 = 5;
+  optional sint32 opt_sint32 = 6;
+  optional sint64 opt_sint64 = 7;
+  optional fixed32 opt_fixed32 = 8;
+  optional fixed64 opt_fixed64 = 9;
+  optional sfixed32 opt_sfixed32 = 10;
+  optional sfixed64 opt_sfixed64 = 11;
+
+  optional float opt_float = 20;
+  optional double opt_double = 21;
+
+  optional bytes opt_bytes = 14;
+  optional string opt_string = 13;
+}
+
+// Message contains repeated fields.
+message Repeats {
+  repeated bool rpt_bool = 1;
+  repeated int32 rpt_int32 = 2;
+  repeated int64 rpt_int64 = 3;
+  repeated uint32 rpt_uint32 = 4;
+  repeated uint64 rpt_uint64 = 5;
+  repeated float rpt_float = 6;
+  repeated double rpt_double = 7;
+  repeated string rpt_string = 15;
+  repeated bytes rpt_bytes = 14;
+}
+
+enum Enum {
+  UNKNOWN = 0;
+  FIRST = 1;
+  SECOND = 2;
+  TENTH = 10;
+}
+
+// Message contains enum fields.
+message Enums {
+  optional Enum opt_enum = 1;
+  repeated Enum rpt_enum = 2;
+
+  enum NestedEnum {
+	UNO = 1;
+	DOS = 2;
+	DIEZ = 10;
+  }
+  optional NestedEnum opt_nested_enum = 3;
+  repeated NestedEnum rpt_nested_enum = 4;
+}
+
+// Message contains message and group fields.
+message Nests {
+  optional Nested opt_nested = 1;
+  optional group OptGroup = 2 {
+    optional bool opt_bool = 1;
+    optional string opt_string = 2;
+    optional Nested opt_nested = 3;
+
+    optional group OptNestedGroup = 4 {
+      optional Enum opt_enum = 1;
+    }
+  }
+
+  repeated Nested rpt_nested = 3;
+  repeated group RptGroup = 4 {
+    repeated bool rpt_bool = 1;
+  }
+}
+
+// Message type used as submessage.
+message Nested {
+  optional string opt_string = 1;
+  optional Nested opt_nested = 2;
+}
+
+// Message contains required fields.
+message Requireds {
+  required bool req_bool = 1;
+  required fixed32 req_fixed32 = 2;
+  required fixed64 req_fixed64 = 3;
+  required sfixed32 req_sfixed32 = 4;
+  required sfixed64 req_sfixed64 = 5;
+  required float req_float = 6;
+  required double req_double = 7;
+  required string req_string = 8;
+  required bytes req_bytes = 9;
+  required Enum req_enum = 10;
+  required Nested req_nested = 11;
+}
+
+// Message contains oneof field.
+message Oneofs {
+  oneof union {
+    string str = 1;
+    Nested msg = 2;
+  }
+}
+
+// Message contains map fields.
+message Maps {
+  map<int32, string> int32_to_str = 1;
+  map<sfixed64, bool> sfixed64_to_bool = 2;
+  map<bool, uint32> bool_to_uint32 = 3;
+  map<uint64, Enum> uint64_to_enum = 4;
+  map<string, Nested> str_to_nested = 5;
+  map<string, Oneofs> str_to_oneofs = 6;
+}
+
+// Message contains well-known type fields.
+message KnownTypes {
+  optional google.protobuf.BoolValue opt_bool = 1;
+  optional google.protobuf.Int32Value opt_int32 = 2;
+  optional google.protobuf.Int64Value opt_int64 = 3;
+  optional google.protobuf.UInt32Value opt_uint32 = 4;
+  optional google.protobuf.UInt64Value opt_uint64 = 5;
+  optional google.protobuf.FloatValue opt_float = 6;
+  optional google.protobuf.DoubleValue opt_double = 7;
+  optional google.protobuf.StringValue opt_string = 8;
+  optional google.protobuf.BytesValue opt_bytes = 9;
+
+  optional google.protobuf.Duration opt_duration = 20;
+  optional google.protobuf.Timestamp opt_timestamp = 21;
+  optional google.protobuf.Struct opt_struct = 25;
+  optional google.protobuf.ListValue opt_list = 26;
+  optional google.protobuf.Value opt_value = 27;
+  optional google.protobuf.Empty opt_empty = 30;
+  optional google.protobuf.Any opt_any = 32;
+}
diff --git a/encoding/textpb/testprotos/pb3/test.pb.go b/encoding/textpb/testprotos/pb3/test.pb.go
new file mode 100644
index 0000000..c5c2fb2
--- /dev/null
+++ b/encoding/textpb/testprotos/pb3/test.pb.go
@@ -0,0 +1,449 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: encoding/textpb/testprotos/pb3/test.proto
+
+package pb3
+
+import (
+	fmt "fmt"
+	proto "github.com/golang/protobuf/proto"
+	_ "github.com/golang/protobuf/ptypes/struct"
+	math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+
+type Enum int32
+
+const (
+	Enum_ZERO Enum = 0
+	Enum_ONE  Enum = 1
+	Enum_TWO  Enum = 2
+	Enum_TEN  Enum = 10
+)
+
+var Enum_name = map[int32]string{
+	0:  "ZERO",
+	1:  "ONE",
+	2:  "TWO",
+	10: "TEN",
+}
+
+var Enum_value = map[string]int32{
+	"ZERO": 0,
+	"ONE":  1,
+	"TWO":  2,
+	"TEN":  10,
+}
+
+func (x Enum) String() string {
+	return proto.EnumName(Enum_name, int32(x))
+}
+
+func (Enum) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_0854715c5b41c422, []int{0}
+}
+
+type Enums_NestedEnum int32
+
+const (
+	Enums_CERO Enums_NestedEnum = 0
+	Enums_UNO  Enums_NestedEnum = 1
+	Enums_DOS  Enums_NestedEnum = 2
+	Enums_DIEZ Enums_NestedEnum = 10
+)
+
+var Enums_NestedEnum_name = map[int32]string{
+	0:  "CERO",
+	1:  "UNO",
+	2:  "DOS",
+	10: "DIEZ",
+}
+
+var Enums_NestedEnum_value = map[string]int32{
+	"CERO": 0,
+	"UNO":  1,
+	"DOS":  2,
+	"DIEZ": 10,
+}
+
+func (x Enums_NestedEnum) String() string {
+	return proto.EnumName(Enums_NestedEnum_name, int32(x))
+}
+
+func (Enums_NestedEnum) EnumDescriptor() ([]byte, []int) {
+	return fileDescriptor_0854715c5b41c422, []int{1, 0}
+}
+
+// Scalars contains scalar field types.
+type Scalars struct {
+	SBool                bool     `protobuf:"varint,1,opt,name=s_bool,json=sBool,proto3" json:"s_bool,omitempty"`
+	SInt32               int32    `protobuf:"varint,2,opt,name=s_int32,json=sInt32,proto3" json:"s_int32,omitempty"`
+	SInt64               int64    `protobuf:"varint,3,opt,name=s_int64,json=sInt64,proto3" json:"s_int64,omitempty"`
+	SUint32              uint32   `protobuf:"varint,4,opt,name=s_uint32,json=sUint32,proto3" json:"s_uint32,omitempty"`
+	SUint64              uint64   `protobuf:"varint,5,opt,name=s_uint64,json=sUint64,proto3" json:"s_uint64,omitempty"`
+	SSint32              int32    `protobuf:"zigzag32,6,opt,name=s_sint32,json=sSint32,proto3" json:"s_sint32,omitempty"`
+	SSint64              int64    `protobuf:"zigzag64,7,opt,name=s_sint64,json=sSint64,proto3" json:"s_sint64,omitempty"`
+	SFixed32             uint32   `protobuf:"fixed32,8,opt,name=s_fixed32,json=sFixed32,proto3" json:"s_fixed32,omitempty"`
+	SFixed64             uint64   `protobuf:"fixed64,9,opt,name=s_fixed64,json=sFixed64,proto3" json:"s_fixed64,omitempty"`
+	SSfixed32            int32    `protobuf:"fixed32,10,opt,name=s_sfixed32,json=sSfixed32,proto3" json:"s_sfixed32,omitempty"`
+	SSfixed64            int64    `protobuf:"fixed64,11,opt,name=s_sfixed64,json=sSfixed64,proto3" json:"s_sfixed64,omitempty"`
+	SFloat               float32  `protobuf:"fixed32,20,opt,name=s_float,json=sFloat,proto3" json:"s_float,omitempty"`
+	SDouble              float64  `protobuf:"fixed64,21,opt,name=s_double,json=sDouble,proto3" json:"s_double,omitempty"`
+	SBytes               []byte   `protobuf:"bytes,14,opt,name=s_bytes,json=sBytes,proto3" json:"s_bytes,omitempty"`
+	SString              string   `protobuf:"bytes,13,opt,name=s_string,json=sString,proto3" json:"s_string,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *Scalars) Reset()         { *m = Scalars{} }
+func (m *Scalars) String() string { return proto.CompactTextString(m) }
+func (*Scalars) ProtoMessage()    {}
+func (*Scalars) Descriptor() ([]byte, []int) {
+	return fileDescriptor_0854715c5b41c422, []int{0}
+}
+
+func (m *Scalars) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Scalars.Unmarshal(m, b)
+}
+func (m *Scalars) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Scalars.Marshal(b, m, deterministic)
+}
+func (m *Scalars) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Scalars.Merge(m, src)
+}
+func (m *Scalars) XXX_Size() int {
+	return xxx_messageInfo_Scalars.Size(m)
+}
+func (m *Scalars) XXX_DiscardUnknown() {
+	xxx_messageInfo_Scalars.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Scalars proto.InternalMessageInfo
+
+func (m *Scalars) GetSBool() bool {
+	if m != nil {
+		return m.SBool
+	}
+	return false
+}
+
+func (m *Scalars) GetSInt32() int32 {
+	if m != nil {
+		return m.SInt32
+	}
+	return 0
+}
+
+func (m *Scalars) GetSInt64() int64 {
+	if m != nil {
+		return m.SInt64
+	}
+	return 0
+}
+
+func (m *Scalars) GetSUint32() uint32 {
+	if m != nil {
+		return m.SUint32
+	}
+	return 0
+}
+
+func (m *Scalars) GetSUint64() uint64 {
+	if m != nil {
+		return m.SUint64
+	}
+	return 0
+}
+
+func (m *Scalars) GetSSint32() int32 {
+	if m != nil {
+		return m.SSint32
+	}
+	return 0
+}
+
+func (m *Scalars) GetSSint64() int64 {
+	if m != nil {
+		return m.SSint64
+	}
+	return 0
+}
+
+func (m *Scalars) GetSFixed32() uint32 {
+	if m != nil {
+		return m.SFixed32
+	}
+	return 0
+}
+
+func (m *Scalars) GetSFixed64() uint64 {
+	if m != nil {
+		return m.SFixed64
+	}
+	return 0
+}
+
+func (m *Scalars) GetSSfixed32() int32 {
+	if m != nil {
+		return m.SSfixed32
+	}
+	return 0
+}
+
+func (m *Scalars) GetSSfixed64() int64 {
+	if m != nil {
+		return m.SSfixed64
+	}
+	return 0
+}
+
+func (m *Scalars) GetSFloat() float32 {
+	if m != nil {
+		return m.SFloat
+	}
+	return 0
+}
+
+func (m *Scalars) GetSDouble() float64 {
+	if m != nil {
+		return m.SDouble
+	}
+	return 0
+}
+
+func (m *Scalars) GetSBytes() []byte {
+	if m != nil {
+		return m.SBytes
+	}
+	return nil
+}
+
+func (m *Scalars) GetSString() string {
+	if m != nil {
+		return m.SString
+	}
+	return ""
+}
+
+// Message contains enum fields.
+type Enums struct {
+	SEnum                Enum               `protobuf:"varint,1,opt,name=s_enum,json=sEnum,proto3,enum=pb3.Enum" json:"s_enum,omitempty"`
+	RptEnum              []Enum             `protobuf:"varint,2,rep,packed,name=rpt_enum,json=rptEnum,proto3,enum=pb3.Enum" json:"rpt_enum,omitempty"`
+	SNestedEnum          Enums_NestedEnum   `protobuf:"varint,3,opt,name=s_nested_enum,json=sNestedEnum,proto3,enum=pb3.Enums_NestedEnum" json:"s_nested_enum,omitempty"`
+	RptNestedEnum        []Enums_NestedEnum `protobuf:"varint,4,rep,packed,name=rpt_nested_enum,json=rptNestedEnum,proto3,enum=pb3.Enums_NestedEnum" json:"rpt_nested_enum,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}           `json:"-"`
+	XXX_unrecognized     []byte             `json:"-"`
+	XXX_sizecache        int32              `json:"-"`
+}
+
+func (m *Enums) Reset()         { *m = Enums{} }
+func (m *Enums) String() string { return proto.CompactTextString(m) }
+func (*Enums) ProtoMessage()    {}
+func (*Enums) Descriptor() ([]byte, []int) {
+	return fileDescriptor_0854715c5b41c422, []int{1}
+}
+
+func (m *Enums) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Enums.Unmarshal(m, b)
+}
+func (m *Enums) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Enums.Marshal(b, m, deterministic)
+}
+func (m *Enums) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Enums.Merge(m, src)
+}
+func (m *Enums) XXX_Size() int {
+	return xxx_messageInfo_Enums.Size(m)
+}
+func (m *Enums) XXX_DiscardUnknown() {
+	xxx_messageInfo_Enums.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Enums proto.InternalMessageInfo
+
+func (m *Enums) GetSEnum() Enum {
+	if m != nil {
+		return m.SEnum
+	}
+	return Enum_ZERO
+}
+
+func (m *Enums) GetRptEnum() []Enum {
+	if m != nil {
+		return m.RptEnum
+	}
+	return nil
+}
+
+func (m *Enums) GetSNestedEnum() Enums_NestedEnum {
+	if m != nil {
+		return m.SNestedEnum
+	}
+	return Enums_CERO
+}
+
+func (m *Enums) GetRptNestedEnum() []Enums_NestedEnum {
+	if m != nil {
+		return m.RptNestedEnum
+	}
+	return nil
+}
+
+// Message contains message and group fields.
+type Nests struct {
+	SNested              *Nested   `protobuf:"bytes,1,opt,name=s_nested,json=sNested,proto3" json:"s_nested,omitempty"`
+	RptNested            []*Nested `protobuf:"bytes,2,rep,name=rpt_nested,json=rptNested,proto3" json:"rpt_nested,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}  `json:"-"`
+	XXX_unrecognized     []byte    `json:"-"`
+	XXX_sizecache        int32     `json:"-"`
+}
+
+func (m *Nests) Reset()         { *m = Nests{} }
+func (m *Nests) String() string { return proto.CompactTextString(m) }
+func (*Nests) ProtoMessage()    {}
+func (*Nests) Descriptor() ([]byte, []int) {
+	return fileDescriptor_0854715c5b41c422, []int{2}
+}
+
+func (m *Nests) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Nests.Unmarshal(m, b)
+}
+func (m *Nests) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Nests.Marshal(b, m, deterministic)
+}
+func (m *Nests) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Nests.Merge(m, src)
+}
+func (m *Nests) XXX_Size() int {
+	return xxx_messageInfo_Nests.Size(m)
+}
+func (m *Nests) XXX_DiscardUnknown() {
+	xxx_messageInfo_Nests.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Nests proto.InternalMessageInfo
+
+func (m *Nests) GetSNested() *Nested {
+	if m != nil {
+		return m.SNested
+	}
+	return nil
+}
+
+func (m *Nests) GetRptNested() []*Nested {
+	if m != nil {
+		return m.RptNested
+	}
+	return nil
+}
+
+// Message type used as submessage.
+type Nested struct {
+	SString              string   `protobuf:"bytes,1,opt,name=s_string,json=sString,proto3" json:"s_string,omitempty"`
+	SNested              *Nested  `protobuf:"bytes,2,opt,name=s_nested,json=sNested,proto3" json:"s_nested,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *Nested) Reset()         { *m = Nested{} }
+func (m *Nested) String() string { return proto.CompactTextString(m) }
+func (*Nested) ProtoMessage()    {}
+func (*Nested) Descriptor() ([]byte, []int) {
+	return fileDescriptor_0854715c5b41c422, []int{3}
+}
+
+func (m *Nested) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Nested.Unmarshal(m, b)
+}
+func (m *Nested) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Nested.Marshal(b, m, deterministic)
+}
+func (m *Nested) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Nested.Merge(m, src)
+}
+func (m *Nested) XXX_Size() int {
+	return xxx_messageInfo_Nested.Size(m)
+}
+func (m *Nested) XXX_DiscardUnknown() {
+	xxx_messageInfo_Nested.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Nested proto.InternalMessageInfo
+
+func (m *Nested) GetSString() string {
+	if m != nil {
+		return m.SString
+	}
+	return ""
+}
+
+func (m *Nested) GetSNested() *Nested {
+	if m != nil {
+		return m.SNested
+	}
+	return nil
+}
+
+func init() {
+	proto.RegisterEnum("pb3.Enum", Enum_name, Enum_value)
+	proto.RegisterEnum("pb3.Enums_NestedEnum", Enums_NestedEnum_name, Enums_NestedEnum_value)
+	proto.RegisterType((*Scalars)(nil), "pb3.Scalars")
+	proto.RegisterType((*Enums)(nil), "pb3.Enums")
+	proto.RegisterType((*Nests)(nil), "pb3.Nests")
+	proto.RegisterType((*Nested)(nil), "pb3.Nested")
+}
+
+func init() {
+	proto.RegisterFile("encoding/textpb/testprotos/pb3/test.proto", fileDescriptor_0854715c5b41c422)
+}
+
+var fileDescriptor_0854715c5b41c422 = []byte{
+	// 566 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x53, 0x5f, 0x6b, 0xdb, 0x3e,
+	0x14, 0xfd, 0x29, 0x4e, 0xec, 0xe4, 0xe6, 0x97, 0xd6, 0x13, 0x2b, 0xf3, 0xfe, 0x81, 0x08, 0x63,
+	0x68, 0x1d, 0xc4, 0x90, 0x18, 0xc3, 0x60, 0xdb, 0x43, 0xd7, 0x14, 0xca, 0x20, 0x01, 0x67, 0x65,
+	0xd0, 0x3d, 0x84, 0x38, 0x71, 0xbd, 0x80, 0x6b, 0x19, 0x5f, 0x79, 0x74, 0x5f, 0x66, 0xdf, 0x74,
+	0x30, 0x24, 0x39, 0x89, 0x3b, 0xe8, 0x9e, 0xac, 0xe3, 0x73, 0x8e, 0xee, 0x3d, 0xf7, 0x22, 0x78,
+	0x93, 0xe4, 0x6b, 0xb1, 0xd9, 0xe6, 0xa9, 0x2f, 0x93, 0x3b, 0x59, 0xc4, 0xbe, 0x4c, 0x50, 0x16,
+	0xa5, 0x90, 0x02, 0xfd, 0x22, 0x9e, 0x68, 0x38, 0xd2, 0x98, 0x5a, 0x45, 0x3c, 0x79, 0xf6, 0x22,
+	0x15, 0x22, 0xcd, 0x12, 0x5f, 0xff, 0x8a, 0xab, 0x1b, 0x1f, 0x65, 0x59, 0xad, 0x6b, 0xc9, 0xf0,
+	0x97, 0x05, 0xce, 0x62, 0xbd, 0xca, 0x56, 0x25, 0xd2, 0x13, 0xb0, 0x71, 0x19, 0x0b, 0x91, 0x79,
+	0x84, 0x11, 0xde, 0x8d, 0x3a, 0x78, 0x26, 0x44, 0x46, 0x9f, 0x80, 0x83, 0xcb, 0x6d, 0x2e, 0x27,
+	0x63, 0xaf, 0xc5, 0x08, 0xef, 0x44, 0x36, 0x5e, 0x2a, 0xb4, 0x27, 0xc2, 0xc0, 0xb3, 0x18, 0xe1,
+	0x96, 0x21, 0xc2, 0x80, 0x3e, 0x85, 0x2e, 0x2e, 0x2b, 0x63, 0x69, 0x33, 0xc2, 0x07, 0x91, 0x83,
+	0x57, 0x1a, 0x1e, 0xa8, 0x30, 0xf0, 0x3a, 0x8c, 0xf0, 0x76, 0x4d, 0xed, 0x5c, 0x68, 0x5c, 0x36,
+	0x23, 0xfc, 0x51, 0xe4, 0xe0, 0xa2, 0xe1, 0x42, 0xe3, 0x72, 0x18, 0xe1, 0xb4, 0xa6, 0xc2, 0x80,
+	0x3e, 0x87, 0x1e, 0x2e, 0x6f, 0xb6, 0x77, 0xc9, 0x66, 0x32, 0xf6, 0xba, 0x8c, 0x70, 0x27, 0xea,
+	0xe2, 0x85, 0xc1, 0x0d, 0x32, 0x0c, 0xbc, 0x1e, 0x23, 0xdc, 0xde, 0x91, 0x61, 0x40, 0x5f, 0x02,
+	0xe0, 0x12, 0x77, 0x56, 0x60, 0x84, 0x1f, 0x47, 0x3d, 0x5c, 0xd4, 0x3f, 0x9a, 0x74, 0x18, 0x78,
+	0x7d, 0x46, 0xb8, 0xbb, 0xa7, 0xc3, 0xc0, 0x84, 0xbf, 0xc9, 0xc4, 0x4a, 0x7a, 0x8f, 0x19, 0xe1,
+	0xad, 0xc8, 0xc6, 0x0b, 0x85, 0x4c, 0xaf, 0x1b, 0x51, 0xc5, 0x59, 0xe2, 0x9d, 0x30, 0xc2, 0x49,
+	0xe4, 0xe0, 0xb9, 0x86, 0xc6, 0x13, 0xff, 0x94, 0x09, 0x7a, 0x47, 0x8c, 0xf0, 0xff, 0x23, 0x1b,
+	0xcf, 0x14, 0xaa, 0xf3, 0xc9, 0x72, 0x9b, 0xa7, 0xde, 0x80, 0x11, 0xde, 0x53, 0xf9, 0x34, 0x1c,
+	0xfe, 0x26, 0xd0, 0x99, 0xe6, 0xd5, 0x2d, 0x52, 0xa6, 0xd6, 0x93, 0xe4, 0xd5, 0xad, 0x5e, 0xcf,
+	0xd1, 0xb8, 0x37, 0x2a, 0xe2, 0xc9, 0x48, 0x71, 0x51, 0x07, 0xd5, 0x87, 0xbe, 0x82, 0x6e, 0x59,
+	0x48, 0xa3, 0x69, 0x31, 0xeb, 0xbe, 0xc6, 0x29, 0x0b, 0xa9, 0x55, 0xef, 0x60, 0x80, 0xcb, 0x3c,
+	0x41, 0x99, 0x6c, 0x8c, 0xd4, 0xd2, 0xd7, 0x9d, 0xec, 0xa5, 0x38, 0x9a, 0x69, 0x56, 0xdb, 0xfa,
+	0x78, 0x00, 0xf4, 0x03, 0x1c, 0xab, 0x02, 0x4d, 0x73, 0x5b, 0xd7, 0x79, 0xc0, 0x3c, 0x28, 0x0b,
+	0x79, 0x80, 0xc3, 0x31, 0x40, 0xe3, 0xb2, 0x2e, 0xb4, 0x3f, 0x4d, 0xa3, 0xb9, 0xfb, 0x1f, 0x75,
+	0xc0, 0xba, 0x9a, 0xcd, 0x5d, 0xa2, 0x0e, 0xe7, 0xf3, 0x85, 0xdb, 0x52, 0xdc, 0xf9, 0xe5, 0xf4,
+	0xda, 0x85, 0xe1, 0x37, 0xe8, 0x28, 0x0f, 0xd2, 0xd7, 0x6a, 0x46, 0xa6, 0xb2, 0x1e, 0x40, 0x7f,
+	0xdc, 0xd7, 0x45, 0xcd, 0x8d, 0x91, 0x53, 0xf7, 0x49, 0x4f, 0x01, 0x0e, 0x3d, 0xea, 0x31, 0xfc,
+	0xa5, 0xec, 0xed, 0x9b, 0x1a, 0x7e, 0x06, 0xbb, 0x76, 0x35, 0x37, 0x40, 0xee, 0x6d, 0xe0, 0x5e,
+	0xe1, 0xd6, 0xc3, 0x85, 0x4f, 0xdf, 0x42, 0x7b, 0x97, 0xeb, 0x7a, 0x9f, 0x6b, 0x3e, 0x9b, 0x9a,
+	0x5c, 0x5f, 0xbe, 0xce, 0xdd, 0x96, 0x3e, 0x4c, 0x67, 0x2e, 0x9c, 0x7d, 0xbc, 0x7e, 0x9f, 0x6e,
+	0xe5, 0xf7, 0x2a, 0x1e, 0xad, 0xc5, 0xad, 0x9f, 0x8a, 0x6c, 0x95, 0xa7, 0x87, 0x27, 0xfa, 0x63,
+	0xec, 0xff, 0xfb, 0x95, 0xc7, 0xb6, 0x3e, 0x4f, 0xfe, 0x04, 0x00, 0x00, 0xff, 0xff, 0xef, 0xcf,
+	0x95, 0x7a, 0x0e, 0x04, 0x00, 0x00,
+}
diff --git a/encoding/textpb/testprotos/pb3/test.proto b/encoding/textpb/testprotos/pb3/test.proto
new file mode 100644
index 0000000..9825b75
--- /dev/null
+++ b/encoding/textpb/testprotos/pb3/test.proto
@@ -0,0 +1,65 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test Protobuf definitions with proto3 syntax.
+syntax = "proto3";
+
+package pb3;
+option go_package = "github.com/golang/protobuf/v2/encoding/textpb/testprotos/pb3";
+
+// Scalars contains scalar field types.
+message Scalars {
+  bool s_bool = 1;
+
+  int32 s_int32 = 2;
+  int64 s_int64 = 3;
+  uint32 s_uint32 = 4;
+  uint64 s_uint64 = 5;
+  sint32 s_sint32 = 6;
+  sint64 s_sint64 = 7;
+  fixed32 s_fixed32 = 8;
+  fixed64 s_fixed64 = 9;
+  sfixed32 s_sfixed32 = 10;
+  sfixed64 s_sfixed64 = 11;
+
+  float s_float = 20;
+  double s_double = 21;
+
+  bytes s_bytes = 14;
+  string s_string = 13;
+}
+
+enum Enum {
+  ZERO = 0;
+  ONE = 1;
+  TWO = 2;
+  TEN = 10;
+}
+
+// Message contains enum fields.
+message Enums {
+  Enum s_enum = 1;
+  repeated Enum rpt_enum = 2;
+
+  enum NestedEnum {
+  	CERO = 0;
+	UNO = 1;
+	DOS = 2;
+	DIEZ = 10;
+  }
+  NestedEnum s_nested_enum = 3;
+  repeated NestedEnum rpt_nested_enum = 4;
+}
+
+// Message contains message and group fields.
+message Nests {
+  Nested s_nested = 1;
+  repeated Nested rpt_nested = 2;
+}
+
+// Message type used as submessage.
+message Nested {
+  string s_string = 1;
+  Nested s_nested = 2;
+}
diff --git a/go.sum b/go.sum
index f84c3f4..c97d598 100644
--- a/go.sum
+++ b/go.sum
@@ -1,12 +1,15 @@
-github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
 github.com/golang/protobuf v1.2.1-0.20181127190454-8d0c54c12466/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
 github.com/golang/protobuf v1.2.1-0.20181129223256-87f1426e5305 h1:L8Akf3H3kki1x1DO8Yb3O47G/DspWKG8l8FPNP+Figk=
 github.com/golang/protobuf v1.2.1-0.20181129223256-87f1426e5305/go.mod h1:asK8yRb/+zxJTE0SbTESCku/4OjiDfbPwk4rEyIatUA=
 github.com/golang/protobuf/v2 v2.0.0-20181127193627-d7e97bc71bcb/go.mod h1:MgUD+N3FwzDmj2CdMsT5ap7K7jx+c9cQDQ7fVhmH+Xw=
+github.com/google/go-cmp v0.2.1-0.20181101181452-745b8ec83783 h1:wVZ6laEGf86tNDTpR5mxFyFIclJJiXCxuJhcQKnsOHk=
 github.com/google/go-cmp v0.2.1-0.20181101181452-745b8ec83783/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3 h1:dgd4x4kJt7G4k4m93AYLzM8Ni6h2qLTfh9n9vXJT3/0=
 golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/tools v0.0.0-20180904205237-0aa4b8830f48/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180928181343-b3c0be4c978b h1:hjfKpJoTfQ2QXKPX9eCDFBZ0t9sDrZL/viAgrN962TQ=
 golang.org/x/tools v0.0.0-20180928181343-b3c0be4c978b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
diff --git a/proto/proto.go b/proto/proto.go
new file mode 100644
index 0000000..0f20339
--- /dev/null
+++ b/proto/proto.go
@@ -0,0 +1,10 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package proto
+
+import "github.com/golang/protobuf/v2/reflect/protoreflect"
+
+// Message is the top-level interface that all messages must implement.
+type Message = protoreflect.ProtoMessage