internal/impl: add fast-path marshal implementation

This is a port of the v1 table marshaler, with some substantial
cleanup and refactoring.

Benchstat results from the protobuf reference benchmark data comparing the
v1 package with v2, with AllowPartial:true set for the new package. This
is not an apples-to-apples comparison, since v1 doesn't have a way to
disable required field checks.  Required field checks in v2 package
currently go through reflection, which performs terribly; my initial
experimentation indicates that fast-path required field checks will
not add a large amount of cost; these results are incomplete but not
wholly inaccurate.

name                                           old time/op  new time/op  delta
/dataset.google_message3_1.pb/Marshal-12        219ms ± 1%   232ms ± 1%   +5.85%  (p=0.004 n=6+5)
/dataset.google_message2.pb/Marshal-12          261µs ± 3%   248µs ± 1%   -5.14%  (p=0.002 n=6+6)
/dataset.google_message1_proto2.pb/Marshal-12   681ns ± 2%   637ns ± 3%   -6.53%  (p=0.002 n=6+6)
/dataset.google_message1_proto3.pb/Marshal-12  1.10µs ± 8%  0.99µs ± 3%   -9.63%  (p=0.002 n=6+6)
/dataset.google_message3_3.pb/Marshal-12       44.2ms ± 3%  35.2ms ± 1%  -20.28%  (p=0.004 n=6+5)
/dataset.google_message4.pb/Marshal-12         91.4ms ± 2%  94.9ms ± 2%   +3.78%  (p=0.002 n=6+6)
/dataset.google_message3_2.pb/Marshal-12       78.7ms ± 6%  80.8ms ± 4%     ~     (p=0.310 n=6+6)
/dataset.google_message3_4.pb/Marshal-12       10.6ms ± 3%  10.6ms ± 8%     ~     (p=0.662 n=5+6)
/dataset.google_message3_5.pb/Marshal-12        675ms ± 4%   510ms ± 2%  -24.40%  (p=0.002 n=6+6)
/dataset.google_message3_1.pb/Marshal           219ms ± 1%   236ms ± 7%   +8.06%  (p=0.004 n=5+6)
/dataset.google_message2.pb/Marshal             257µs ± 1%   250µs ± 3%     ~     (p=0.052 n=5+6)
/dataset.google_message1_proto2.pb/Marshal      685ns ± 1%   628ns ± 1%   -8.41%  (p=0.008 n=5+5)
/dataset.google_message1_proto3.pb/Marshal     1.08µs ± 1%  0.98µs ± 2%   -9.31%  (p=0.004 n=5+6)
/dataset.google_message3_3.pb/Marshal          43.7ms ± 1%  35.1ms ± 1%  -19.76%  (p=0.002 n=6+6)
/dataset.google_message4.pb/Marshal            93.4ms ± 4%  94.9ms ± 2%     ~     (p=0.180 n=6+6)
/dataset.google_message3_2.pb/Marshal           105ms ± 2%    98ms ± 7%   -6.81%  (p=0.009 n=5+6)
/dataset.google_message3_4.pb/Marshal          16.3ms ± 6%  15.7ms ± 3%   -3.44%  (p=0.041 n=6+6)
/dataset.google_message3_5.pb/Marshal           676ms ± 4%   504ms ± 2%  -25.50%  (p=0.004 n=6+5)

Change-Id: I72cc4597117f4cf5d236ef505777d49dd4a5f75d
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/171020
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/internal/cmd/generate-types/impl.go b/internal/cmd/generate-types/impl.go
new file mode 100644
index 0000000..05945ec
--- /dev/null
+++ b/internal/cmd/generate-types/impl.go
@@ -0,0 +1,255 @@
+// Copyright 2019 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 main
+
+import (
+	"text/template"
+)
+
+func generateImplEncode() string {
+	return mustExecute(implEncodeTemplate, ProtoKinds)
+}
+
+var implEncodeTemplate = template.Must(template.New("").Parse(`
+{{- /*
+  IsZero is an expression testing if 'v' is the zero value.
+*/ -}}
+{{- define "IsZero" -}}
+{{if eq .WireType "Bytes" -}}
+len(v) == 0
+{{- else if or (eq .Name "Double") (eq .Name "Float") -}}
+v == 0 && !math.Signbit(float64(v))
+{{- else -}}
+v == {{.GoType.Zero}}
+{{- end -}}
+{{- end -}}
+
+{{- /*
+  Size is an expression computing the size of 'v'.
+*/ -}}
+{{- define "Size" -}}
+{{- if .WireType.ConstSize -}}
+wire.Size{{.WireType}}()
+{{- else if eq .WireType "Bytes" -}}
+wire.SizeBytes(len({{.FromGoType}}))
+{{- else -}}
+wire.Size{{.WireType}}({{.FromGoType}})
+{{- end -}}
+{{- end -}}
+
+{{- /*
+  Append is a set of statements appending 'v' to 'b'.
+*/ -}}
+{{- define "Append" -}}
+b = wire.Append{{.WireType}}(b, {{.FromGoType}})
+{{- end -}}
+
+{{- range .}}
+{{- if .FromGoType }}
+// size{{.Name}} returns the size of wire encoding a {{.GoType}} pointer as a {{.Name}}.
+func size{{.Name}}(p pointer, tagsize int, _ marshalOptions) (size int) {
+	{{if not .WireType.ConstSize -}}
+	v := *p.{{.GoType.PointerMethod}}()
+	{{- end}}
+	return tagsize + {{template "Size" .}}
+}
+
+// append{{.Name}} wire encodes a {{.GoType}} pointer as a {{.Name}}.
+func append{{.Name}}(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.{{.GoType.PointerMethod}}()
+	b = wire.AppendVarint(b, wiretag)
+	{{template "Append" .}}
+	return b, nil
+}
+
+var coder{{.Name}} = pointerCoderFuncs{
+	size:    size{{.Name}},
+	marshal: append{{.Name}},
+}
+
+// size{{.Name}} returns the size of wire encoding a {{.GoType}} pointer as a {{.Name}}.
+// The zero value is not encoded.
+func size{{.Name}}NoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.{{.GoType.PointerMethod}}()
+	if {{template "IsZero" .}} {
+		return 0
+	}
+	return tagsize + {{template "Size" .}}
+}
+
+// append{{.Name}} wire encodes a {{.GoType}} pointer as a {{.Name}}.
+// The zero value is not encoded.
+func append{{.Name}}NoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.{{.GoType.PointerMethod}}()
+	if {{template "IsZero" .}} {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	{{template "Append" .}}
+	return b, nil
+}
+
+var coder{{.Name}}NoZero = pointerCoderFuncs{
+	size:    size{{.Name}}NoZero,
+	marshal: append{{.Name}}NoZero,
+}
+
+{{- if not .NoPointer}}
+// size{{.Name}}Ptr returns the size of wire encoding a *{{.GoType}} pointer as a {{.Name}}.
+// It panics if the pointer is nil.
+func size{{.Name}}Ptr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	{{if not .WireType.ConstSize -}}
+	v := **p.{{.GoType.PointerMethod}}Ptr()
+	{{end -}}
+	return tagsize + {{template "Size" .}}
+}
+
+// append{{.Name}} wire encodes a *{{.GoType}} pointer as a {{.Name}}.
+// It panics if the pointer is nil.
+func append{{.Name}}Ptr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.{{.GoType.PointerMethod}}Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	{{template "Append" .}}
+	return b, nil
+}
+
+var coder{{.Name}}Ptr = pointerCoderFuncs{
+	size:    size{{.Name}}Ptr,
+	marshal: append{{.Name}}Ptr,
+}
+{{end}}
+
+// size{{.Name}}Slice returns the size of wire encoding a []{{.GoType}} pointer as a repeated {{.Name}}.
+func size{{.Name}}Slice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.{{.GoType.PointerMethod}}Slice()
+	{{if .WireType.ConstSize -}}
+	size = len(s) * (tagsize + {{template "Size" .}})
+	{{- else -}}
+	for _, v := range s {
+		size += tagsize + {{template "Size" .}}
+	}
+	{{- end}}
+	return size
+}
+
+// append{{.Name}}Slice encodes a []{{.GoType}} pointer as a repeated {{.Name}}.
+func append{{.Name}}Slice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.{{.GoType.PointerMethod}}Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		{{template "Append" .}}
+	}
+	return b, nil
+}
+
+var coder{{.Name}}Slice = pointerCoderFuncs{
+	size:    size{{.Name}}Slice,
+	marshal: append{{.Name}}Slice,
+}
+
+{{if or (eq .WireType "Varint") (eq .WireType "Fixed32") (eq .WireType "Fixed64")}}
+// size{{.Name}}PackedSlice returns the size of wire encoding a []{{.GoType}} pointer as a packed repeated {{.Name}}.
+func size{{.Name}}PackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.{{.GoType.PointerMethod}}Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	{{if .WireType.ConstSize -}}
+	n := len(s) * {{template "Size" .}}
+	{{- else -}}
+	n := 0
+	for _, v := range s {
+		n += {{template "Size" .}}
+	}
+	{{- end}}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// append{{.Name}}PackedSlice encodes a []{{.GoType}} pointer as a packed repeated {{.Name}}.
+func append{{.Name}}PackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.{{.GoType.PointerMethod}}Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	{{if .WireType.ConstSize -}}
+	n := len(s) * {{template "Size" .}}
+	{{- else -}}
+	n := 0
+	for _, v := range s {
+		n += {{template "Size" .}}
+	}
+	{{- end}}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		{{template "Append" .}}
+	}
+	return b, nil
+}
+
+var coder{{.Name}}PackedSlice = pointerCoderFuncs{
+	size:    size{{.Name}}PackedSlice,
+	marshal: append{{.Name}}PackedSlice,
+}
+{{end}}
+
+// size{{.Name}}Iface returns the size of wire encoding a {{.GoType}} value as a {{.Name}}.
+func size{{.Name}}Iface(ival interface{}, tagsize int, _ marshalOptions) int {
+	{{- if not .WireType.ConstSize}}
+	v := ival.({{.GoType}})
+	{{end -}}
+	return tagsize + {{template "Size" .}}
+}
+
+// append{{.Name}}Iface encodes a {{.GoType}} value as a {{.Name}}.
+func append{{.Name}}Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.({{.GoType}})
+	b = wire.AppendVarint(b, wiretag)
+	{{template "Append" .}}
+	return b, nil
+}
+
+var coder{{.Name}}Iface = ifaceCoderFuncs{
+	size:    size{{.Name}}Iface,
+	marshal: append{{.Name}}Iface,
+}
+
+// size{{.Name}}SliceIface returns the size of wire encoding a []{{.GoType}} value as a repeated {{.Name}}.
+func size{{.Name}}SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]{{.GoType}})
+	{{if .WireType.ConstSize -}}
+	size = len(s) * (tagsize + {{template "Size" .}})
+	{{- else -}}
+	for _, v := range s {
+		size += tagsize + {{template "Size" .}}
+	}
+	{{- end}}
+	return size
+}
+
+// append{{.Name}}SliceIface encodes a []{{.GoType}} value as a repeated {{.Name}}.
+func append{{.Name}}SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]{{.GoType}})
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		{{template "Append" .}}
+	}
+	return b, nil
+}
+
+var coder{{.Name}}SliceIface = ifaceCoderFuncs{
+	size:    size{{.Name}}SliceIface,
+	marshal: append{{.Name}}SliceIface,
+}
+
+{{end -}}
+{{end -}}
+
+var wireTypes = map[protoreflect.Kind]wire.Type{
+{{range . -}}
+	protoreflect.{{.Name}}Kind: {{.WireType.Expr}},
+{{end}}
+}
+`))
diff --git a/internal/cmd/generate-types/main.go b/internal/cmd/generate-types/main.go
index 8ae3a52..c851062 100644
--- a/internal/cmd/generate-types/main.go
+++ b/internal/cmd/generate-types/main.go
@@ -40,6 +40,7 @@
 	chdirRoot()
 	writeSource("internal/fileinit/desc_list_gen.go", generateFileinitDescList())
 	writeSource("internal/prototype/protofile_list_gen.go", generateListTypes())
+	writeSource("internal/impl/encode_gen.go", generateImplEncode())
 	writeSource("proto/decode_gen.go", generateProtoDecode())
 	writeSource("proto/encode_gen.go", generateProtoEncode())
 	writeSource("proto/size_gen.go", generateProtoSize())
@@ -311,6 +312,7 @@
 	for _, pkg := range []string{
 		"fmt",
 		"math",
+		"reflect",
 		"sync",
 		"unicode/utf8",
 		"",
@@ -319,6 +321,7 @@
 		"google.golang.org/protobuf/internal/pragma",
 		"google.golang.org/protobuf/internal/typefmt",
 		"google.golang.org/protobuf/reflect/protoreflect",
+		"google.golang.org/protobuf/runtime/protoiface",
 	} {
 		if pkg == "" {
 			imports = append(imports, "") // blank line between stdlib and proto packages
@@ -341,7 +344,11 @@
 		src,
 	}, "\n")
 	b, err := format.Source([]byte(s))
-	check(err)
+	if err != nil {
+		// Just print the error and output the unformatted file for examination.
+		fmt.Fprintf(os.Stderr, "%v:%v\n", file, err)
+		b = []byte(s)
+	}
 
 	absFile := filepath.Join(repoRoot, file)
 	if run {
diff --git a/internal/cmd/generate-types/proto.go b/internal/cmd/generate-types/proto.go
index dbbc566..0010127 100644
--- a/internal/cmd/generate-types/proto.go
+++ b/internal/cmd/generate-types/proto.go
@@ -4,7 +4,10 @@
 
 package main
 
-import "text/template"
+import (
+	"strings"
+	"text/template"
+)
 
 type WireType string
 
@@ -27,11 +30,64 @@
 	return w == WireVarint || w == WireFixed32 || w == WireFixed64
 }
 
+func (w WireType) ConstSize() bool {
+	return w == WireFixed32 || w == WireFixed64
+}
+
+type GoType string
+
+const (
+	GoBool    = "bool"
+	GoInt32   = "int32"
+	GoUint32  = "uint32"
+	GoInt64   = "int64"
+	GoUint64  = "uint64"
+	GoFloat32 = "float32"
+	GoFloat64 = "float64"
+	GoString  = "string"
+	GoBytes   = "[]byte"
+)
+
+func (g GoType) Zero() Expr {
+	switch g {
+	case GoBool:
+		return "false"
+	case GoString:
+		return `""`
+	case GoBytes:
+		return "nil"
+	}
+	return "0"
+}
+
+// Kind is the reflect.Kind of the type.
+func (g GoType) Kind() Expr {
+	if g == "" || g == GoBytes {
+		return ""
+	}
+	return "reflect." + Expr(strings.ToUpper(string(g[:1]))+string(g[1:]))
+}
+
+// PointerMethod is the "internal/impl".pointer method used to access a pointer to this type.
+func (g GoType) PointerMethod() Expr {
+	if g == GoBytes {
+		return "Bytes"
+	}
+	return Expr(strings.ToUpper(string(g[:1])) + string(g[1:]))
+}
+
 type ProtoKind struct {
-	Name      string
-	WireType  WireType
+	Name     string
+	WireType WireType
+
+	// Conversions to/from protoreflect.Value.
 	ToValue   Expr
 	FromValue Expr
+
+	// Conversions to/from generated structures.
+	GoType     GoType
+	FromGoType Expr
+	NoPointer  bool
 }
 
 func (k ProtoKind) Expr() Expr {
@@ -40,10 +96,12 @@
 
 var ProtoKinds = []ProtoKind{
 	{
-		Name:      "Bool",
-		WireType:  WireVarint,
-		ToValue:   "wire.DecodeBool(v)",
-		FromValue: "wire.EncodeBool(v.Bool())",
+		Name:       "Bool",
+		WireType:   WireVarint,
+		ToValue:    "wire.DecodeBool(v)",
+		FromValue:  "wire.EncodeBool(v.Bool())",
+		GoType:     GoBool,
+		FromGoType: "wire.EncodeBool(v)",
 	},
 	{
 		Name:      "Enum",
@@ -52,88 +110,117 @@
 		FromValue: "uint64(v.Enum())",
 	},
 	{
-		Name:      "Int32",
-		WireType:  WireVarint,
-		ToValue:   "int32(v)",
-		FromValue: "uint64(int32(v.Int()))",
+		Name:       "Int32",
+		WireType:   WireVarint,
+		ToValue:    "int32(v)",
+		FromValue:  "uint64(int32(v.Int()))",
+		GoType:     GoInt32,
+		FromGoType: "uint64(v)",
 	},
 	{
-		Name:      "Sint32",
-		WireType:  WireVarint,
-		ToValue:   "int32(wire.DecodeZigZag(v & math.MaxUint32))",
-		FromValue: "wire.EncodeZigZag(int64(int32(v.Int())))",
+		Name:       "Sint32",
+		WireType:   WireVarint,
+		ToValue:    "int32(wire.DecodeZigZag(v & math.MaxUint32))",
+		FromValue:  "wire.EncodeZigZag(int64(int32(v.Int())))",
+		GoType:     GoInt32,
+		FromGoType: "wire.EncodeZigZag(int64(v))",
 	},
 	{
-		Name:      "Uint32",
-		WireType:  WireVarint,
-		ToValue:   "uint32(v)",
-		FromValue: "uint64(uint32(v.Uint()))",
+		Name:       "Uint32",
+		WireType:   WireVarint,
+		ToValue:    "uint32(v)",
+		FromValue:  "uint64(uint32(v.Uint()))",
+		GoType:     GoUint32,
+		FromGoType: "uint64(v)",
 	},
 	{
-		Name:      "Int64",
-		WireType:  WireVarint,
-		ToValue:   "int64(v)",
-		FromValue: "uint64(v.Int())",
+		Name:       "Int64",
+		WireType:   WireVarint,
+		ToValue:    "int64(v)",
+		FromValue:  "uint64(v.Int())",
+		GoType:     GoInt64,
+		FromGoType: "uint64(v)",
 	},
 	{
-		Name:      "Sint64",
-		WireType:  WireVarint,
-		ToValue:   "wire.DecodeZigZag(v)",
-		FromValue: "wire.EncodeZigZag(v.Int())",
+		Name:       "Sint64",
+		WireType:   WireVarint,
+		ToValue:    "wire.DecodeZigZag(v)",
+		FromValue:  "wire.EncodeZigZag(v.Int())",
+		GoType:     GoInt64,
+		FromGoType: "wire.EncodeZigZag(v)",
 	},
 	{
-		Name:      "Uint64",
-		WireType:  WireVarint,
-		ToValue:   "v",
-		FromValue: "v.Uint()",
+		Name:       "Uint64",
+		WireType:   WireVarint,
+		ToValue:    "v",
+		FromValue:  "v.Uint()",
+		GoType:     GoUint64,
+		FromGoType: "v",
 	},
 	{
-		Name:      "Sfixed32",
-		WireType:  WireFixed32,
-		ToValue:   "int32(v)",
-		FromValue: "uint32(v.Int())",
+		Name:       "Sfixed32",
+		WireType:   WireFixed32,
+		ToValue:    "int32(v)",
+		FromValue:  "uint32(v.Int())",
+		GoType:     GoInt32,
+		FromGoType: "uint32(v)",
 	},
 	{
-		Name:      "Fixed32",
-		WireType:  WireFixed32,
-		ToValue:   "uint32(v)",
-		FromValue: "uint32(v.Uint())",
+		Name:       "Fixed32",
+		WireType:   WireFixed32,
+		ToValue:    "uint32(v)",
+		FromValue:  "uint32(v.Uint())",
+		GoType:     GoUint32,
+		FromGoType: "v",
 	},
 	{
-		Name:      "Float",
-		WireType:  WireFixed32,
-		ToValue:   "math.Float32frombits(uint32(v))",
-		FromValue: "math.Float32bits(float32(v.Float()))",
+		Name:       "Float",
+		WireType:   WireFixed32,
+		ToValue:    "math.Float32frombits(uint32(v))",
+		FromValue:  "math.Float32bits(float32(v.Float()))",
+		GoType:     GoFloat32,
+		FromGoType: "math.Float32bits(v)",
 	},
 	{
-		Name:      "Sfixed64",
-		WireType:  WireFixed64,
-		ToValue:   "int64(v)",
-		FromValue: "uint64(v.Int())",
+		Name:       "Sfixed64",
+		WireType:   WireFixed64,
+		ToValue:    "int64(v)",
+		FromValue:  "uint64(v.Int())",
+		GoType:     GoInt64,
+		FromGoType: "uint64(v)",
 	},
 	{
-		Name:      "Fixed64",
-		WireType:  WireFixed64,
-		ToValue:   "v",
-		FromValue: "v.Uint()",
+		Name:       "Fixed64",
+		WireType:   WireFixed64,
+		ToValue:    "v",
+		FromValue:  "v.Uint()",
+		GoType:     GoUint64,
+		FromGoType: "v",
 	},
 	{
-		Name:      "Double",
-		WireType:  WireFixed64,
-		ToValue:   "math.Float64frombits(v)",
-		FromValue: "math.Float64bits(v.Float())",
+		Name:       "Double",
+		WireType:   WireFixed64,
+		ToValue:    "math.Float64frombits(v)",
+		FromValue:  "math.Float64bits(v.Float())",
+		GoType:     GoFloat64,
+		FromGoType: "math.Float64bits(v)",
 	},
 	{
-		Name:      "String",
-		WireType:  WireBytes,
-		ToValue:   "string(v)",
-		FromValue: "[]byte(v.String())",
+		Name:       "String",
+		WireType:   WireBytes,
+		ToValue:    "string(v)",
+		FromValue:  "[]byte(v.String())",
+		GoType:     GoString,
+		FromGoType: "[]byte(v)",
 	},
 	{
-		Name:      "Bytes",
-		WireType:  WireBytes,
-		ToValue:   "append(([]byte)(nil), v...)",
-		FromValue: "v.Bytes()",
+		Name:       "Bytes",
+		WireType:   WireBytes,
+		ToValue:    "append(([]byte)(nil), v...)",
+		FromValue:  "v.Bytes()",
+		GoType:     GoBytes,
+		FromGoType: "v",
+		NoPointer:  true,
 	},
 	{
 		Name:      "Message",
diff --git a/internal/impl/codec_extension.go b/internal/impl/codec_extension.go
new file mode 100644
index 0000000..b92932d
--- /dev/null
+++ b/internal/impl/codec_extension.go
@@ -0,0 +1,43 @@
+// Copyright 2019 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 impl
+
+import (
+	"google.golang.org/protobuf/internal/encoding/wire"
+	piface "google.golang.org/protobuf/runtime/protoiface"
+)
+
+type extensionFieldInfo struct {
+	wiretag uint64
+	tagsize int
+	funcs   ifaceCoderFuncs
+}
+
+func (mi *MessageType) extensionFieldInfo(desc *piface.ExtensionDescV1) *extensionFieldInfo {
+	// As of this time (Go 1.12, linux/amd64), an RWMutex benchmarks as faster
+	// than a sync.Map.
+	mi.extensionFieldInfosMu.RLock()
+	e, ok := mi.extensionFieldInfos[desc]
+	mi.extensionFieldInfosMu.RUnlock()
+	if ok {
+		return e
+	}
+
+	etype := extensionTypeFromDesc(desc)
+	wiretag := wire.EncodeTag(etype.Number(), wireTypes[etype.Kind()])
+	e = &extensionFieldInfo{
+		wiretag: wiretag,
+		tagsize: wire.SizeVarint(wiretag),
+		funcs:   encoderFuncsForValue(etype, etype.GoType()),
+	}
+
+	mi.extensionFieldInfosMu.Lock()
+	if mi.extensionFieldInfos == nil {
+		mi.extensionFieldInfos = make(map[*piface.ExtensionDescV1]*extensionFieldInfo)
+	}
+	mi.extensionFieldInfos[desc] = e
+	mi.extensionFieldInfosMu.Unlock()
+	return e
+}
diff --git a/internal/impl/codec_field.go b/internal/impl/codec_field.go
new file mode 100644
index 0000000..38bd392
--- /dev/null
+++ b/internal/impl/codec_field.go
@@ -0,0 +1,577 @@
+// Copyright 2019 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 impl
+
+import (
+	"fmt"
+	"reflect"
+
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+// pointerCoderFuncs is a set of pointer encoding functions.
+type pointerCoderFuncs struct {
+	size    func(p pointer, tagsize int, opts marshalOptions) int
+	marshal func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error)
+}
+
+// ifaceCoderFuncs is a set of interface{} encoding functions.
+type ifaceCoderFuncs struct {
+	size    func(ival interface{}, tagsize int, opts marshalOptions) int
+	marshal func(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error)
+}
+
+// fieldCoder returns pointer functions for a field, used for operating on
+// struct fields.
+func fieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
+	switch {
+	case fd.Cardinality() == pref.Repeated && !fd.IsPacked():
+		// Repeated fields (not packed).
+		if ft.Kind() != reflect.Slice {
+			break
+		}
+		ft := ft.Elem()
+		switch fd.Kind() {
+		case pref.BoolKind:
+			if ft.Kind() == reflect.Bool {
+				return coderBoolSlice
+			}
+		case pref.EnumKind:
+			if ft.Kind() == reflect.Int32 {
+				return coderEnumSlice
+			}
+		case pref.Int32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderInt32Slice
+			}
+		case pref.Sint32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSint32Slice
+			}
+		case pref.Uint32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderUint32Slice
+			}
+		case pref.Int64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderInt64Slice
+			}
+		case pref.Sint64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSint64Slice
+			}
+		case pref.Uint64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderUint64Slice
+			}
+		case pref.Sfixed32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSfixed32Slice
+			}
+		case pref.Fixed32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderFixed32Slice
+			}
+		case pref.FloatKind:
+			if ft.Kind() == reflect.Float32 {
+				return coderFloatSlice
+			}
+		case pref.Sfixed64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSfixed64Slice
+			}
+		case pref.Fixed64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderFixed64Slice
+			}
+		case pref.DoubleKind:
+			if ft.Kind() == reflect.Float64 {
+				return coderDoubleSlice
+			}
+		case pref.StringKind:
+			if ft.Kind() == reflect.String && fd.Syntax() == pref.Proto3 {
+				return coderStringSliceValidateUTF8
+			}
+			if ft.Kind() == reflect.String {
+				return coderStringSlice
+			}
+			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
+				return coderBytesSlice
+			}
+		case pref.BytesKind:
+			if ft.Kind() == reflect.String {
+				return coderStringSlice
+			}
+			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
+				return coderBytesSlice
+			}
+		case pref.MessageKind:
+			return makeMessageSliceFieldCoder(fd, ft)
+		case pref.GroupKind:
+			return makeGroupSliceFieldCoder(fd, ft)
+		}
+	case fd.Cardinality() == pref.Repeated && fd.IsPacked():
+		// Packed repeated fields.
+		//
+		// Only repeated fields of primitive numeric types
+		// (Varint, Fixed32, or Fixed64 wire type) can be packed.
+		if ft.Kind() != reflect.Slice {
+			break
+		}
+		ft := ft.Elem()
+		switch fd.Kind() {
+		case pref.BoolKind:
+			if ft.Kind() == reflect.Bool {
+				return coderBoolPackedSlice
+			}
+		case pref.EnumKind:
+			if ft.Kind() == reflect.Int32 {
+				return coderEnumPackedSlice
+			}
+		case pref.Int32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderInt32PackedSlice
+			}
+		case pref.Sint32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSint32PackedSlice
+			}
+		case pref.Uint32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderUint32PackedSlice
+			}
+		case pref.Int64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderInt64PackedSlice
+			}
+		case pref.Sint64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSint64PackedSlice
+			}
+		case pref.Uint64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderUint64PackedSlice
+			}
+		case pref.Sfixed32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSfixed32PackedSlice
+			}
+		case pref.Fixed32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderFixed32PackedSlice
+			}
+		case pref.FloatKind:
+			if ft.Kind() == reflect.Float32 {
+				return coderFloatPackedSlice
+			}
+		case pref.Sfixed64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSfixed64PackedSlice
+			}
+		case pref.Fixed64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderFixed64PackedSlice
+			}
+		case pref.DoubleKind:
+			if ft.Kind() == reflect.Float64 {
+				return coderDoublePackedSlice
+			}
+		}
+	case fd.Kind() == pref.MessageKind:
+		return makeMessageFieldCoder(fd, ft)
+	case fd.Kind() == pref.GroupKind:
+		return makeGroupFieldCoder(fd, ft)
+	case fd.Syntax() == pref.Proto3 && fd.ContainingOneof() == nil:
+		// Populated oneof fields always encode even if set to the zero value,
+		// which normally are not encoded in proto3.
+		switch fd.Kind() {
+		case pref.BoolKind:
+			if ft.Kind() == reflect.Bool {
+				return coderBoolNoZero
+			}
+		case pref.EnumKind:
+			if ft.Kind() == reflect.Int32 {
+				return coderEnumNoZero
+			}
+		case pref.Int32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderInt32NoZero
+			}
+		case pref.Sint32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSint32NoZero
+			}
+		case pref.Uint32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderUint32NoZero
+			}
+		case pref.Int64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderInt64NoZero
+			}
+		case pref.Sint64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSint64NoZero
+			}
+		case pref.Uint64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderUint64NoZero
+			}
+		case pref.Sfixed32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSfixed32NoZero
+			}
+		case pref.Fixed32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderFixed32NoZero
+			}
+		case pref.FloatKind:
+			if ft.Kind() == reflect.Float32 {
+				return coderFloatNoZero
+			}
+		case pref.Sfixed64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSfixed64NoZero
+			}
+		case pref.Fixed64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderFixed64NoZero
+			}
+		case pref.DoubleKind:
+			if ft.Kind() == reflect.Float64 {
+				return coderDoubleNoZero
+			}
+		case pref.StringKind:
+			if ft.Kind() == reflect.String {
+				return coderStringNoZeroValidateUTF8
+			}
+			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
+				return coderBytesNoZero
+			}
+		case pref.BytesKind:
+			if ft.Kind() == reflect.String {
+				return coderStringNoZero
+			}
+			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
+				return coderBytesNoZero
+			}
+		}
+	case ft.Kind() == reflect.Ptr:
+		ft := ft.Elem()
+		switch fd.Kind() {
+		case pref.BoolKind:
+			if ft.Kind() == reflect.Bool {
+				return coderBoolPtr
+			}
+		case pref.EnumKind:
+			if ft.Kind() == reflect.Int32 {
+				return coderEnumPtr
+			}
+		case pref.Int32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderInt32Ptr
+			}
+		case pref.Sint32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSint32Ptr
+			}
+		case pref.Uint32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderUint32Ptr
+			}
+		case pref.Int64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderInt64Ptr
+			}
+		case pref.Sint64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSint64Ptr
+			}
+		case pref.Uint64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderUint64Ptr
+			}
+		case pref.Sfixed32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSfixed32Ptr
+			}
+		case pref.Fixed32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderFixed32Ptr
+			}
+		case pref.FloatKind:
+			if ft.Kind() == reflect.Float32 {
+				return coderFloatPtr
+			}
+		case pref.Sfixed64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSfixed64Ptr
+			}
+		case pref.Fixed64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderFixed64Ptr
+			}
+		case pref.DoubleKind:
+			if ft.Kind() == reflect.Float64 {
+				return coderDoublePtr
+			}
+		case pref.StringKind:
+			if ft.Kind() == reflect.String {
+				return coderStringPtr
+			}
+		case pref.BytesKind:
+			if ft.Kind() == reflect.String {
+				return coderStringPtr
+			}
+		}
+	default:
+		switch fd.Kind() {
+		case pref.BoolKind:
+			if ft.Kind() == reflect.Bool {
+				return coderBool
+			}
+		case pref.EnumKind:
+			if ft.Kind() == reflect.Int32 {
+				return coderEnum
+			}
+		case pref.Int32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderInt32
+			}
+		case pref.Sint32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSint32
+			}
+		case pref.Uint32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderUint32
+			}
+		case pref.Int64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderInt64
+			}
+		case pref.Sint64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSint64
+			}
+		case pref.Uint64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderUint64
+			}
+		case pref.Sfixed32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSfixed32
+			}
+		case pref.Fixed32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderFixed32
+			}
+		case pref.FloatKind:
+			if ft.Kind() == reflect.Float32 {
+				return coderFloat
+			}
+		case pref.Sfixed64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSfixed64
+			}
+		case pref.Fixed64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderFixed64
+			}
+		case pref.DoubleKind:
+			if ft.Kind() == reflect.Float64 {
+				return coderDouble
+			}
+		case pref.StringKind:
+			if fd.Syntax() == pref.Proto3 && ft.Kind() == reflect.String {
+				return coderStringValidateUTF8
+			}
+			if ft.Kind() == reflect.String {
+				return coderString
+			}
+			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
+				return coderBytes
+			}
+		case pref.BytesKind:
+			if ft.Kind() == reflect.String {
+				return coderString
+			}
+			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
+				return coderBytes
+			}
+		}
+	}
+	panic(fmt.Errorf("invalid type: no encoder for %v %v %v/%v", fd.FullName(), fd.Cardinality(), fd.Kind(), ft))
+}
+
+// encoderFuncsForValue returns interface{} value functions for a field, used for
+// extension values and map encoding.
+func encoderFuncsForValue(fd pref.FieldDescriptor, ft reflect.Type) ifaceCoderFuncs {
+	switch {
+	case fd.Cardinality() == pref.Repeated && !fd.IsPacked():
+		if ft.Kind() != reflect.Ptr || ft.Elem().Kind() != reflect.Slice {
+			break
+		}
+		ft := ft.Elem().Elem()
+		switch fd.Kind() {
+		case pref.BoolKind:
+			if ft.Kind() == reflect.Bool {
+				return coderBoolSliceIface
+			}
+		case pref.EnumKind:
+			if ft.Kind() == reflect.Int32 {
+				return coderEnumSliceIface
+			}
+		case pref.Int32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderInt32SliceIface
+			}
+		case pref.Sint32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSint32SliceIface
+			}
+		case pref.Uint32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderUint32SliceIface
+			}
+		case pref.Int64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderInt64SliceIface
+			}
+		case pref.Sint64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSint64SliceIface
+			}
+		case pref.Uint64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderUint64SliceIface
+			}
+		case pref.Sfixed32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSfixed32SliceIface
+			}
+		case pref.Fixed32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderFixed32SliceIface
+			}
+		case pref.FloatKind:
+			if ft.Kind() == reflect.Float32 {
+				return coderFloatSliceIface
+			}
+		case pref.Sfixed64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSfixed64SliceIface
+			}
+		case pref.Fixed64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderFixed64SliceIface
+			}
+		case pref.DoubleKind:
+			if ft.Kind() == reflect.Float64 {
+				return coderDoubleSliceIface
+			}
+		case pref.StringKind:
+			if ft.Kind() == reflect.String {
+				return coderStringSliceIface
+			}
+			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
+				return coderBytesSliceIface
+			}
+		case pref.BytesKind:
+			if ft.Kind() == reflect.String {
+				return coderStringSliceIface
+			}
+			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
+				return coderBytesSliceIface
+			}
+		case pref.MessageKind:
+			return coderMessageSliceIface
+		case pref.GroupKind:
+			return coderGroupSliceIface
+		}
+	case fd.Cardinality() == pref.Repeated && fd.IsPacked():
+	default:
+		switch fd.Kind() {
+		case pref.BoolKind:
+			if ft.Kind() == reflect.Bool {
+				return coderBoolIface
+			}
+		case pref.EnumKind:
+			if ft.Kind() == reflect.Int32 {
+				return coderEnumIface
+			}
+		case pref.Int32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderInt32Iface
+			}
+		case pref.Sint32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSint32Iface
+			}
+		case pref.Uint32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderUint32Iface
+			}
+		case pref.Int64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderInt64Iface
+			}
+		case pref.Sint64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSint64Iface
+			}
+		case pref.Uint64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderUint64Iface
+			}
+		case pref.Sfixed32Kind:
+			if ft.Kind() == reflect.Int32 {
+				return coderSfixed32Iface
+			}
+		case pref.Fixed32Kind:
+			if ft.Kind() == reflect.Uint32 {
+				return coderFixed32Iface
+			}
+		case pref.FloatKind:
+			if ft.Kind() == reflect.Float32 {
+				return coderFloatIface
+			}
+		case pref.Sfixed64Kind:
+			if ft.Kind() == reflect.Int64 {
+				return coderSfixed64Iface
+			}
+		case pref.Fixed64Kind:
+			if ft.Kind() == reflect.Uint64 {
+				return coderFixed64Iface
+			}
+		case pref.DoubleKind:
+			if ft.Kind() == reflect.Float64 {
+				return coderDoubleIface
+			}
+		case pref.StringKind:
+			if fd.Syntax() == pref.Proto3 && ft.Kind() == reflect.String {
+				return coderStringIfaceValidateUTF8
+			}
+			if ft.Kind() == reflect.String {
+				return coderStringIface
+			}
+			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
+				return coderBytesIface
+			}
+		case pref.BytesKind:
+			if ft.Kind() == reflect.String {
+				return coderStringIface
+			}
+			if ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8 {
+				return coderBytesIface
+			}
+		case pref.MessageKind:
+			return coderMessageIface
+		case pref.GroupKind:
+			return coderGroupIface
+		}
+	}
+	panic(fmt.Errorf("invalid type: no encoder for %v %v %v/%v", fd.FullName(), fd.Cardinality(), fd.Kind(), ft))
+}
diff --git a/internal/impl/encode.go b/internal/impl/encode.go
new file mode 100644
index 0000000..c0fce6c
--- /dev/null
+++ b/internal/impl/encode.go
@@ -0,0 +1,183 @@
+// Copyright 2019 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 impl
+
+import (
+	"sort"
+	"sync/atomic"
+
+	"google.golang.org/protobuf/internal/errors"
+	proto "google.golang.org/protobuf/proto"
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+	piface "google.golang.org/protobuf/runtime/protoiface"
+)
+
+type marshalOptions uint
+
+const (
+	marshalAllowPartial marshalOptions = 1 << iota
+	marshalDeterministic
+	marshalUseCachedSize
+)
+
+func newMarshalOptions(opts piface.MarshalOptions) marshalOptions {
+	var o marshalOptions
+	if opts.AllowPartial {
+		o |= marshalAllowPartial
+	}
+	if opts.Deterministic {
+		o |= marshalDeterministic
+	}
+	if opts.UseCachedSize {
+		o |= marshalUseCachedSize
+	}
+	return o
+}
+
+func (o marshalOptions) Options() proto.MarshalOptions {
+	return proto.MarshalOptions{
+		AllowPartial:  o.AllowPartial(),
+		Deterministic: o.Deterministic(),
+		UseCachedSize: o.UseCachedSize(),
+	}
+}
+
+func (o marshalOptions) AllowPartial() bool  { return o&marshalAllowPartial != 0 }
+func (o marshalOptions) Deterministic() bool { return o&marshalDeterministic != 0 }
+func (o marshalOptions) UseCachedSize() bool { return o&marshalUseCachedSize != 0 }
+
+// size is protoreflect.Methods.Size.
+func (mi *MessageType) size(msg pref.ProtoMessage) (size int) {
+	return mi.sizePointer(pointerOfIface(msg), 0)
+}
+
+func (mi *MessageType) sizePointer(p pointer, opts marshalOptions) (size int) {
+	mi.init()
+	if p.IsNil() {
+		return 0
+	}
+	if opts.UseCachedSize() && mi.sizecacheOffset.IsValid() {
+		return int(atomic.LoadInt32(p.Apply(mi.sizecacheOffset).Int32()))
+	}
+	return mi.sizePointerSlow(p, opts)
+}
+
+func (mi *MessageType) sizePointerSlow(p pointer, opts marshalOptions) (size int) {
+	if mi.extensionOffset.IsValid() {
+		e := p.Apply(mi.extensionOffset).Extensions()
+		size += mi.sizeExtensions(e, opts)
+	}
+	for _, f := range mi.fieldsOrdered {
+		fptr := p.Apply(f.offset)
+		if f.isPointer && fptr.Elem().IsNil() {
+			continue
+		}
+		if f.funcs.size == nil {
+			continue
+		}
+		size += f.funcs.size(fptr, f.tagsize, opts)
+	}
+	if mi.unknownOffset.IsValid() {
+		u := *p.Apply(mi.unknownOffset).Bytes()
+		size += len(u)
+	}
+	if mi.sizecacheOffset.IsValid() {
+		atomic.StoreInt32(p.Apply(mi.sizecacheOffset).Int32(), int32(size))
+	}
+	return size
+}
+
+// marshalAppend is protoreflect.Methods.MarshalAppend.
+func (mi *MessageType) marshalAppend(b []byte, msg pref.ProtoMessage, opts piface.MarshalOptions) ([]byte, error) {
+	return mi.marshalAppendPointer(b, pointerOfIface(msg), newMarshalOptions(opts))
+}
+
+func (mi *MessageType) marshalAppendPointer(b []byte, p pointer, opts marshalOptions) ([]byte, error) {
+	mi.init()
+	if p.IsNil() {
+		return b, nil
+	}
+	var err error
+	var nerr errors.NonFatal
+	// The old marshaler encodes extensions at beginning.
+	if mi.extensionOffset.IsValid() {
+		e := p.Apply(mi.extensionOffset).Extensions()
+		// TODO: Special handling for MessageSet?
+		b, err = mi.appendExtensions(b, e, opts)
+		if !nerr.Merge(err) {
+			return b, err
+		}
+	}
+	for _, f := range mi.fieldsOrdered {
+		fptr := p.Apply(f.offset)
+		if f.isPointer && fptr.Elem().IsNil() {
+			continue
+		}
+		if f.funcs.marshal == nil {
+			continue
+		}
+		b, err = f.funcs.marshal(b, fptr, f.wiretag, opts)
+		if !nerr.Merge(err) {
+			return b, err
+		}
+	}
+	if mi.unknownOffset.IsValid() {
+		u := *p.Apply(mi.unknownOffset).Bytes()
+		b = append(b, u...)
+	}
+	return b, nerr.E
+}
+
+func (mi *MessageType) sizeExtensions(ext *legacyExtensionMap, opts marshalOptions) (n int) {
+	if ext == nil {
+		return 0
+	}
+	for _, e := range *ext {
+		ei := mi.extensionFieldInfo(e.Desc)
+		if ei.funcs.size == nil {
+			continue
+		}
+		n += ei.funcs.size(e.value, ei.tagsize, opts)
+	}
+	return n
+}
+
+func (mi *MessageType) appendExtensions(b []byte, ext *legacyExtensionMap, opts marshalOptions) ([]byte, error) {
+	if ext == nil {
+		return b, nil
+	}
+
+	switch len(*ext) {
+	case 0:
+		return b, nil
+	case 1:
+		// Fast-path for one extension: Don't bother sorting the keys.
+		var err error
+		for _, e := range *ext {
+			ei := mi.extensionFieldInfo(e.Desc)
+			b, err = ei.funcs.marshal(b, e.value, ei.wiretag, opts)
+		}
+		return b, err
+	default:
+		// Sort the keys to provide a deterministic encoding.
+		// Not sure this is required, but the old code does it.
+		keys := make([]int, 0, len(*ext))
+		for k := range *ext {
+			keys = append(keys, int(k))
+		}
+		sort.Ints(keys)
+		var err error
+		var nerr errors.NonFatal
+		for _, k := range keys {
+			e := (*ext)[int32(k)]
+			ei := mi.extensionFieldInfo(e.Desc)
+			b, err = ei.funcs.marshal(b, e.value, ei.wiretag, opts)
+			if !nerr.Merge(err) {
+				return b, err
+			}
+		}
+		return b, nerr.E
+	}
+}
diff --git a/internal/impl/encode_field.go b/internal/impl/encode_field.go
new file mode 100644
index 0000000..6dbbed1
--- /dev/null
+++ b/internal/impl/encode_field.go
@@ -0,0 +1,494 @@
+// Copyright 2019 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 impl
+
+import (
+	"fmt"
+	"reflect"
+	"unicode/utf8"
+
+	"google.golang.org/protobuf/internal/encoding/wire"
+	"google.golang.org/protobuf/internal/errors"
+	"google.golang.org/protobuf/proto"
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+type errInvalidUTF8 struct{}
+
+func (errInvalidUTF8) Error() string     { return "string field contains invalid UTF-8" }
+func (errInvalidUTF8) InvalidUTF8() bool { return true }
+
+func makeOneofFieldCoder(fs reflect.StructField, od pref.OneofDescriptor, structFields map[pref.FieldNumber]reflect.StructField, otypes map[pref.FieldNumber]reflect.Type) pointerCoderFuncs {
+	type oneofFieldInfo struct {
+		wiretag uint64
+		tagsize int
+		funcs   pointerCoderFuncs
+	}
+
+	oneofFieldInfos := make(map[reflect.Type]oneofFieldInfo)
+	for i, fields := 0, od.Fields(); i < fields.Len(); i++ {
+		fd := fields.Get(i)
+		ot := otypes[fd.Number()]
+		wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
+		oneofFieldInfos[ot] = oneofFieldInfo{
+			wiretag: wiretag,
+			tagsize: wire.SizeVarint(wiretag),
+			funcs:   fieldCoder(fd, ot.Field(0).Type),
+		}
+	}
+	ft := fs.Type
+	return pointerCoderFuncs{
+		size: func(p pointer, _ int, opts marshalOptions) int {
+			v := p.AsValueOf(ft).Elem()
+			if v.IsNil() {
+				return 0
+			}
+			v = v.Elem() // interface -> *struct
+			telem := v.Elem().Type()
+			info, ok := oneofFieldInfos[telem]
+			if !ok {
+				panic(fmt.Errorf("invalid oneof type %v", telem))
+			}
+			return info.funcs.size(pointerOfValue(v).Apply(zeroOffset), info.tagsize, opts)
+		},
+		marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+			v := p.AsValueOf(ft).Elem()
+			if v.IsNil() {
+				return b, nil
+			}
+			v = v.Elem() // interface -> *struct
+			telem := v.Elem().Type()
+			info, ok := oneofFieldInfos[telem]
+			if !ok {
+				panic(fmt.Errorf("invalid oneof type %v", telem))
+			}
+			return info.funcs.marshal(b, pointerOfValue(v).Apply(zeroOffset), info.wiretag, opts)
+		},
+	}
+}
+
+func makeMessageFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
+	if fi, ok := getMessageType(ft); ok {
+		return pointerCoderFuncs{
+			size: func(p pointer, tagsize int, opts marshalOptions) int {
+				return sizeMessageType(p, fi, tagsize, opts)
+			},
+			marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+				return appendMessageType(b, p, wiretag, fi, opts)
+			},
+		}
+	} else {
+		return pointerCoderFuncs{
+			size: func(p pointer, tagsize int, opts marshalOptions) int {
+				m := legacyWrapper.MessageOf(p.AsValueOf(ft).Elem().Interface()).Interface()
+				return sizeMessage(m, tagsize, opts)
+			},
+			marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+				m := legacyWrapper.MessageOf(p.AsValueOf(ft).Elem().Interface()).Interface()
+				return appendMessage(b, m, wiretag, opts)
+			},
+		}
+	}
+}
+
+func sizeMessageType(p pointer, mi *MessageType, tagsize int, opts marshalOptions) int {
+	return wire.SizeBytes(mi.sizePointer(p.Elem(), opts)) + tagsize
+}
+
+func appendMessageType(b []byte, p pointer, wiretag uint64, mi *MessageType, opts marshalOptions) ([]byte, error) {
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(mi.sizePointer(p.Elem(), opts)))
+	return mi.marshalAppendPointer(b, p.Elem(), opts)
+}
+
+func sizeMessage(m proto.Message, tagsize int, _ marshalOptions) int {
+	return wire.SizeBytes(proto.Size(m)) + tagsize
+}
+
+func appendMessage(b []byte, m proto.Message, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(proto.Size(m)))
+	return opts.Options().MarshalAppend(b, m)
+}
+
+func sizeMessageIface(ival interface{}, tagsize int, opts marshalOptions) int {
+	m := Export{}.MessageOf(ival).Interface()
+	return sizeMessage(m, tagsize, opts)
+}
+
+func appendMessageIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	m := Export{}.MessageOf(ival).Interface()
+	return appendMessage(b, m, wiretag, opts)
+}
+
+var coderMessageIface = ifaceCoderFuncs{
+	size:    sizeMessageIface,
+	marshal: appendMessageIface,
+}
+
+func makeGroupFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
+	if fi, ok := getMessageType(ft); ok {
+		return pointerCoderFuncs{
+			size: func(p pointer, tagsize int, opts marshalOptions) int {
+				return sizeGroupType(p, fi, tagsize, opts)
+			},
+			marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+				return appendGroupType(b, p, wiretag, fi, opts)
+			},
+		}
+	} else {
+		return pointerCoderFuncs{
+			size: func(p pointer, tagsize int, opts marshalOptions) int {
+				m := legacyWrapper.MessageOf(p.AsValueOf(ft).Elem().Interface()).Interface()
+				return sizeGroup(m, tagsize, opts)
+			},
+			marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+				m := legacyWrapper.MessageOf(p.AsValueOf(ft).Elem().Interface()).Interface()
+				return appendGroup(b, m, wiretag, opts)
+			},
+		}
+	}
+}
+
+func sizeGroupType(p pointer, mi *MessageType, tagsize int, opts marshalOptions) int {
+	return 2*tagsize + mi.sizePointer(p.Elem(), opts)
+}
+
+func appendGroupType(b []byte, p pointer, wiretag uint64, mi *MessageType, opts marshalOptions) ([]byte, error) {
+	b = wire.AppendVarint(b, wiretag) // start group
+	b, err := mi.marshalAppendPointer(b, p.Elem(), opts)
+	b = wire.AppendVarint(b, wiretag+1) // end group
+	return b, err
+}
+
+func sizeGroup(m proto.Message, tagsize int, _ marshalOptions) int {
+	return 2*tagsize + proto.Size(m)
+}
+
+func appendGroup(b []byte, m proto.Message, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	b = wire.AppendVarint(b, wiretag) // start group
+	b, err := opts.Options().MarshalAppend(b, m)
+	b = wire.AppendVarint(b, wiretag+1) // end group
+	return b, err
+}
+
+func sizeGroupIface(ival interface{}, tagsize int, opts marshalOptions) int {
+	m := Export{}.MessageOf(ival).Interface()
+	return sizeGroup(m, tagsize, opts)
+}
+
+func appendGroupIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	m := Export{}.MessageOf(ival).Interface()
+	return appendGroup(b, m, wiretag, opts)
+}
+
+var coderGroupIface = ifaceCoderFuncs{
+	size:    sizeGroupIface,
+	marshal: appendGroupIface,
+}
+
+func makeMessageSliceFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
+	if fi, ok := getMessageType(ft); ok {
+		return pointerCoderFuncs{
+			marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+				return appendMessageSliceInfo(b, p, wiretag, fi, opts)
+			},
+			size: func(p pointer, tagsize int, opts marshalOptions) int {
+				return sizeMessageSliceInfo(p, fi, tagsize, opts)
+			},
+		}
+	}
+	return pointerCoderFuncs{
+		size: func(p pointer, tagsize int, opts marshalOptions) int {
+			return sizeMessageSlice(p, ft, tagsize, opts)
+		},
+		marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+			return appendMessageSlice(b, p, wiretag, ft, opts)
+		},
+	}
+}
+
+func sizeMessageSliceInfo(p pointer, mi *MessageType, tagsize int, opts marshalOptions) int {
+	s := p.PointerSlice()
+	n := 0
+	for _, v := range s {
+		n += wire.SizeBytes(mi.sizePointer(v, opts)) + tagsize
+	}
+	return n
+}
+
+func appendMessageSliceInfo(b []byte, p pointer, wiretag uint64, mi *MessageType, opts marshalOptions) ([]byte, error) {
+	s := p.PointerSlice()
+	var nerr errors.NonFatal
+	var err error
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		siz := mi.sizePointer(v, opts)
+		b = wire.AppendVarint(b, uint64(siz))
+		b, err = mi.marshalAppendPointer(b, v, opts)
+		if !nerr.Merge(err) {
+			return b, err
+		}
+	}
+	return b, nerr.E
+}
+
+func sizeMessageSlice(p pointer, goType reflect.Type, tagsize int, _ marshalOptions) int {
+	s := p.PointerSlice()
+	n := 0
+	for _, v := range s {
+		m := Export{}.MessageOf(v.AsValueOf(goType.Elem()).Interface()).Interface()
+		n += wire.SizeBytes(proto.Size(m)) + tagsize
+	}
+	return n
+}
+
+func appendMessageSlice(b []byte, p pointer, wiretag uint64, goType reflect.Type, opts marshalOptions) ([]byte, error) {
+	s := p.PointerSlice()
+	var nerr errors.NonFatal
+	var err error
+	for _, v := range s {
+		m := Export{}.MessageOf(v.AsValueOf(goType.Elem()).Interface()).Interface()
+		b = wire.AppendVarint(b, wiretag)
+		siz := proto.Size(m)
+		b = wire.AppendVarint(b, uint64(siz))
+		b, err = opts.Options().MarshalAppend(b, m)
+		if !nerr.Merge(err) {
+			return b, err
+		}
+	}
+	return b, nerr.E
+}
+
+// Slices of messages
+
+func sizeMessageSliceIface(ival interface{}, tagsize int, opts marshalOptions) int {
+	p := pointerOfIface(ival)
+	return sizeMessageSlice(p, reflect.TypeOf(ival).Elem().Elem(), tagsize, opts)
+}
+
+func appendMessageSliceIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	p := pointerOfIface(ival)
+	return appendMessageSlice(b, p, wiretag, reflect.TypeOf(ival).Elem().Elem(), opts)
+}
+
+var coderMessageSliceIface = ifaceCoderFuncs{
+	size:    sizeMessageSliceIface,
+	marshal: appendMessageSliceIface,
+}
+
+func makeGroupSliceFieldCoder(fd pref.FieldDescriptor, ft reflect.Type) pointerCoderFuncs {
+	if fi, ok := getMessageType(ft); ok {
+		return pointerCoderFuncs{
+			size: func(p pointer, tagsize int, opts marshalOptions) int {
+				return sizeGroupSliceInfo(p, fi, tagsize, opts)
+			},
+			marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+				return appendGroupSliceInfo(b, p, wiretag, fi, opts)
+			},
+		}
+	}
+	return pointerCoderFuncs{
+		size: func(p pointer, tagsize int, opts marshalOptions) int {
+			return sizeGroupSlice(p, ft, tagsize, opts)
+		},
+		marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+			return appendGroupSlice(b, p, wiretag, ft, opts)
+		},
+	}
+}
+
+func sizeGroupSlice(p pointer, messageType reflect.Type, tagsize int, _ marshalOptions) int {
+	s := p.PointerSlice()
+	n := 0
+	for _, v := range s {
+		m := Export{}.MessageOf(v.AsValueOf(messageType.Elem()).Interface()).Interface()
+		n += 2*tagsize + proto.Size(m)
+	}
+	return n
+}
+
+func appendGroupSlice(b []byte, p pointer, wiretag uint64, messageType reflect.Type, opts marshalOptions) ([]byte, error) {
+	s := p.PointerSlice()
+	var nerr errors.NonFatal
+	var err error
+	for _, v := range s {
+		m := Export{}.MessageOf(v.AsValueOf(messageType.Elem()).Interface()).Interface()
+		b = wire.AppendVarint(b, wiretag) // start group
+		b, err = opts.Options().MarshalAppend(b, m)
+		if !nerr.Merge(err) {
+			return b, err
+		}
+		b = wire.AppendVarint(b, wiretag+1) // end group
+	}
+	return b, nerr.E
+}
+
+func sizeGroupSliceInfo(p pointer, mi *MessageType, tagsize int, opts marshalOptions) int {
+	s := p.PointerSlice()
+	n := 0
+	for _, v := range s {
+		n += 2*tagsize + mi.sizePointer(v, opts)
+	}
+	return n
+}
+
+func appendGroupSliceInfo(b []byte, p pointer, wiretag uint64, mi *MessageType, opts marshalOptions) ([]byte, error) {
+	s := p.PointerSlice()
+	var nerr errors.NonFatal
+	var err error
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag) // start group
+		b, err = mi.marshalAppendPointer(b, v, opts)
+		if !nerr.Merge(err) {
+			return b, err
+		}
+		b = wire.AppendVarint(b, wiretag+1) // end group
+	}
+	return b, nerr.E
+}
+
+func sizeGroupSliceIface(ival interface{}, tagsize int, opts marshalOptions) int {
+	p := pointerOfIface(ival)
+	return sizeGroupSlice(p, reflect.TypeOf(ival).Elem().Elem(), tagsize, opts)
+}
+
+func appendGroupSliceIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	p := pointerOfIface(ival)
+	return appendGroupSlice(b, p, wiretag, reflect.TypeOf(ival).Elem().Elem(), opts)
+}
+
+var coderGroupSliceIface = ifaceCoderFuncs{
+	size:    sizeGroupSliceIface,
+	marshal: appendGroupSliceIface,
+}
+
+// Enums
+
+func sizeEnumIface(ival interface{}, tagsize int, _ marshalOptions) (n int) {
+	v := reflect.ValueOf(ival).Int()
+	return wire.SizeVarint(uint64(v)) + tagsize
+}
+
+func appendEnumIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := reflect.ValueOf(ival).Int()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderEnumIface = ifaceCoderFuncs{
+	size:    sizeEnumIface,
+	marshal: appendEnumIface,
+}
+
+func sizeEnumSliceIface(ival interface{}, tagsize int, opts marshalOptions) (size int) {
+	return sizeEnumSliceReflect(reflect.ValueOf(ival).Elem(), tagsize, opts)
+}
+
+func sizeEnumSliceReflect(s reflect.Value, tagsize int, _ marshalOptions) (size int) {
+	for i, llen := 0, s.Len(); i < llen; i++ {
+		size += wire.SizeVarint(uint64(s.Index(i).Int())) + tagsize
+	}
+	return size
+}
+
+func appendEnumSliceIface(b []byte, ival interface{}, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	return appendEnumSliceReflect(b, reflect.ValueOf(ival).Elem(), wiretag, opts)
+}
+
+func appendEnumSliceReflect(b []byte, s reflect.Value, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	for i, llen := 0, s.Len(); i < llen; i++ {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, uint64(s.Index(i).Int()))
+	}
+	return b, nil
+}
+
+var coderEnumSliceIface = ifaceCoderFuncs{
+	size:    sizeEnumSliceIface,
+	marshal: appendEnumSliceIface,
+}
+
+// Strings with UTF8 validation.
+
+func appendStringValidateUTF8(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.String()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendBytes(b, []byte(v))
+	if !utf8.ValidString(v) {
+		return b, errInvalidUTF8{}
+	}
+	return b, nil
+}
+
+var coderStringValidateUTF8 = pointerCoderFuncs{
+	size:    sizeString,
+	marshal: appendStringValidateUTF8,
+}
+
+func appendStringNoZeroValidateUTF8(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.String()
+	if len(v) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendBytes(b, []byte(v))
+	if !utf8.ValidString(v) {
+		return b, errInvalidUTF8{}
+	}
+	return b, nil
+}
+
+var coderStringNoZeroValidateUTF8 = pointerCoderFuncs{
+	size:    sizeStringNoZero,
+	marshal: appendStringNoZeroValidateUTF8,
+}
+
+func sizeStringSliceValidateUTF8(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.StringSlice()
+	for _, v := range s {
+		size += tagsize + wire.SizeBytes(len([]byte(v)))
+	}
+	return size
+}
+
+func appendStringSliceValidateUTF8(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.StringSlice()
+	var err error
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendBytes(b, []byte(v))
+		if !utf8.ValidString(v) {
+			err = errInvalidUTF8{}
+		}
+	}
+	return b, err
+}
+
+var coderStringSliceValidateUTF8 = pointerCoderFuncs{
+	size:    sizeStringSliceValidateUTF8,
+	marshal: appendStringSliceValidateUTF8,
+}
+
+func sizeStringIfaceValidateUTF8(ival interface{}, tagsize int, _ marshalOptions) int {
+	v := ival.(string)
+	return tagsize + wire.SizeBytes(len([]byte(v)))
+}
+
+func appendStringIfaceValidateUTF8(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(string)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendBytes(b, []byte(v))
+	if !utf8.ValidString(v) {
+		return b, errInvalidUTF8{}
+	}
+	return b, nil
+}
+
+var coderStringIfaceValidateUTF8 = ifaceCoderFuncs{
+	size:    sizeStringIfaceValidateUTF8,
+	marshal: appendStringIfaceValidateUTF8,
+}
diff --git a/internal/impl/encode_gen.go b/internal/impl/encode_gen.go
new file mode 100644
index 0000000..6f55323
--- /dev/null
+++ b/internal/impl/encode_gen.go
@@ -0,0 +1,2420 @@
+// 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.
+
+// Code generated by generate-types. DO NOT EDIT.
+
+package impl
+
+import (
+	"math"
+
+	"google.golang.org/protobuf/internal/encoding/wire"
+	"google.golang.org/protobuf/reflect/protoreflect"
+)
+
+// sizeBool returns the size of wire encoding a bool pointer as a Bool.
+func sizeBool(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Bool()
+	return tagsize + wire.SizeVarint(wire.EncodeBool(v))
+}
+
+// appendBool wire encodes a bool pointer as a Bool.
+func appendBool(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Bool()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeBool(v))
+	return b, nil
+}
+
+var coderBool = pointerCoderFuncs{
+	size:    sizeBool,
+	marshal: appendBool,
+}
+
+// sizeBool returns the size of wire encoding a bool pointer as a Bool.
+// The zero value is not encoded.
+func sizeBoolNoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Bool()
+	if v == false {
+		return 0
+	}
+	return tagsize + wire.SizeVarint(wire.EncodeBool(v))
+}
+
+// appendBool wire encodes a bool pointer as a Bool.
+// The zero value is not encoded.
+func appendBoolNoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Bool()
+	if v == false {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeBool(v))
+	return b, nil
+}
+
+var coderBoolNoZero = pointerCoderFuncs{
+	size:    sizeBoolNoZero,
+	marshal: appendBoolNoZero,
+}
+
+// sizeBoolPtr returns the size of wire encoding a *bool pointer as a Bool.
+// It panics if the pointer is nil.
+func sizeBoolPtr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := **p.BoolPtr()
+	return tagsize + wire.SizeVarint(wire.EncodeBool(v))
+}
+
+// appendBool wire encodes a *bool pointer as a Bool.
+// It panics if the pointer is nil.
+func appendBoolPtr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.BoolPtr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeBool(v))
+	return b, nil
+}
+
+var coderBoolPtr = pointerCoderFuncs{
+	size:    sizeBoolPtr,
+	marshal: appendBoolPtr,
+}
+
+// sizeBoolSlice returns the size of wire encoding a []bool pointer as a repeated Bool.
+func sizeBoolSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.BoolSlice()
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(wire.EncodeBool(v))
+	}
+	return size
+}
+
+// appendBoolSlice encodes a []bool pointer as a repeated Bool.
+func appendBoolSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.BoolSlice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, wire.EncodeBool(v))
+	}
+	return b, nil
+}
+
+var coderBoolSlice = pointerCoderFuncs{
+	size:    sizeBoolSlice,
+	marshal: appendBoolSlice,
+}
+
+// sizeBoolPackedSlice returns the size of wire encoding a []bool pointer as a packed repeated Bool.
+func sizeBoolPackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.BoolSlice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeBool(v))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendBoolPackedSlice encodes a []bool pointer as a packed repeated Bool.
+func appendBoolPackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.BoolSlice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeBool(v))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, wire.EncodeBool(v))
+	}
+	return b, nil
+}
+
+var coderBoolPackedSlice = pointerCoderFuncs{
+	size:    sizeBoolPackedSlice,
+	marshal: appendBoolPackedSlice,
+}
+
+// sizeBoolIface returns the size of wire encoding a bool value as a Bool.
+func sizeBoolIface(ival interface{}, tagsize int, _ marshalOptions) int {
+	v := ival.(bool)
+	return tagsize + wire.SizeVarint(wire.EncodeBool(v))
+}
+
+// appendBoolIface encodes a bool value as a Bool.
+func appendBoolIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(bool)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeBool(v))
+	return b, nil
+}
+
+var coderBoolIface = ifaceCoderFuncs{
+	size:    sizeBoolIface,
+	marshal: appendBoolIface,
+}
+
+// sizeBoolSliceIface returns the size of wire encoding a []bool value as a repeated Bool.
+func sizeBoolSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]bool)
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(wire.EncodeBool(v))
+	}
+	return size
+}
+
+// appendBoolSliceIface encodes a []bool value as a repeated Bool.
+func appendBoolSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]bool)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, wire.EncodeBool(v))
+	}
+	return b, nil
+}
+
+var coderBoolSliceIface = ifaceCoderFuncs{
+	size:    sizeBoolSliceIface,
+	marshal: appendBoolSliceIface,
+}
+
+// sizeInt32 returns the size of wire encoding a int32 pointer as a Int32.
+func sizeInt32(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Int32()
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendInt32 wire encodes a int32 pointer as a Int32.
+func appendInt32(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int32()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderInt32 = pointerCoderFuncs{
+	size:    sizeInt32,
+	marshal: appendInt32,
+}
+
+// sizeInt32 returns the size of wire encoding a int32 pointer as a Int32.
+// The zero value is not encoded.
+func sizeInt32NoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Int32()
+	if v == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendInt32 wire encodes a int32 pointer as a Int32.
+// The zero value is not encoded.
+func appendInt32NoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int32()
+	if v == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderInt32NoZero = pointerCoderFuncs{
+	size:    sizeInt32NoZero,
+	marshal: appendInt32NoZero,
+}
+
+// sizeInt32Ptr returns the size of wire encoding a *int32 pointer as a Int32.
+// It panics if the pointer is nil.
+func sizeInt32Ptr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := **p.Int32Ptr()
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendInt32 wire encodes a *int32 pointer as a Int32.
+// It panics if the pointer is nil.
+func appendInt32Ptr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Int32Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderInt32Ptr = pointerCoderFuncs{
+	size:    sizeInt32Ptr,
+	marshal: appendInt32Ptr,
+}
+
+// sizeInt32Slice returns the size of wire encoding a []int32 pointer as a repeated Int32.
+func sizeInt32Slice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int32Slice()
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(uint64(v))
+	}
+	return size
+}
+
+// appendInt32Slice encodes a []int32 pointer as a repeated Int32.
+func appendInt32Slice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int32Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderInt32Slice = pointerCoderFuncs{
+	size:    sizeInt32Slice,
+	marshal: appendInt32Slice,
+}
+
+// sizeInt32PackedSlice returns the size of wire encoding a []int32 pointer as a packed repeated Int32.
+func sizeInt32PackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int32Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendInt32PackedSlice encodes a []int32 pointer as a packed repeated Int32.
+func appendInt32PackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int32Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderInt32PackedSlice = pointerCoderFuncs{
+	size:    sizeInt32PackedSlice,
+	marshal: appendInt32PackedSlice,
+}
+
+// sizeInt32Iface returns the size of wire encoding a int32 value as a Int32.
+func sizeInt32Iface(ival interface{}, tagsize int, _ marshalOptions) int {
+	v := ival.(int32)
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendInt32Iface encodes a int32 value as a Int32.
+func appendInt32Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(int32)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderInt32Iface = ifaceCoderFuncs{
+	size:    sizeInt32Iface,
+	marshal: appendInt32Iface,
+}
+
+// sizeInt32SliceIface returns the size of wire encoding a []int32 value as a repeated Int32.
+func sizeInt32SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int32)
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(uint64(v))
+	}
+	return size
+}
+
+// appendInt32SliceIface encodes a []int32 value as a repeated Int32.
+func appendInt32SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int32)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderInt32SliceIface = ifaceCoderFuncs{
+	size:    sizeInt32SliceIface,
+	marshal: appendInt32SliceIface,
+}
+
+// sizeSint32 returns the size of wire encoding a int32 pointer as a Sint32.
+func sizeSint32(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Int32()
+	return tagsize + wire.SizeVarint(wire.EncodeZigZag(int64(v)))
+}
+
+// appendSint32 wire encodes a int32 pointer as a Sint32.
+func appendSint32(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int32()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeZigZag(int64(v)))
+	return b, nil
+}
+
+var coderSint32 = pointerCoderFuncs{
+	size:    sizeSint32,
+	marshal: appendSint32,
+}
+
+// sizeSint32 returns the size of wire encoding a int32 pointer as a Sint32.
+// The zero value is not encoded.
+func sizeSint32NoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Int32()
+	if v == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeVarint(wire.EncodeZigZag(int64(v)))
+}
+
+// appendSint32 wire encodes a int32 pointer as a Sint32.
+// The zero value is not encoded.
+func appendSint32NoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int32()
+	if v == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeZigZag(int64(v)))
+	return b, nil
+}
+
+var coderSint32NoZero = pointerCoderFuncs{
+	size:    sizeSint32NoZero,
+	marshal: appendSint32NoZero,
+}
+
+// sizeSint32Ptr returns the size of wire encoding a *int32 pointer as a Sint32.
+// It panics if the pointer is nil.
+func sizeSint32Ptr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := **p.Int32Ptr()
+	return tagsize + wire.SizeVarint(wire.EncodeZigZag(int64(v)))
+}
+
+// appendSint32 wire encodes a *int32 pointer as a Sint32.
+// It panics if the pointer is nil.
+func appendSint32Ptr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Int32Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeZigZag(int64(v)))
+	return b, nil
+}
+
+var coderSint32Ptr = pointerCoderFuncs{
+	size:    sizeSint32Ptr,
+	marshal: appendSint32Ptr,
+}
+
+// sizeSint32Slice returns the size of wire encoding a []int32 pointer as a repeated Sint32.
+func sizeSint32Slice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int32Slice()
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(wire.EncodeZigZag(int64(v)))
+	}
+	return size
+}
+
+// appendSint32Slice encodes a []int32 pointer as a repeated Sint32.
+func appendSint32Slice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int32Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, wire.EncodeZigZag(int64(v)))
+	}
+	return b, nil
+}
+
+var coderSint32Slice = pointerCoderFuncs{
+	size:    sizeSint32Slice,
+	marshal: appendSint32Slice,
+}
+
+// sizeSint32PackedSlice returns the size of wire encoding a []int32 pointer as a packed repeated Sint32.
+func sizeSint32PackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int32Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeZigZag(int64(v)))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendSint32PackedSlice encodes a []int32 pointer as a packed repeated Sint32.
+func appendSint32PackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int32Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeZigZag(int64(v)))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, wire.EncodeZigZag(int64(v)))
+	}
+	return b, nil
+}
+
+var coderSint32PackedSlice = pointerCoderFuncs{
+	size:    sizeSint32PackedSlice,
+	marshal: appendSint32PackedSlice,
+}
+
+// sizeSint32Iface returns the size of wire encoding a int32 value as a Sint32.
+func sizeSint32Iface(ival interface{}, tagsize int, _ marshalOptions) int {
+	v := ival.(int32)
+	return tagsize + wire.SizeVarint(wire.EncodeZigZag(int64(v)))
+}
+
+// appendSint32Iface encodes a int32 value as a Sint32.
+func appendSint32Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(int32)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeZigZag(int64(v)))
+	return b, nil
+}
+
+var coderSint32Iface = ifaceCoderFuncs{
+	size:    sizeSint32Iface,
+	marshal: appendSint32Iface,
+}
+
+// sizeSint32SliceIface returns the size of wire encoding a []int32 value as a repeated Sint32.
+func sizeSint32SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int32)
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(wire.EncodeZigZag(int64(v)))
+	}
+	return size
+}
+
+// appendSint32SliceIface encodes a []int32 value as a repeated Sint32.
+func appendSint32SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int32)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, wire.EncodeZigZag(int64(v)))
+	}
+	return b, nil
+}
+
+var coderSint32SliceIface = ifaceCoderFuncs{
+	size:    sizeSint32SliceIface,
+	marshal: appendSint32SliceIface,
+}
+
+// sizeUint32 returns the size of wire encoding a uint32 pointer as a Uint32.
+func sizeUint32(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Uint32()
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendUint32 wire encodes a uint32 pointer as a Uint32.
+func appendUint32(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Uint32()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderUint32 = pointerCoderFuncs{
+	size:    sizeUint32,
+	marshal: appendUint32,
+}
+
+// sizeUint32 returns the size of wire encoding a uint32 pointer as a Uint32.
+// The zero value is not encoded.
+func sizeUint32NoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Uint32()
+	if v == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendUint32 wire encodes a uint32 pointer as a Uint32.
+// The zero value is not encoded.
+func appendUint32NoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Uint32()
+	if v == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderUint32NoZero = pointerCoderFuncs{
+	size:    sizeUint32NoZero,
+	marshal: appendUint32NoZero,
+}
+
+// sizeUint32Ptr returns the size of wire encoding a *uint32 pointer as a Uint32.
+// It panics if the pointer is nil.
+func sizeUint32Ptr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := **p.Uint32Ptr()
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendUint32 wire encodes a *uint32 pointer as a Uint32.
+// It panics if the pointer is nil.
+func appendUint32Ptr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Uint32Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderUint32Ptr = pointerCoderFuncs{
+	size:    sizeUint32Ptr,
+	marshal: appendUint32Ptr,
+}
+
+// sizeUint32Slice returns the size of wire encoding a []uint32 pointer as a repeated Uint32.
+func sizeUint32Slice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Uint32Slice()
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(uint64(v))
+	}
+	return size
+}
+
+// appendUint32Slice encodes a []uint32 pointer as a repeated Uint32.
+func appendUint32Slice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Uint32Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderUint32Slice = pointerCoderFuncs{
+	size:    sizeUint32Slice,
+	marshal: appendUint32Slice,
+}
+
+// sizeUint32PackedSlice returns the size of wire encoding a []uint32 pointer as a packed repeated Uint32.
+func sizeUint32PackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Uint32Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendUint32PackedSlice encodes a []uint32 pointer as a packed repeated Uint32.
+func appendUint32PackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Uint32Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderUint32PackedSlice = pointerCoderFuncs{
+	size:    sizeUint32PackedSlice,
+	marshal: appendUint32PackedSlice,
+}
+
+// sizeUint32Iface returns the size of wire encoding a uint32 value as a Uint32.
+func sizeUint32Iface(ival interface{}, tagsize int, _ marshalOptions) int {
+	v := ival.(uint32)
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendUint32Iface encodes a uint32 value as a Uint32.
+func appendUint32Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(uint32)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderUint32Iface = ifaceCoderFuncs{
+	size:    sizeUint32Iface,
+	marshal: appendUint32Iface,
+}
+
+// sizeUint32SliceIface returns the size of wire encoding a []uint32 value as a repeated Uint32.
+func sizeUint32SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]uint32)
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(uint64(v))
+	}
+	return size
+}
+
+// appendUint32SliceIface encodes a []uint32 value as a repeated Uint32.
+func appendUint32SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]uint32)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderUint32SliceIface = ifaceCoderFuncs{
+	size:    sizeUint32SliceIface,
+	marshal: appendUint32SliceIface,
+}
+
+// sizeInt64 returns the size of wire encoding a int64 pointer as a Int64.
+func sizeInt64(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Int64()
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendInt64 wire encodes a int64 pointer as a Int64.
+func appendInt64(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int64()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderInt64 = pointerCoderFuncs{
+	size:    sizeInt64,
+	marshal: appendInt64,
+}
+
+// sizeInt64 returns the size of wire encoding a int64 pointer as a Int64.
+// The zero value is not encoded.
+func sizeInt64NoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Int64()
+	if v == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendInt64 wire encodes a int64 pointer as a Int64.
+// The zero value is not encoded.
+func appendInt64NoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int64()
+	if v == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderInt64NoZero = pointerCoderFuncs{
+	size:    sizeInt64NoZero,
+	marshal: appendInt64NoZero,
+}
+
+// sizeInt64Ptr returns the size of wire encoding a *int64 pointer as a Int64.
+// It panics if the pointer is nil.
+func sizeInt64Ptr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := **p.Int64Ptr()
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendInt64 wire encodes a *int64 pointer as a Int64.
+// It panics if the pointer is nil.
+func appendInt64Ptr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Int64Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderInt64Ptr = pointerCoderFuncs{
+	size:    sizeInt64Ptr,
+	marshal: appendInt64Ptr,
+}
+
+// sizeInt64Slice returns the size of wire encoding a []int64 pointer as a repeated Int64.
+func sizeInt64Slice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int64Slice()
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(uint64(v))
+	}
+	return size
+}
+
+// appendInt64Slice encodes a []int64 pointer as a repeated Int64.
+func appendInt64Slice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int64Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderInt64Slice = pointerCoderFuncs{
+	size:    sizeInt64Slice,
+	marshal: appendInt64Slice,
+}
+
+// sizeInt64PackedSlice returns the size of wire encoding a []int64 pointer as a packed repeated Int64.
+func sizeInt64PackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int64Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendInt64PackedSlice encodes a []int64 pointer as a packed repeated Int64.
+func appendInt64PackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int64Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(uint64(v))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderInt64PackedSlice = pointerCoderFuncs{
+	size:    sizeInt64PackedSlice,
+	marshal: appendInt64PackedSlice,
+}
+
+// sizeInt64Iface returns the size of wire encoding a int64 value as a Int64.
+func sizeInt64Iface(ival interface{}, tagsize int, _ marshalOptions) int {
+	v := ival.(int64)
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+// appendInt64Iface encodes a int64 value as a Int64.
+func appendInt64Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(int64)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderInt64Iface = ifaceCoderFuncs{
+	size:    sizeInt64Iface,
+	marshal: appendInt64Iface,
+}
+
+// sizeInt64SliceIface returns the size of wire encoding a []int64 value as a repeated Int64.
+func sizeInt64SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int64)
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(uint64(v))
+	}
+	return size
+}
+
+// appendInt64SliceIface encodes a []int64 value as a repeated Int64.
+func appendInt64SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int64)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderInt64SliceIface = ifaceCoderFuncs{
+	size:    sizeInt64SliceIface,
+	marshal: appendInt64SliceIface,
+}
+
+// sizeSint64 returns the size of wire encoding a int64 pointer as a Sint64.
+func sizeSint64(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Int64()
+	return tagsize + wire.SizeVarint(wire.EncodeZigZag(v))
+}
+
+// appendSint64 wire encodes a int64 pointer as a Sint64.
+func appendSint64(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int64()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeZigZag(v))
+	return b, nil
+}
+
+var coderSint64 = pointerCoderFuncs{
+	size:    sizeSint64,
+	marshal: appendSint64,
+}
+
+// sizeSint64 returns the size of wire encoding a int64 pointer as a Sint64.
+// The zero value is not encoded.
+func sizeSint64NoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Int64()
+	if v == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeVarint(wire.EncodeZigZag(v))
+}
+
+// appendSint64 wire encodes a int64 pointer as a Sint64.
+// The zero value is not encoded.
+func appendSint64NoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int64()
+	if v == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeZigZag(v))
+	return b, nil
+}
+
+var coderSint64NoZero = pointerCoderFuncs{
+	size:    sizeSint64NoZero,
+	marshal: appendSint64NoZero,
+}
+
+// sizeSint64Ptr returns the size of wire encoding a *int64 pointer as a Sint64.
+// It panics if the pointer is nil.
+func sizeSint64Ptr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := **p.Int64Ptr()
+	return tagsize + wire.SizeVarint(wire.EncodeZigZag(v))
+}
+
+// appendSint64 wire encodes a *int64 pointer as a Sint64.
+// It panics if the pointer is nil.
+func appendSint64Ptr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Int64Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeZigZag(v))
+	return b, nil
+}
+
+var coderSint64Ptr = pointerCoderFuncs{
+	size:    sizeSint64Ptr,
+	marshal: appendSint64Ptr,
+}
+
+// sizeSint64Slice returns the size of wire encoding a []int64 pointer as a repeated Sint64.
+func sizeSint64Slice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int64Slice()
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(wire.EncodeZigZag(v))
+	}
+	return size
+}
+
+// appendSint64Slice encodes a []int64 pointer as a repeated Sint64.
+func appendSint64Slice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int64Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, wire.EncodeZigZag(v))
+	}
+	return b, nil
+}
+
+var coderSint64Slice = pointerCoderFuncs{
+	size:    sizeSint64Slice,
+	marshal: appendSint64Slice,
+}
+
+// sizeSint64PackedSlice returns the size of wire encoding a []int64 pointer as a packed repeated Sint64.
+func sizeSint64PackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int64Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeZigZag(v))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendSint64PackedSlice encodes a []int64 pointer as a packed repeated Sint64.
+func appendSint64PackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int64Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(wire.EncodeZigZag(v))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, wire.EncodeZigZag(v))
+	}
+	return b, nil
+}
+
+var coderSint64PackedSlice = pointerCoderFuncs{
+	size:    sizeSint64PackedSlice,
+	marshal: appendSint64PackedSlice,
+}
+
+// sizeSint64Iface returns the size of wire encoding a int64 value as a Sint64.
+func sizeSint64Iface(ival interface{}, tagsize int, _ marshalOptions) int {
+	v := ival.(int64)
+	return tagsize + wire.SizeVarint(wire.EncodeZigZag(v))
+}
+
+// appendSint64Iface encodes a int64 value as a Sint64.
+func appendSint64Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(int64)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, wire.EncodeZigZag(v))
+	return b, nil
+}
+
+var coderSint64Iface = ifaceCoderFuncs{
+	size:    sizeSint64Iface,
+	marshal: appendSint64Iface,
+}
+
+// sizeSint64SliceIface returns the size of wire encoding a []int64 value as a repeated Sint64.
+func sizeSint64SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int64)
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(wire.EncodeZigZag(v))
+	}
+	return size
+}
+
+// appendSint64SliceIface encodes a []int64 value as a repeated Sint64.
+func appendSint64SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int64)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, wire.EncodeZigZag(v))
+	}
+	return b, nil
+}
+
+var coderSint64SliceIface = ifaceCoderFuncs{
+	size:    sizeSint64SliceIface,
+	marshal: appendSint64SliceIface,
+}
+
+// sizeUint64 returns the size of wire encoding a uint64 pointer as a Uint64.
+func sizeUint64(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Uint64()
+	return tagsize + wire.SizeVarint(v)
+}
+
+// appendUint64 wire encodes a uint64 pointer as a Uint64.
+func appendUint64(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Uint64()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, v)
+	return b, nil
+}
+
+var coderUint64 = pointerCoderFuncs{
+	size:    sizeUint64,
+	marshal: appendUint64,
+}
+
+// sizeUint64 returns the size of wire encoding a uint64 pointer as a Uint64.
+// The zero value is not encoded.
+func sizeUint64NoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Uint64()
+	if v == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeVarint(v)
+}
+
+// appendUint64 wire encodes a uint64 pointer as a Uint64.
+// The zero value is not encoded.
+func appendUint64NoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Uint64()
+	if v == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, v)
+	return b, nil
+}
+
+var coderUint64NoZero = pointerCoderFuncs{
+	size:    sizeUint64NoZero,
+	marshal: appendUint64NoZero,
+}
+
+// sizeUint64Ptr returns the size of wire encoding a *uint64 pointer as a Uint64.
+// It panics if the pointer is nil.
+func sizeUint64Ptr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := **p.Uint64Ptr()
+	return tagsize + wire.SizeVarint(v)
+}
+
+// appendUint64 wire encodes a *uint64 pointer as a Uint64.
+// It panics if the pointer is nil.
+func appendUint64Ptr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Uint64Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, v)
+	return b, nil
+}
+
+var coderUint64Ptr = pointerCoderFuncs{
+	size:    sizeUint64Ptr,
+	marshal: appendUint64Ptr,
+}
+
+// sizeUint64Slice returns the size of wire encoding a []uint64 pointer as a repeated Uint64.
+func sizeUint64Slice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Uint64Slice()
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(v)
+	}
+	return size
+}
+
+// appendUint64Slice encodes a []uint64 pointer as a repeated Uint64.
+func appendUint64Slice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Uint64Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, v)
+	}
+	return b, nil
+}
+
+var coderUint64Slice = pointerCoderFuncs{
+	size:    sizeUint64Slice,
+	marshal: appendUint64Slice,
+}
+
+// sizeUint64PackedSlice returns the size of wire encoding a []uint64 pointer as a packed repeated Uint64.
+func sizeUint64PackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Uint64Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(v)
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendUint64PackedSlice encodes a []uint64 pointer as a packed repeated Uint64.
+func appendUint64PackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Uint64Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for _, v := range s {
+		n += wire.SizeVarint(v)
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendVarint(b, v)
+	}
+	return b, nil
+}
+
+var coderUint64PackedSlice = pointerCoderFuncs{
+	size:    sizeUint64PackedSlice,
+	marshal: appendUint64PackedSlice,
+}
+
+// sizeUint64Iface returns the size of wire encoding a uint64 value as a Uint64.
+func sizeUint64Iface(ival interface{}, tagsize int, _ marshalOptions) int {
+	v := ival.(uint64)
+	return tagsize + wire.SizeVarint(v)
+}
+
+// appendUint64Iface encodes a uint64 value as a Uint64.
+func appendUint64Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(uint64)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, v)
+	return b, nil
+}
+
+var coderUint64Iface = ifaceCoderFuncs{
+	size:    sizeUint64Iface,
+	marshal: appendUint64Iface,
+}
+
+// sizeUint64SliceIface returns the size of wire encoding a []uint64 value as a repeated Uint64.
+func sizeUint64SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]uint64)
+	for _, v := range s {
+		size += tagsize + wire.SizeVarint(v)
+	}
+	return size
+}
+
+// appendUint64SliceIface encodes a []uint64 value as a repeated Uint64.
+func appendUint64SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]uint64)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendVarint(b, v)
+	}
+	return b, nil
+}
+
+var coderUint64SliceIface = ifaceCoderFuncs{
+	size:    sizeUint64SliceIface,
+	marshal: appendUint64SliceIface,
+}
+
+// sizeSfixed32 returns the size of wire encoding a int32 pointer as a Sfixed32.
+func sizeSfixed32(p pointer, tagsize int, _ marshalOptions) (size int) {
+
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendSfixed32 wire encodes a int32 pointer as a Sfixed32.
+func appendSfixed32(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int32()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, uint32(v))
+	return b, nil
+}
+
+var coderSfixed32 = pointerCoderFuncs{
+	size:    sizeSfixed32,
+	marshal: appendSfixed32,
+}
+
+// sizeSfixed32 returns the size of wire encoding a int32 pointer as a Sfixed32.
+// The zero value is not encoded.
+func sizeSfixed32NoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Int32()
+	if v == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendSfixed32 wire encodes a int32 pointer as a Sfixed32.
+// The zero value is not encoded.
+func appendSfixed32NoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int32()
+	if v == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, uint32(v))
+	return b, nil
+}
+
+var coderSfixed32NoZero = pointerCoderFuncs{
+	size:    sizeSfixed32NoZero,
+	marshal: appendSfixed32NoZero,
+}
+
+// sizeSfixed32Ptr returns the size of wire encoding a *int32 pointer as a Sfixed32.
+// It panics if the pointer is nil.
+func sizeSfixed32Ptr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendSfixed32 wire encodes a *int32 pointer as a Sfixed32.
+// It panics if the pointer is nil.
+func appendSfixed32Ptr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Int32Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, uint32(v))
+	return b, nil
+}
+
+var coderSfixed32Ptr = pointerCoderFuncs{
+	size:    sizeSfixed32Ptr,
+	marshal: appendSfixed32Ptr,
+}
+
+// sizeSfixed32Slice returns the size of wire encoding a []int32 pointer as a repeated Sfixed32.
+func sizeSfixed32Slice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int32Slice()
+	size = len(s) * (tagsize + wire.SizeFixed32())
+	return size
+}
+
+// appendSfixed32Slice encodes a []int32 pointer as a repeated Sfixed32.
+func appendSfixed32Slice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int32Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed32(b, uint32(v))
+	}
+	return b, nil
+}
+
+var coderSfixed32Slice = pointerCoderFuncs{
+	size:    sizeSfixed32Slice,
+	marshal: appendSfixed32Slice,
+}
+
+// sizeSfixed32PackedSlice returns the size of wire encoding a []int32 pointer as a packed repeated Sfixed32.
+func sizeSfixed32PackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int32Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed32()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendSfixed32PackedSlice encodes a []int32 pointer as a packed repeated Sfixed32.
+func appendSfixed32PackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int32Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed32()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed32(b, uint32(v))
+	}
+	return b, nil
+}
+
+var coderSfixed32PackedSlice = pointerCoderFuncs{
+	size:    sizeSfixed32PackedSlice,
+	marshal: appendSfixed32PackedSlice,
+}
+
+// sizeSfixed32Iface returns the size of wire encoding a int32 value as a Sfixed32.
+func sizeSfixed32Iface(ival interface{}, tagsize int, _ marshalOptions) int {
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendSfixed32Iface encodes a int32 value as a Sfixed32.
+func appendSfixed32Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(int32)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, uint32(v))
+	return b, nil
+}
+
+var coderSfixed32Iface = ifaceCoderFuncs{
+	size:    sizeSfixed32Iface,
+	marshal: appendSfixed32Iface,
+}
+
+// sizeSfixed32SliceIface returns the size of wire encoding a []int32 value as a repeated Sfixed32.
+func sizeSfixed32SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int32)
+	size = len(s) * (tagsize + wire.SizeFixed32())
+	return size
+}
+
+// appendSfixed32SliceIface encodes a []int32 value as a repeated Sfixed32.
+func appendSfixed32SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int32)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed32(b, uint32(v))
+	}
+	return b, nil
+}
+
+var coderSfixed32SliceIface = ifaceCoderFuncs{
+	size:    sizeSfixed32SliceIface,
+	marshal: appendSfixed32SliceIface,
+}
+
+// sizeFixed32 returns the size of wire encoding a uint32 pointer as a Fixed32.
+func sizeFixed32(p pointer, tagsize int, _ marshalOptions) (size int) {
+
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendFixed32 wire encodes a uint32 pointer as a Fixed32.
+func appendFixed32(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Uint32()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, v)
+	return b, nil
+}
+
+var coderFixed32 = pointerCoderFuncs{
+	size:    sizeFixed32,
+	marshal: appendFixed32,
+}
+
+// sizeFixed32 returns the size of wire encoding a uint32 pointer as a Fixed32.
+// The zero value is not encoded.
+func sizeFixed32NoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Uint32()
+	if v == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendFixed32 wire encodes a uint32 pointer as a Fixed32.
+// The zero value is not encoded.
+func appendFixed32NoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Uint32()
+	if v == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, v)
+	return b, nil
+}
+
+var coderFixed32NoZero = pointerCoderFuncs{
+	size:    sizeFixed32NoZero,
+	marshal: appendFixed32NoZero,
+}
+
+// sizeFixed32Ptr returns the size of wire encoding a *uint32 pointer as a Fixed32.
+// It panics if the pointer is nil.
+func sizeFixed32Ptr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendFixed32 wire encodes a *uint32 pointer as a Fixed32.
+// It panics if the pointer is nil.
+func appendFixed32Ptr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Uint32Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, v)
+	return b, nil
+}
+
+var coderFixed32Ptr = pointerCoderFuncs{
+	size:    sizeFixed32Ptr,
+	marshal: appendFixed32Ptr,
+}
+
+// sizeFixed32Slice returns the size of wire encoding a []uint32 pointer as a repeated Fixed32.
+func sizeFixed32Slice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Uint32Slice()
+	size = len(s) * (tagsize + wire.SizeFixed32())
+	return size
+}
+
+// appendFixed32Slice encodes a []uint32 pointer as a repeated Fixed32.
+func appendFixed32Slice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Uint32Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed32(b, v)
+	}
+	return b, nil
+}
+
+var coderFixed32Slice = pointerCoderFuncs{
+	size:    sizeFixed32Slice,
+	marshal: appendFixed32Slice,
+}
+
+// sizeFixed32PackedSlice returns the size of wire encoding a []uint32 pointer as a packed repeated Fixed32.
+func sizeFixed32PackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Uint32Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed32()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendFixed32PackedSlice encodes a []uint32 pointer as a packed repeated Fixed32.
+func appendFixed32PackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Uint32Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed32()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed32(b, v)
+	}
+	return b, nil
+}
+
+var coderFixed32PackedSlice = pointerCoderFuncs{
+	size:    sizeFixed32PackedSlice,
+	marshal: appendFixed32PackedSlice,
+}
+
+// sizeFixed32Iface returns the size of wire encoding a uint32 value as a Fixed32.
+func sizeFixed32Iface(ival interface{}, tagsize int, _ marshalOptions) int {
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendFixed32Iface encodes a uint32 value as a Fixed32.
+func appendFixed32Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(uint32)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, v)
+	return b, nil
+}
+
+var coderFixed32Iface = ifaceCoderFuncs{
+	size:    sizeFixed32Iface,
+	marshal: appendFixed32Iface,
+}
+
+// sizeFixed32SliceIface returns the size of wire encoding a []uint32 value as a repeated Fixed32.
+func sizeFixed32SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]uint32)
+	size = len(s) * (tagsize + wire.SizeFixed32())
+	return size
+}
+
+// appendFixed32SliceIface encodes a []uint32 value as a repeated Fixed32.
+func appendFixed32SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]uint32)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed32(b, v)
+	}
+	return b, nil
+}
+
+var coderFixed32SliceIface = ifaceCoderFuncs{
+	size:    sizeFixed32SliceIface,
+	marshal: appendFixed32SliceIface,
+}
+
+// sizeFloat returns the size of wire encoding a float32 pointer as a Float.
+func sizeFloat(p pointer, tagsize int, _ marshalOptions) (size int) {
+
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendFloat wire encodes a float32 pointer as a Float.
+func appendFloat(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Float32()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, math.Float32bits(v))
+	return b, nil
+}
+
+var coderFloat = pointerCoderFuncs{
+	size:    sizeFloat,
+	marshal: appendFloat,
+}
+
+// sizeFloat returns the size of wire encoding a float32 pointer as a Float.
+// The zero value is not encoded.
+func sizeFloatNoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Float32()
+	if v == 0 && !math.Signbit(float64(v)) {
+		return 0
+	}
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendFloat wire encodes a float32 pointer as a Float.
+// The zero value is not encoded.
+func appendFloatNoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Float32()
+	if v == 0 && !math.Signbit(float64(v)) {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, math.Float32bits(v))
+	return b, nil
+}
+
+var coderFloatNoZero = pointerCoderFuncs{
+	size:    sizeFloatNoZero,
+	marshal: appendFloatNoZero,
+}
+
+// sizeFloatPtr returns the size of wire encoding a *float32 pointer as a Float.
+// It panics if the pointer is nil.
+func sizeFloatPtr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendFloat wire encodes a *float32 pointer as a Float.
+// It panics if the pointer is nil.
+func appendFloatPtr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Float32Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, math.Float32bits(v))
+	return b, nil
+}
+
+var coderFloatPtr = pointerCoderFuncs{
+	size:    sizeFloatPtr,
+	marshal: appendFloatPtr,
+}
+
+// sizeFloatSlice returns the size of wire encoding a []float32 pointer as a repeated Float.
+func sizeFloatSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Float32Slice()
+	size = len(s) * (tagsize + wire.SizeFixed32())
+	return size
+}
+
+// appendFloatSlice encodes a []float32 pointer as a repeated Float.
+func appendFloatSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Float32Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed32(b, math.Float32bits(v))
+	}
+	return b, nil
+}
+
+var coderFloatSlice = pointerCoderFuncs{
+	size:    sizeFloatSlice,
+	marshal: appendFloatSlice,
+}
+
+// sizeFloatPackedSlice returns the size of wire encoding a []float32 pointer as a packed repeated Float.
+func sizeFloatPackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Float32Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed32()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendFloatPackedSlice encodes a []float32 pointer as a packed repeated Float.
+func appendFloatPackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Float32Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed32()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed32(b, math.Float32bits(v))
+	}
+	return b, nil
+}
+
+var coderFloatPackedSlice = pointerCoderFuncs{
+	size:    sizeFloatPackedSlice,
+	marshal: appendFloatPackedSlice,
+}
+
+// sizeFloatIface returns the size of wire encoding a float32 value as a Float.
+func sizeFloatIface(ival interface{}, tagsize int, _ marshalOptions) int {
+	return tagsize + wire.SizeFixed32()
+}
+
+// appendFloatIface encodes a float32 value as a Float.
+func appendFloatIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(float32)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed32(b, math.Float32bits(v))
+	return b, nil
+}
+
+var coderFloatIface = ifaceCoderFuncs{
+	size:    sizeFloatIface,
+	marshal: appendFloatIface,
+}
+
+// sizeFloatSliceIface returns the size of wire encoding a []float32 value as a repeated Float.
+func sizeFloatSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]float32)
+	size = len(s) * (tagsize + wire.SizeFixed32())
+	return size
+}
+
+// appendFloatSliceIface encodes a []float32 value as a repeated Float.
+func appendFloatSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]float32)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed32(b, math.Float32bits(v))
+	}
+	return b, nil
+}
+
+var coderFloatSliceIface = ifaceCoderFuncs{
+	size:    sizeFloatSliceIface,
+	marshal: appendFloatSliceIface,
+}
+
+// sizeSfixed64 returns the size of wire encoding a int64 pointer as a Sfixed64.
+func sizeSfixed64(p pointer, tagsize int, _ marshalOptions) (size int) {
+
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendSfixed64 wire encodes a int64 pointer as a Sfixed64.
+func appendSfixed64(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int64()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, uint64(v))
+	return b, nil
+}
+
+var coderSfixed64 = pointerCoderFuncs{
+	size:    sizeSfixed64,
+	marshal: appendSfixed64,
+}
+
+// sizeSfixed64 returns the size of wire encoding a int64 pointer as a Sfixed64.
+// The zero value is not encoded.
+func sizeSfixed64NoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Int64()
+	if v == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendSfixed64 wire encodes a int64 pointer as a Sfixed64.
+// The zero value is not encoded.
+func appendSfixed64NoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Int64()
+	if v == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, uint64(v))
+	return b, nil
+}
+
+var coderSfixed64NoZero = pointerCoderFuncs{
+	size:    sizeSfixed64NoZero,
+	marshal: appendSfixed64NoZero,
+}
+
+// sizeSfixed64Ptr returns the size of wire encoding a *int64 pointer as a Sfixed64.
+// It panics if the pointer is nil.
+func sizeSfixed64Ptr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendSfixed64 wire encodes a *int64 pointer as a Sfixed64.
+// It panics if the pointer is nil.
+func appendSfixed64Ptr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Int64Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, uint64(v))
+	return b, nil
+}
+
+var coderSfixed64Ptr = pointerCoderFuncs{
+	size:    sizeSfixed64Ptr,
+	marshal: appendSfixed64Ptr,
+}
+
+// sizeSfixed64Slice returns the size of wire encoding a []int64 pointer as a repeated Sfixed64.
+func sizeSfixed64Slice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int64Slice()
+	size = len(s) * (tagsize + wire.SizeFixed64())
+	return size
+}
+
+// appendSfixed64Slice encodes a []int64 pointer as a repeated Sfixed64.
+func appendSfixed64Slice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int64Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed64(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderSfixed64Slice = pointerCoderFuncs{
+	size:    sizeSfixed64Slice,
+	marshal: appendSfixed64Slice,
+}
+
+// sizeSfixed64PackedSlice returns the size of wire encoding a []int64 pointer as a packed repeated Sfixed64.
+func sizeSfixed64PackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Int64Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed64()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendSfixed64PackedSlice encodes a []int64 pointer as a packed repeated Sfixed64.
+func appendSfixed64PackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Int64Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed64()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed64(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderSfixed64PackedSlice = pointerCoderFuncs{
+	size:    sizeSfixed64PackedSlice,
+	marshal: appendSfixed64PackedSlice,
+}
+
+// sizeSfixed64Iface returns the size of wire encoding a int64 value as a Sfixed64.
+func sizeSfixed64Iface(ival interface{}, tagsize int, _ marshalOptions) int {
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendSfixed64Iface encodes a int64 value as a Sfixed64.
+func appendSfixed64Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(int64)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, uint64(v))
+	return b, nil
+}
+
+var coderSfixed64Iface = ifaceCoderFuncs{
+	size:    sizeSfixed64Iface,
+	marshal: appendSfixed64Iface,
+}
+
+// sizeSfixed64SliceIface returns the size of wire encoding a []int64 value as a repeated Sfixed64.
+func sizeSfixed64SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]int64)
+	size = len(s) * (tagsize + wire.SizeFixed64())
+	return size
+}
+
+// appendSfixed64SliceIface encodes a []int64 value as a repeated Sfixed64.
+func appendSfixed64SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]int64)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed64(b, uint64(v))
+	}
+	return b, nil
+}
+
+var coderSfixed64SliceIface = ifaceCoderFuncs{
+	size:    sizeSfixed64SliceIface,
+	marshal: appendSfixed64SliceIface,
+}
+
+// sizeFixed64 returns the size of wire encoding a uint64 pointer as a Fixed64.
+func sizeFixed64(p pointer, tagsize int, _ marshalOptions) (size int) {
+
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendFixed64 wire encodes a uint64 pointer as a Fixed64.
+func appendFixed64(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Uint64()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, v)
+	return b, nil
+}
+
+var coderFixed64 = pointerCoderFuncs{
+	size:    sizeFixed64,
+	marshal: appendFixed64,
+}
+
+// sizeFixed64 returns the size of wire encoding a uint64 pointer as a Fixed64.
+// The zero value is not encoded.
+func sizeFixed64NoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Uint64()
+	if v == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendFixed64 wire encodes a uint64 pointer as a Fixed64.
+// The zero value is not encoded.
+func appendFixed64NoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Uint64()
+	if v == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, v)
+	return b, nil
+}
+
+var coderFixed64NoZero = pointerCoderFuncs{
+	size:    sizeFixed64NoZero,
+	marshal: appendFixed64NoZero,
+}
+
+// sizeFixed64Ptr returns the size of wire encoding a *uint64 pointer as a Fixed64.
+// It panics if the pointer is nil.
+func sizeFixed64Ptr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendFixed64 wire encodes a *uint64 pointer as a Fixed64.
+// It panics if the pointer is nil.
+func appendFixed64Ptr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Uint64Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, v)
+	return b, nil
+}
+
+var coderFixed64Ptr = pointerCoderFuncs{
+	size:    sizeFixed64Ptr,
+	marshal: appendFixed64Ptr,
+}
+
+// sizeFixed64Slice returns the size of wire encoding a []uint64 pointer as a repeated Fixed64.
+func sizeFixed64Slice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Uint64Slice()
+	size = len(s) * (tagsize + wire.SizeFixed64())
+	return size
+}
+
+// appendFixed64Slice encodes a []uint64 pointer as a repeated Fixed64.
+func appendFixed64Slice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Uint64Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed64(b, v)
+	}
+	return b, nil
+}
+
+var coderFixed64Slice = pointerCoderFuncs{
+	size:    sizeFixed64Slice,
+	marshal: appendFixed64Slice,
+}
+
+// sizeFixed64PackedSlice returns the size of wire encoding a []uint64 pointer as a packed repeated Fixed64.
+func sizeFixed64PackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Uint64Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed64()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendFixed64PackedSlice encodes a []uint64 pointer as a packed repeated Fixed64.
+func appendFixed64PackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Uint64Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed64()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed64(b, v)
+	}
+	return b, nil
+}
+
+var coderFixed64PackedSlice = pointerCoderFuncs{
+	size:    sizeFixed64PackedSlice,
+	marshal: appendFixed64PackedSlice,
+}
+
+// sizeFixed64Iface returns the size of wire encoding a uint64 value as a Fixed64.
+func sizeFixed64Iface(ival interface{}, tagsize int, _ marshalOptions) int {
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendFixed64Iface encodes a uint64 value as a Fixed64.
+func appendFixed64Iface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(uint64)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, v)
+	return b, nil
+}
+
+var coderFixed64Iface = ifaceCoderFuncs{
+	size:    sizeFixed64Iface,
+	marshal: appendFixed64Iface,
+}
+
+// sizeFixed64SliceIface returns the size of wire encoding a []uint64 value as a repeated Fixed64.
+func sizeFixed64SliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]uint64)
+	size = len(s) * (tagsize + wire.SizeFixed64())
+	return size
+}
+
+// appendFixed64SliceIface encodes a []uint64 value as a repeated Fixed64.
+func appendFixed64SliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]uint64)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed64(b, v)
+	}
+	return b, nil
+}
+
+var coderFixed64SliceIface = ifaceCoderFuncs{
+	size:    sizeFixed64SliceIface,
+	marshal: appendFixed64SliceIface,
+}
+
+// sizeDouble returns the size of wire encoding a float64 pointer as a Double.
+func sizeDouble(p pointer, tagsize int, _ marshalOptions) (size int) {
+
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendDouble wire encodes a float64 pointer as a Double.
+func appendDouble(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Float64()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, math.Float64bits(v))
+	return b, nil
+}
+
+var coderDouble = pointerCoderFuncs{
+	size:    sizeDouble,
+	marshal: appendDouble,
+}
+
+// sizeDouble returns the size of wire encoding a float64 pointer as a Double.
+// The zero value is not encoded.
+func sizeDoubleNoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Float64()
+	if v == 0 && !math.Signbit(float64(v)) {
+		return 0
+	}
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendDouble wire encodes a float64 pointer as a Double.
+// The zero value is not encoded.
+func appendDoubleNoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Float64()
+	if v == 0 && !math.Signbit(float64(v)) {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, math.Float64bits(v))
+	return b, nil
+}
+
+var coderDoubleNoZero = pointerCoderFuncs{
+	size:    sizeDoubleNoZero,
+	marshal: appendDoubleNoZero,
+}
+
+// sizeDoublePtr returns the size of wire encoding a *float64 pointer as a Double.
+// It panics if the pointer is nil.
+func sizeDoublePtr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendDouble wire encodes a *float64 pointer as a Double.
+// It panics if the pointer is nil.
+func appendDoublePtr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.Float64Ptr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, math.Float64bits(v))
+	return b, nil
+}
+
+var coderDoublePtr = pointerCoderFuncs{
+	size:    sizeDoublePtr,
+	marshal: appendDoublePtr,
+}
+
+// sizeDoubleSlice returns the size of wire encoding a []float64 pointer as a repeated Double.
+func sizeDoubleSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Float64Slice()
+	size = len(s) * (tagsize + wire.SizeFixed64())
+	return size
+}
+
+// appendDoubleSlice encodes a []float64 pointer as a repeated Double.
+func appendDoubleSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Float64Slice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed64(b, math.Float64bits(v))
+	}
+	return b, nil
+}
+
+var coderDoubleSlice = pointerCoderFuncs{
+	size:    sizeDoubleSlice,
+	marshal: appendDoubleSlice,
+}
+
+// sizeDoublePackedSlice returns the size of wire encoding a []float64 pointer as a packed repeated Double.
+func sizeDoublePackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.Float64Slice()
+	if len(s) == 0 {
+		return 0
+	}
+	n := len(s) * wire.SizeFixed64()
+	return tagsize + wire.SizeBytes(n)
+}
+
+// appendDoublePackedSlice encodes a []float64 pointer as a packed repeated Double.
+func appendDoublePackedSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.Float64Slice()
+	if len(s) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := len(s) * wire.SizeFixed64()
+	b = wire.AppendVarint(b, uint64(n))
+	for _, v := range s {
+		b = wire.AppendFixed64(b, math.Float64bits(v))
+	}
+	return b, nil
+}
+
+var coderDoublePackedSlice = pointerCoderFuncs{
+	size:    sizeDoublePackedSlice,
+	marshal: appendDoublePackedSlice,
+}
+
+// sizeDoubleIface returns the size of wire encoding a float64 value as a Double.
+func sizeDoubleIface(ival interface{}, tagsize int, _ marshalOptions) int {
+	return tagsize + wire.SizeFixed64()
+}
+
+// appendDoubleIface encodes a float64 value as a Double.
+func appendDoubleIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(float64)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendFixed64(b, math.Float64bits(v))
+	return b, nil
+}
+
+var coderDoubleIface = ifaceCoderFuncs{
+	size:    sizeDoubleIface,
+	marshal: appendDoubleIface,
+}
+
+// sizeDoubleSliceIface returns the size of wire encoding a []float64 value as a repeated Double.
+func sizeDoubleSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]float64)
+	size = len(s) * (tagsize + wire.SizeFixed64())
+	return size
+}
+
+// appendDoubleSliceIface encodes a []float64 value as a repeated Double.
+func appendDoubleSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]float64)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendFixed64(b, math.Float64bits(v))
+	}
+	return b, nil
+}
+
+var coderDoubleSliceIface = ifaceCoderFuncs{
+	size:    sizeDoubleSliceIface,
+	marshal: appendDoubleSliceIface,
+}
+
+// sizeString returns the size of wire encoding a string pointer as a String.
+func sizeString(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.String()
+	return tagsize + wire.SizeBytes(len([]byte(v)))
+}
+
+// appendString wire encodes a string pointer as a String.
+func appendString(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.String()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendBytes(b, []byte(v))
+	return b, nil
+}
+
+var coderString = pointerCoderFuncs{
+	size:    sizeString,
+	marshal: appendString,
+}
+
+// sizeString returns the size of wire encoding a string pointer as a String.
+// The zero value is not encoded.
+func sizeStringNoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.String()
+	if len(v) == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeBytes(len([]byte(v)))
+}
+
+// appendString wire encodes a string pointer as a String.
+// The zero value is not encoded.
+func appendStringNoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.String()
+	if len(v) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendBytes(b, []byte(v))
+	return b, nil
+}
+
+var coderStringNoZero = pointerCoderFuncs{
+	size:    sizeStringNoZero,
+	marshal: appendStringNoZero,
+}
+
+// sizeStringPtr returns the size of wire encoding a *string pointer as a String.
+// It panics if the pointer is nil.
+func sizeStringPtr(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := **p.StringPtr()
+	return tagsize + wire.SizeBytes(len([]byte(v)))
+}
+
+// appendString wire encodes a *string pointer as a String.
+// It panics if the pointer is nil.
+func appendStringPtr(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := **p.StringPtr()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendBytes(b, []byte(v))
+	return b, nil
+}
+
+var coderStringPtr = pointerCoderFuncs{
+	size:    sizeStringPtr,
+	marshal: appendStringPtr,
+}
+
+// sizeStringSlice returns the size of wire encoding a []string pointer as a repeated String.
+func sizeStringSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.StringSlice()
+	for _, v := range s {
+		size += tagsize + wire.SizeBytes(len([]byte(v)))
+	}
+	return size
+}
+
+// appendStringSlice encodes a []string pointer as a repeated String.
+func appendStringSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.StringSlice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendBytes(b, []byte(v))
+	}
+	return b, nil
+}
+
+var coderStringSlice = pointerCoderFuncs{
+	size:    sizeStringSlice,
+	marshal: appendStringSlice,
+}
+
+// sizeStringIface returns the size of wire encoding a string value as a String.
+func sizeStringIface(ival interface{}, tagsize int, _ marshalOptions) int {
+	v := ival.(string)
+	return tagsize + wire.SizeBytes(len([]byte(v)))
+}
+
+// appendStringIface encodes a string value as a String.
+func appendStringIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.(string)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendBytes(b, []byte(v))
+	return b, nil
+}
+
+var coderStringIface = ifaceCoderFuncs{
+	size:    sizeStringIface,
+	marshal: appendStringIface,
+}
+
+// sizeStringSliceIface returns the size of wire encoding a []string value as a repeated String.
+func sizeStringSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[]string)
+	for _, v := range s {
+		size += tagsize + wire.SizeBytes(len([]byte(v)))
+	}
+	return size
+}
+
+// appendStringSliceIface encodes a []string value as a repeated String.
+func appendStringSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[]string)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendBytes(b, []byte(v))
+	}
+	return b, nil
+}
+
+var coderStringSliceIface = ifaceCoderFuncs{
+	size:    sizeStringSliceIface,
+	marshal: appendStringSliceIface,
+}
+
+// sizeBytes returns the size of wire encoding a []byte pointer as a Bytes.
+func sizeBytes(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Bytes()
+	return tagsize + wire.SizeBytes(len(v))
+}
+
+// appendBytes wire encodes a []byte pointer as a Bytes.
+func appendBytes(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Bytes()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendBytes(b, v)
+	return b, nil
+}
+
+var coderBytes = pointerCoderFuncs{
+	size:    sizeBytes,
+	marshal: appendBytes,
+}
+
+// sizeBytes returns the size of wire encoding a []byte pointer as a Bytes.
+// The zero value is not encoded.
+func sizeBytesNoZero(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := *p.Bytes()
+	if len(v) == 0 {
+		return 0
+	}
+	return tagsize + wire.SizeBytes(len(v))
+}
+
+// appendBytes wire encodes a []byte pointer as a Bytes.
+// The zero value is not encoded.
+func appendBytesNoZero(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := *p.Bytes()
+	if len(v) == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendBytes(b, v)
+	return b, nil
+}
+
+var coderBytesNoZero = pointerCoderFuncs{
+	size:    sizeBytesNoZero,
+	marshal: appendBytesNoZero,
+}
+
+// sizeBytesSlice returns the size of wire encoding a [][]byte pointer as a repeated Bytes.
+func sizeBytesSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := *p.BytesSlice()
+	for _, v := range s {
+		size += tagsize + wire.SizeBytes(len(v))
+	}
+	return size
+}
+
+// appendBytesSlice encodes a [][]byte pointer as a repeated Bytes.
+func appendBytesSlice(b []byte, p pointer, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *p.BytesSlice()
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendBytes(b, v)
+	}
+	return b, nil
+}
+
+var coderBytesSlice = pointerCoderFuncs{
+	size:    sizeBytesSlice,
+	marshal: appendBytesSlice,
+}
+
+// sizeBytesIface returns the size of wire encoding a []byte value as a Bytes.
+func sizeBytesIface(ival interface{}, tagsize int, _ marshalOptions) int {
+	v := ival.([]byte)
+	return tagsize + wire.SizeBytes(len(v))
+}
+
+// appendBytesIface encodes a []byte value as a Bytes.
+func appendBytesIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	v := ival.([]byte)
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendBytes(b, v)
+	return b, nil
+}
+
+var coderBytesIface = ifaceCoderFuncs{
+	size:    sizeBytesIface,
+	marshal: appendBytesIface,
+}
+
+// sizeBytesSliceIface returns the size of wire encoding a [][]byte value as a repeated Bytes.
+func sizeBytesSliceIface(ival interface{}, tagsize int, _ marshalOptions) (size int) {
+	s := *ival.(*[][]byte)
+	for _, v := range s {
+		size += tagsize + wire.SizeBytes(len(v))
+	}
+	return size
+}
+
+// appendBytesSliceIface encodes a [][]byte value as a repeated Bytes.
+func appendBytesSliceIface(b []byte, ival interface{}, wiretag uint64, _ marshalOptions) ([]byte, error) {
+	s := *ival.(*[][]byte)
+	for _, v := range s {
+		b = wire.AppendVarint(b, wiretag)
+		b = wire.AppendBytes(b, v)
+	}
+	return b, nil
+}
+
+var coderBytesSliceIface = ifaceCoderFuncs{
+	size:    sizeBytesSliceIface,
+	marshal: appendBytesSliceIface,
+}
+
+var wireTypes = map[protoreflect.Kind]wire.Type{
+	protoreflect.BoolKind:     wire.VarintType,
+	protoreflect.EnumKind:     wire.VarintType,
+	protoreflect.Int32Kind:    wire.VarintType,
+	protoreflect.Sint32Kind:   wire.VarintType,
+	protoreflect.Uint32Kind:   wire.VarintType,
+	protoreflect.Int64Kind:    wire.VarintType,
+	protoreflect.Sint64Kind:   wire.VarintType,
+	protoreflect.Uint64Kind:   wire.VarintType,
+	protoreflect.Sfixed32Kind: wire.Fixed32Type,
+	protoreflect.Fixed32Kind:  wire.Fixed32Type,
+	protoreflect.FloatKind:    wire.Fixed32Type,
+	protoreflect.Sfixed64Kind: wire.Fixed64Type,
+	protoreflect.Fixed64Kind:  wire.Fixed64Type,
+	protoreflect.DoubleKind:   wire.Fixed64Type,
+	protoreflect.StringKind:   wire.BytesType,
+	protoreflect.BytesKind:    wire.BytesType,
+	protoreflect.MessageKind:  wire.BytesType,
+	protoreflect.GroupKind:    wire.StartGroupType,
+}
diff --git a/internal/impl/encode_map.go b/internal/impl/encode_map.go
new file mode 100644
index 0000000..38e152a
--- /dev/null
+++ b/internal/impl/encode_map.go
@@ -0,0 +1,143 @@
+// Copyright 2019 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 impl
+
+import (
+	"fmt"
+	"reflect"
+	"sort"
+
+	"google.golang.org/protobuf/internal/encoding/wire"
+	"google.golang.org/protobuf/internal/errors"
+	"google.golang.org/protobuf/proto"
+	pref "google.golang.org/protobuf/reflect/protoreflect"
+)
+
+var protoMessageType = reflect.TypeOf((*proto.Message)(nil)).Elem()
+
+func encoderFuncsForMap(fd pref.FieldDescriptor, ft reflect.Type) (funcs pointerCoderFuncs) {
+	// TODO: Consider generating specialized map coders.
+	keyField := fd.MapKey()
+	valField := fd.MapValue()
+	keyWiretag := wire.EncodeTag(1, wireTypes[keyField.Kind()])
+	valWiretag := wire.EncodeTag(2, wireTypes[valField.Kind()])
+	keyFuncs := encoderFuncsForValue(keyField, ft.Key())
+	valFuncs := encoderFuncsForValue(valField, ft.Elem())
+
+	return pointerCoderFuncs{
+		size: func(p pointer, tagsize int, opts marshalOptions) int {
+			return sizeMap(p, tagsize, ft, keyFuncs, valFuncs, opts)
+		},
+		marshal: func(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+			return appendMap(b, p, wiretag, keyWiretag, valWiretag, ft, keyFuncs, valFuncs, opts)
+		},
+	}
+}
+
+const (
+	mapKeyTagSize = 1 // field 1, tag size 1.
+	mapValTagSize = 1 // field 2, tag size 2.
+)
+
+func sizeMap(p pointer, tagsize int, goType reflect.Type, keyFuncs, valFuncs ifaceCoderFuncs, opts marshalOptions) int {
+	m := p.AsValueOf(goType).Elem()
+	n := 0
+	if m.Len() == 0 {
+		return 0
+	}
+	iter := mapRange(m)
+	for iter.Next() {
+		ki := iter.Key().Interface()
+		vi := iter.Value().Interface()
+		size := keyFuncs.size(ki, mapKeyTagSize, opts) + valFuncs.size(vi, mapValTagSize, opts)
+		n += wire.SizeBytes(size) + tagsize
+	}
+	return n
+}
+
+func appendMap(b []byte, p pointer, wiretag, keyWiretag, valWiretag uint64, goType reflect.Type, keyFuncs, valFuncs ifaceCoderFuncs, opts marshalOptions) ([]byte, error) {
+	m := p.AsValueOf(goType).Elem()
+	var nerr errors.NonFatal
+	var err error
+
+	if m.Len() == 0 {
+		return b, nil
+	}
+
+	if opts.Deterministic() {
+		keys := m.MapKeys()
+		sort.Sort(mapKeys(keys))
+		for _, k := range keys {
+			b, err = appendMapElement(b, k, m.MapIndex(k), wiretag, keyWiretag, valWiretag, keyFuncs, valFuncs, opts)
+			if !nerr.Merge(err) {
+				return b, err
+			}
+		}
+		return b, nerr.E
+	}
+
+	iter := mapRange(m)
+	for iter.Next() {
+		b, err = appendMapElement(b, iter.Key(), iter.Value(), wiretag, keyWiretag, valWiretag, keyFuncs, valFuncs, opts)
+		if !nerr.Merge(err) {
+			return b, err
+		}
+	}
+	return b, nerr.E
+}
+
+func appendMapElement(b []byte, key, value reflect.Value, wiretag, keyWiretag, valWiretag uint64, keyFuncs, valFuncs ifaceCoderFuncs, opts marshalOptions) ([]byte, error) {
+	ki := key.Interface()
+	vi := value.Interface()
+	b = wire.AppendVarint(b, wiretag)
+	size := keyFuncs.size(ki, mapKeyTagSize, opts) + valFuncs.size(vi, mapValTagSize, opts)
+	b = wire.AppendVarint(b, uint64(size))
+	var nerr errors.NonFatal
+	b, err := keyFuncs.marshal(b, ki, keyWiretag, opts)
+	if !nerr.Merge(err) {
+		return b, err
+	}
+	b, err = valFuncs.marshal(b, vi, valWiretag, opts)
+	if !nerr.Merge(err) {
+		return b, err
+	}
+	return b, nerr.E
+}
+
+// mapKeys returns a sort.Interface to be used for sorting the map keys.
+// Map fields may have key types of non-float scalars, strings and enums.
+func mapKeys(vs []reflect.Value) sort.Interface {
+	s := mapKeySorter{vs: vs}
+
+	// Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps.
+	if len(vs) == 0 {
+		return s
+	}
+	switch vs[0].Kind() {
+	case reflect.Int32, reflect.Int64:
+		s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() }
+	case reflect.Uint32, reflect.Uint64:
+		s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() }
+	case reflect.Bool:
+		s.less = func(a, b reflect.Value) bool { return !a.Bool() && b.Bool() } // false < true
+	case reflect.String:
+		s.less = func(a, b reflect.Value) bool { return a.String() < b.String() }
+	default:
+		panic(fmt.Sprintf("unsupported map key type: %v", vs[0].Kind()))
+	}
+
+	return s
+}
+
+type mapKeySorter struct {
+	vs   []reflect.Value
+	less func(a, b reflect.Value) bool
+}
+
+func (s mapKeySorter) Len() int      { return len(s.vs) }
+func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] }
+func (s mapKeySorter) Less(i, j int) bool {
+	return s.less(s.vs[i], s.vs[j])
+}
diff --git a/internal/impl/encode_map_go111.go b/internal/impl/encode_map_go111.go
new file mode 100644
index 0000000..2706bb6
--- /dev/null
+++ b/internal/impl/encode_map_go111.go
@@ -0,0 +1,37 @@
+// Copyright 2019 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.
+
+// +build !go1.12
+
+package impl
+
+import "reflect"
+
+type mapIter struct {
+	v    reflect.Value
+	keys []reflect.Value
+}
+
+// mapRange provides a less-efficient equivalent to
+// the Go 1.12 reflect.Value.MapRange method.
+func mapRange(v reflect.Value) *mapIter {
+	return &mapIter{v: v}
+}
+
+func (i *mapIter) Next() bool {
+	if i.keys == nil {
+		i.keys = i.v.MapKeys()
+	} else {
+		i.keys = i.keys[1:]
+	}
+	return len(i.keys) > 0
+}
+
+func (i *mapIter) Key() reflect.Value {
+	return i.keys[0]
+}
+
+func (i *mapIter) Value() reflect.Value {
+	return i.v.MapIndex(i.keys[0])
+}
diff --git a/internal/impl/encode_map_go112.go b/internal/impl/encode_map_go112.go
new file mode 100644
index 0000000..1533ef6
--- /dev/null
+++ b/internal/impl/encode_map_go112.go
@@ -0,0 +1,11 @@
+// Copyright 2019 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.
+
+// +build go1.12
+
+package impl
+
+import "reflect"
+
+func mapRange(v reflect.Value) *reflect.MapIter { return v.MapRange() }
diff --git a/internal/impl/encode_reflect.go b/internal/impl/encode_reflect.go
new file mode 100644
index 0000000..6e172d9
--- /dev/null
+++ b/internal/impl/encode_reflect.go
@@ -0,0 +1,94 @@
+// Copyright 2019 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.
+
+// +build purego appengine
+
+package impl
+
+import (
+	"google.golang.org/protobuf/internal/encoding/wire"
+)
+
+func sizeEnum(p pointer, tagsize int, _ marshalOptions) (size int) {
+	v := p.v.Elem().Int()
+	return tagsize + wire.SizeVarint(uint64(v))
+}
+
+func appendEnum(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	v := p.v.Elem().Int()
+	b = wire.AppendVarint(b, wiretag)
+	b = wire.AppendVarint(b, uint64(v))
+	return b, nil
+}
+
+var coderEnum = pointerCoderFuncs{sizeEnum, appendEnum}
+
+func sizeEnumNoZero(p pointer, tagsize int, opts marshalOptions) (size int) {
+	if p.v.Elem().Int() == 0 {
+		return 0
+	}
+	return sizeEnum(p, tagsize, opts)
+}
+
+func appendEnumNoZero(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	if p.v.Elem().Int() == 0 {
+		return b, nil
+	}
+	return appendEnum(b, p, wiretag, opts)
+}
+
+var coderEnumNoZero = pointerCoderFuncs{sizeEnumNoZero, appendEnumNoZero}
+
+func sizeEnumPtr(p pointer, tagsize int, opts marshalOptions) (size int) {
+	return sizeEnum(pointer{p.v.Elem()}, tagsize, opts)
+}
+
+func appendEnumPtr(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	return appendEnum(b, pointer{p.v.Elem()}, wiretag, opts)
+}
+
+var coderEnumPtr = pointerCoderFuncs{sizeEnumPtr, appendEnumPtr}
+
+func sizeEnumSlice(p pointer, tagsize int, opts marshalOptions) (size int) {
+	return sizeEnumSliceReflect(p.v.Elem(), tagsize, opts)
+}
+
+func appendEnumSlice(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	return appendEnumSliceReflect(b, p.v.Elem(), wiretag, opts)
+}
+
+var coderEnumSlice = pointerCoderFuncs{sizeEnumSlice, appendEnumSlice}
+
+func sizeEnumPackedSlice(p pointer, tagsize int, _ marshalOptions) (size int) {
+	s := p.v.Elem()
+	slen := s.Len()
+	if slen == 0 {
+		return 0
+	}
+	n := 0
+	for i := 0; i < slen; i++ {
+		n += wire.SizeVarint(uint64(s.Index(i).Int()))
+	}
+	return tagsize + wire.SizeBytes(n)
+}
+
+func appendEnumPackedSlice(b []byte, p pointer, wiretag uint64, opts marshalOptions) ([]byte, error) {
+	s := p.v.Elem()
+	slen := s.Len()
+	if slen == 0 {
+		return b, nil
+	}
+	b = wire.AppendVarint(b, wiretag)
+	n := 0
+	for i := 0; i < slen; i++ {
+		n += wire.SizeVarint(uint64(s.Index(i).Int()))
+	}
+	b = wire.AppendVarint(b, uint64(n))
+	for i := 0; i < slen; i++ {
+		b = wire.AppendVarint(b, uint64(s.Index(i).Int()))
+	}
+	return b, nil
+}
+
+var coderEnumPackedSlice = pointerCoderFuncs{sizeEnumPackedSlice, appendEnumPackedSlice}
diff --git a/internal/impl/encode_unsafe.go b/internal/impl/encode_unsafe.go
new file mode 100644
index 0000000..e118af1
--- /dev/null
+++ b/internal/impl/encode_unsafe.go
@@ -0,0 +1,17 @@
+// Copyright 2019 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.
+
+// +build !purego,!appengine
+
+package impl
+
+// When using unsafe pointers, we can just treat enum values as int32s.
+
+var (
+	coderEnumNoZero      = coderInt32NoZero
+	coderEnum            = coderInt32
+	coderEnumPtr         = coderInt32Ptr
+	coderEnumSlice       = coderInt32Slice
+	coderEnumPackedSlice = coderInt32PackedSlice
+)
diff --git a/internal/impl/message.go b/internal/impl/message.go
index 96efec9..1c6ab9b 100644
--- a/internal/impl/message.go
+++ b/internal/impl/message.go
@@ -7,9 +7,11 @@
 import (
 	"fmt"
 	"reflect"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
+	"sync/atomic"
 
 	pvalue "google.golang.org/protobuf/internal/value"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
@@ -28,29 +30,102 @@
 	// Once set, this field must never be mutated.
 	PBType pref.MessageType
 
-	once sync.Once // protects all unexported fields
+	initMu   sync.Mutex // protects all unexported fields
+	initDone uint32
 
-	// TODO: Split fields into dense and sparse maps similar to the current
-	// table-driven implementation in v1?
-	fields map[pref.FieldNumber]*fieldInfo
+	// Keep a separate slice of fields for efficient field encoding in tag order
+	// and because iterating over a slice is substantially faster than a map.
+	fields        map[pref.FieldNumber]*fieldInfo
+	fieldsOrdered []*fieldInfo
+
 	oneofs map[pref.Name]*oneofInfo
 
 	unknownFields   func(*messageDataType) pref.UnknownFields
 	extensionFields func(*messageDataType) pref.KnownFields
+	methods         piface.Methods
+
+	extensionOffset       offset
+	sizecacheOffset       offset
+	unknownOffset         offset
+	extensionFieldInfosMu sync.RWMutex
+	extensionFieldInfos   map[*piface.ExtensionDescV1]*extensionFieldInfo
+}
+
+var prefMessageType = reflect.TypeOf((*pref.Message)(nil)).Elem()
+
+// getMessageType returns the MessageType (if any) for a type.
+//
+// We find the MessageType by calling the ProtoReflect method on the type's
+// zero value and looking at the returned type to see if it is a
+// messageReflectWrapper. Note that the MessageType may still be uninitialized
+// at this point.
+func getMessageType(mt reflect.Type) (mi *MessageType, ok bool) {
+	method, ok := mt.MethodByName("ProtoReflect")
+	if !ok {
+		return nil, false
+	}
+	if method.Type.NumIn() != 1 || method.Type.NumOut() != 1 || method.Type.Out(0) != prefMessageType {
+		return nil, false
+	}
+	ret := reflect.Zero(mt).Method(method.Index).Call(nil)
+	m, ok := ret[0].Elem().Interface().(*messageReflectWrapper)
+	if !ok {
+		return nil, ok
+	}
+	return m.mi, true
 }
 
 func (mi *MessageType) init() {
-	mi.once.Do(func() {
-		t := mi.GoType
-		if t.Kind() != reflect.Ptr && t.Elem().Kind() != reflect.Struct {
-			panic(fmt.Sprintf("got %v, want *struct kind", t))
-		}
+	// This function is called in the hot path. Inline the sync.Once
+	// logic, since allocating a closure for Once.Do is expensive.
+	// Keep init small to ensure that it can be inlined.
+	if atomic.LoadUint32(&mi.initDone) == 1 {
+		return
+	}
+	mi.initOnce()
+}
 
-		si := mi.makeStructInfo(t.Elem())
-		mi.makeKnownFieldsFunc(si)
-		mi.makeUnknownFieldsFunc(t.Elem())
-		mi.makeExtensionFieldsFunc(t.Elem())
-	})
+func (mi *MessageType) initOnce() {
+	mi.initMu.Lock()
+	defer mi.initMu.Unlock()
+	if mi.initDone == 1 {
+		return
+	}
+
+	t := mi.GoType
+	if t.Kind() != reflect.Ptr && t.Elem().Kind() != reflect.Struct {
+		panic(fmt.Sprintf("got %v, want *struct kind", t))
+	}
+
+	si := mi.makeStructInfo(t.Elem())
+	mi.makeKnownFieldsFunc(si)
+	mi.makeUnknownFieldsFunc(t.Elem())
+	mi.makeExtensionFieldsFunc(t.Elem())
+	mi.makeMethods(t.Elem())
+
+	atomic.StoreUint32(&mi.initDone, 1)
+}
+
+var sizecacheType = reflect.TypeOf(int32(0))
+
+func (mi *MessageType) makeMethods(t reflect.Type) {
+	mi.extensionOffset = invalidOffset
+	if fx, _ := t.FieldByName("XXX_InternalExtensions"); fx.Type == extType {
+		mi.extensionOffset = offsetOf(fx)
+	} else if fx, _ = t.FieldByName("XXX_extensions"); fx.Type == extType {
+		mi.extensionOffset = offsetOf(fx)
+	}
+	mi.sizecacheOffset = invalidOffset
+	if fx, _ := t.FieldByName("XXX_sizecache"); fx.Type == sizecacheType {
+		mi.sizecacheOffset = offsetOf(fx)
+	}
+	mi.unknownOffset = invalidOffset
+	if fx, _ := t.FieldByName("XXX_unrecognized"); fx.Type == bytesType {
+		mi.unknownOffset = offsetOf(fx)
+	}
+	mi.methods.Flags = piface.MethodFlagDeterministicMarshal
+	mi.methods.MarshalAppend = mi.marshalAppend
+	mi.methods.Size = mi.size
 }
 
 type structInfo struct {
@@ -113,6 +188,7 @@
 // any discrepancies.
 func (mi *MessageType) makeKnownFieldsFunc(si structInfo) {
 	mi.fields = map[pref.FieldNumber]*fieldInfo{}
+	mi.fieldsOrdered = make([]*fieldInfo, 0, mi.PBType.Fields().Len())
 	for i := 0; i < mi.PBType.Descriptor().Fields().Len(); i++ {
 		fd := mi.PBType.Descriptor().Fields().Get(i)
 		fs := si.fieldsByNumber[fd.Number()]
@@ -120,6 +196,16 @@
 		switch {
 		case fd.ContainingOneof() != nil:
 			fi = fieldInfoForOneof(fd, si.oneofsByName[fd.ContainingOneof().Name()], si.oneofWrappersByNumber[fd.Number()])
+			// There is one fieldInfo for each proto message field, but only one struct
+			// field for all message fields in a oneof. We install the encoder functions
+			// on the fieldInfo for the first field in the oneof.
+			//
+			// A slightly simpler approach would be to have each fieldInfo's encoder
+			// handle the case where that field is set, but this would require more
+			// checks  against the current oneof type than a single map lookup.
+			if fd.ContainingOneof().Fields().Get(0).Name() == fd.Name() {
+				fi.funcs = makeOneofFieldCoder(si.oneofsByName[fd.ContainingOneof().Name()], fd.ContainingOneof(), si.fieldsByNumber, si.oneofWrappersByNumber)
+			}
 		case fd.IsMap():
 			fi = fieldInfoForMap(fd, fs)
 		case fd.IsList():
@@ -129,8 +215,13 @@
 		default:
 			fi = fieldInfoForScalar(fd, fs)
 		}
+		fi.num = fd.Number()
 		mi.fields[fd.Number()] = &fi
+		mi.fieldsOrdered = append(mi.fieldsOrdered, &fi)
 	}
+	sort.Slice(mi.fieldsOrdered, func(i, j int) bool {
+		return mi.fieldsOrdered[i].num < mi.fieldsOrdered[j].num
+	})
 
 	mi.oneofs = map[pref.Name]*oneofInfo{}
 	for i := 0; i < mi.PBType.Descriptor().Oneofs().Len(); i++ {
@@ -164,7 +255,8 @@
 }
 
 func (mi *MessageType) Methods() *piface.Methods {
-	return nil
+	mi.init()
+	return &mi.methods
 }
 
 func (mi *MessageType) dataTypeOf(p interface{}) *messageDataType {
@@ -230,7 +322,6 @@
 func (m *messageReflectWrapper) ProtoUnwrap() interface{} {
 	return m.p.AsIfaceOf(m.mi.GoType.Elem())
 }
-func (m *messageReflectWrapper) ProtoMutable() {}
 
 var _ pvalue.Unwrapper = (*messageReflectWrapper)(nil)
 
@@ -240,11 +331,23 @@
 	return (*messageReflectWrapper)(m)
 }
 func (m *messageIfaceWrapper) XXX_Methods() *piface.Methods {
-	return m.mi.Methods()
+	// TODO: Consider not recreating this on every call.
+	m.mi.init()
+	return &piface.Methods{
+		Flags:         piface.MethodFlagDeterministicMarshal,
+		MarshalAppend: m.marshalAppend,
+		Size:          m.size,
+	}
 }
 func (m *messageIfaceWrapper) ProtoUnwrap() interface{} {
 	return m.p.AsIfaceOf(m.mi.GoType.Elem())
 }
+func (m *messageIfaceWrapper) marshalAppend(b []byte, _ pref.ProtoMessage, opts piface.MarshalOptions) ([]byte, error) {
+	return m.mi.marshalAppendPointer(b, m.p, newMarshalOptions(opts))
+}
+func (m *messageIfaceWrapper) size(msg pref.ProtoMessage) (size int) {
+	return m.mi.sizePointer(m.p, 0)
+}
 
 type knownFields messageDataType
 
diff --git a/internal/impl/message_field.go b/internal/impl/message_field.go
index 356ec78..72f4523 100644
--- a/internal/impl/message_field.go
+++ b/internal/impl/message_field.go
@@ -9,18 +9,26 @@
 	"math"
 	"reflect"
 
+	"google.golang.org/protobuf/internal/encoding/wire"
 	pvalue "google.golang.org/protobuf/internal/value"
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 )
 
 type fieldInfo struct {
-	// TODO: specialize marshal and unmarshal functions?
-
+	// These fields are used for protobuf reflection support.
 	has        func(pointer) bool
 	get        func(pointer) pref.Value
 	set        func(pointer, pref.Value)
 	clear      func(pointer)
 	newMessage func() pref.Message
+
+	// These fields are used for fast-path functions.
+	funcs     pointerCoderFuncs // fast-path per-field functions
+	num       pref.FieldNumber  // field number
+	offset    offset            // struct field offset
+	wiretag   uint64            // field tag (number + wire type)
+	tagsize   int               // size of the varint-encoded tag
+	isPointer bool              // true if IsNil may be called on the struct field
 }
 
 func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, ot reflect.Type) fieldInfo {
@@ -82,6 +90,8 @@
 			// This is only valid for messages and panics for other kinds.
 			return conv.MessageType.New()
 		},
+		offset:    fieldOffset,
+		isPointer: true,
 	}
 }
 
@@ -92,6 +102,7 @@
 	}
 	keyConv := pvalue.NewLegacyConverter(ft.Key(), fd.MapKey().Kind(), legacyWrapper)
 	valConv := pvalue.NewLegacyConverter(ft.Elem(), fd.MapValue().Kind(), legacyWrapper)
+	wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
 	fieldOffset := offsetOf(fs)
 	// TODO: Implement unsafe fast path?
 	return fieldInfo{
@@ -118,6 +129,11 @@
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 			rv.Set(reflect.Zero(rv.Type()))
 		},
+		funcs:     encoderFuncsForMap(fd, ft),
+		offset:    fieldOffset,
+		wiretag:   wiretag,
+		tagsize:   wire.SizeVarint(wiretag),
+		isPointer: true,
 	}
 }
 
@@ -127,6 +143,12 @@
 		panic(fmt.Sprintf("invalid type: got %v, want slice kind", ft))
 	}
 	conv := pvalue.NewLegacyConverter(ft.Elem(), fd.Kind(), legacyWrapper)
+	var wiretag uint64
+	if !fd.IsPacked() {
+		wiretag = wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
+	} else {
+		wiretag = wire.EncodeTag(fd.Number(), wire.BytesType)
+	}
 	fieldOffset := offsetOf(fs)
 	// TODO: Implement unsafe fast path?
 	return fieldInfo{
@@ -153,6 +175,11 @@
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 			rv.Set(reflect.Zero(rv.Type()))
 		},
+		funcs:     fieldCoder(fd, ft),
+		offset:    fieldOffset,
+		wiretag:   wiretag,
+		tagsize:   wire.SizeVarint(wiretag),
+		isPointer: true,
 	}
 }
 
@@ -160,6 +187,7 @@
 
 func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField) fieldInfo {
 	ft := fs.Type
+	funcs := fieldCoder(fd, ft)
 	nullable := fd.Syntax() == pref.Proto2
 	if nullable {
 		if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
@@ -171,6 +199,7 @@
 	}
 	conv := pvalue.NewLegacyConverter(ft, fd.Kind(), legacyWrapper)
 	fieldOffset := offsetOf(fs)
+	wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
 	// TODO: Implement unsafe fast path?
 	return fieldInfo{
 		has: func(p pointer) bool {
@@ -228,6 +257,11 @@
 			rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
 			rv.Set(reflect.Zero(rv.Type()))
 		},
+		funcs:     funcs,
+		offset:    fieldOffset,
+		isPointer: nullable,
+		wiretag:   wiretag,
+		tagsize:   wire.SizeVarint(wiretag),
 	}
 }
 
@@ -236,6 +270,7 @@
 	conv := pvalue.NewLegacyConverter(ft, fd.Kind(), legacyWrapper)
 	fieldOffset := offsetOf(fs)
 	// TODO: Implement unsafe fast path?
+	wiretag := wire.EncodeTag(fd.Number(), wireTypes[fd.Kind()])
 	return fieldInfo{
 		has: func(p pointer) bool {
 			if p.IsNil() {
@@ -268,6 +303,11 @@
 		newMessage: func() pref.Message {
 			return conv.MessageType.New()
 		},
+		funcs:     fieldCoder(fd, ft),
+		offset:    fieldOffset,
+		isPointer: true,
+		wiretag:   wiretag,
+		tagsize:   wire.SizeVarint(wiretag),
 	}
 }
 
diff --git a/internal/impl/pointer_reflect.go b/internal/impl/pointer_reflect.go
index 72b782c..b851b1b 100644
--- a/internal/impl/pointer_reflect.go
+++ b/internal/impl/pointer_reflect.go
@@ -23,6 +23,15 @@
 	return f.Index
 }
 
+// IsValid reports whether the offset is valid.
+func (f offset) IsValid() bool { return f != nil }
+
+// invalidOffset is an invalid field offset.
+var invalidOffset = offset(nil)
+
+// zeroOffset is a noop when calling pointer.Apply.
+var zeroOffset = offset([]int{0})
+
 // pointer is an abstract representation of a pointer to a struct or field.
 type pointer struct{ v reflect.Value }
 
@@ -62,3 +71,52 @@
 func (p pointer) AsIfaceOf(t reflect.Type) interface{} {
 	return p.AsValueOf(t).Interface()
 }
+
+func (p pointer) Bool() *bool              { return p.v.Interface().(*bool) }
+func (p pointer) BoolPtr() **bool          { return p.v.Interface().(**bool) }
+func (p pointer) BoolSlice() *[]bool       { return p.v.Interface().(*[]bool) }
+func (p pointer) Int32() *int32            { return p.v.Interface().(*int32) }
+func (p pointer) Int32Ptr() **int32        { return p.v.Interface().(**int32) }
+func (p pointer) Int32Slice() *[]int32     { return p.v.Interface().(*[]int32) }
+func (p pointer) Int64() *int64            { return p.v.Interface().(*int64) }
+func (p pointer) Int64Ptr() **int64        { return p.v.Interface().(**int64) }
+func (p pointer) Int64Slice() *[]int64     { return p.v.Interface().(*[]int64) }
+func (p pointer) Uint32() *uint32          { return p.v.Interface().(*uint32) }
+func (p pointer) Uint32Ptr() **uint32      { return p.v.Interface().(**uint32) }
+func (p pointer) Uint32Slice() *[]uint32   { return p.v.Interface().(*[]uint32) }
+func (p pointer) Uint64() *uint64          { return p.v.Interface().(*uint64) }
+func (p pointer) Uint64Ptr() **uint64      { return p.v.Interface().(**uint64) }
+func (p pointer) Uint64Slice() *[]uint64   { return p.v.Interface().(*[]uint64) }
+func (p pointer) Float32() *float32        { return p.v.Interface().(*float32) }
+func (p pointer) Float32Ptr() **float32    { return p.v.Interface().(**float32) }
+func (p pointer) Float32Slice() *[]float32 { return p.v.Interface().(*[]float32) }
+func (p pointer) Float64() *float64        { return p.v.Interface().(*float64) }
+func (p pointer) Float64Ptr() **float64    { return p.v.Interface().(**float64) }
+func (p pointer) Float64Slice() *[]float64 { return p.v.Interface().(*[]float64) }
+func (p pointer) String() *string          { return p.v.Interface().(*string) }
+func (p pointer) StringPtr() **string      { return p.v.Interface().(**string) }
+func (p pointer) StringSlice() *[]string   { return p.v.Interface().(*[]string) }
+func (p pointer) Bytes() *[]byte           { return p.v.Interface().(*[]byte) }
+func (p pointer) BytesSlice() *[][]byte    { return p.v.Interface().(*[][]byte) }
+func (p pointer) Extensions() *legacyExtensionMap {
+	return (*legacyExtensionMap)(p.v.Interface().(*map[int32]ExtensionFieldV1))
+}
+
+func (p pointer) Elem() pointer {
+	return pointer{v: p.v.Elem()}
+}
+
+// PointerSlice copies []*T from p as a new []pointer.
+// This behavior differs from the implementation in pointer_unsafe.go.
+func (p pointer) PointerSlice() []pointer {
+	// TODO: reconsider this
+	if p.v.IsNil() {
+		return nil
+	}
+	n := p.v.Elem().Len()
+	s := make([]pointer, n)
+	for i := 0; i < n; i++ {
+		s[i] = pointer{v: p.v.Elem().Index(i)}
+	}
+	return s
+}
diff --git a/internal/impl/pointer_unsafe.go b/internal/impl/pointer_unsafe.go
index 16078bd..f04a561 100644
--- a/internal/impl/pointer_unsafe.go
+++ b/internal/impl/pointer_unsafe.go
@@ -20,6 +20,15 @@
 	return offset(f.Offset)
 }
 
+// IsValid reports whether the offset is valid.
+func (f offset) IsValid() bool { return f != invalidOffset }
+
+// invalidOffset is an invalid field offset.
+var invalidOffset = ^offset(0)
+
+// zeroOffset is a noop when calling pointer.Apply.
+var zeroOffset = offset(0)
+
 // pointer is a pointer to a message struct or field.
 type pointer struct{ p unsafe.Pointer }
 
@@ -63,3 +72,44 @@
 	// TODO: Use tricky unsafe magic to directly create ifaceHeader.
 	return p.AsValueOf(t).Interface()
 }
+
+func (p pointer) Bool() *bool                     { return (*bool)(p.p) }
+func (p pointer) BoolPtr() **bool                 { return (**bool)(p.p) }
+func (p pointer) BoolSlice() *[]bool              { return (*[]bool)(p.p) }
+func (p pointer) Int32() *int32                   { return (*int32)(p.p) }
+func (p pointer) Int32Ptr() **int32               { return (**int32)(p.p) }
+func (p pointer) Int32Slice() *[]int32            { return (*[]int32)(p.p) }
+func (p pointer) Int64() *int64                   { return (*int64)(p.p) }
+func (p pointer) Int64Ptr() **int64               { return (**int64)(p.p) }
+func (p pointer) Int64Slice() *[]int64            { return (*[]int64)(p.p) }
+func (p pointer) Uint32() *uint32                 { return (*uint32)(p.p) }
+func (p pointer) Uint32Ptr() **uint32             { return (**uint32)(p.p) }
+func (p pointer) Uint32Slice() *[]uint32          { return (*[]uint32)(p.p) }
+func (p pointer) Uint64() *uint64                 { return (*uint64)(p.p) }
+func (p pointer) Uint64Ptr() **uint64             { return (**uint64)(p.p) }
+func (p pointer) Uint64Slice() *[]uint64          { return (*[]uint64)(p.p) }
+func (p pointer) Float32() *float32               { return (*float32)(p.p) }
+func (p pointer) Float32Ptr() **float32           { return (**float32)(p.p) }
+func (p pointer) Float32Slice() *[]float32        { return (*[]float32)(p.p) }
+func (p pointer) Float64() *float64               { return (*float64)(p.p) }
+func (p pointer) Float64Ptr() **float64           { return (**float64)(p.p) }
+func (p pointer) Float64Slice() *[]float64        { return (*[]float64)(p.p) }
+func (p pointer) String() *string                 { return (*string)(p.p) }
+func (p pointer) StringPtr() **string             { return (**string)(p.p) }
+func (p pointer) StringSlice() *[]string          { return (*[]string)(p.p) }
+func (p pointer) Bytes() *[]byte                  { return (*[]byte)(p.p) }
+func (p pointer) BytesSlice() *[][]byte           { return (*[][]byte)(p.p) }
+func (p pointer) Extensions() *legacyExtensionMap { return (*legacyExtensionMap)(p.p) }
+
+func (p pointer) Elem() pointer {
+	return pointer{p: *(*unsafe.Pointer)(p.p)}
+}
+
+// PointerSlice loads []*T from p as a []pointer.
+// The value returned is aliased with the original slice.
+// This behavior differs from the implementation in pointer_reflect.go.
+func (p pointer) PointerSlice() []pointer {
+	// Super-tricky - p should point to a []*T where T is a
+	// message type. We load it as []pointer.
+	return *(*[]pointer)(p.p)
+}
diff --git a/proto/decode_test.go b/proto/decode_test.go
index 47dfdb4..074aeb6 100644
--- a/proto/decode_test.go
+++ b/proto/decode_test.go
@@ -18,6 +18,8 @@
 	pref "google.golang.org/protobuf/reflect/protoreflect"
 	"google.golang.org/protobuf/runtime/protolegacy"
 
+	legacypb "google.golang.org/protobuf/internal/testprotos/legacy"
+	legacy1pb "google.golang.org/protobuf/internal/testprotos/legacy/proto2.v0.0.0-20160225-2fc053c5"
 	testpb "google.golang.org/protobuf/internal/testprotos/test"
 	test3pb "google.golang.org/protobuf/internal/testprotos/test3"
 )
@@ -516,17 +518,20 @@
 		decodeTo: []proto.Message{&testpb.TestAllTypes{
 			RepeatedNestedMessage: []*testpb.TestAllTypes_NestedMessage{
 				{A: scalar.Int32(1)},
+				nil,
 				{A: scalar.Int32(2)},
 			},
 		}, &test3pb.TestAllTypes{
 			RepeatedNestedMessage: []*test3pb.TestAllTypes_NestedMessage{
 				{A: 1},
+				nil,
 				{A: 2},
 			},
 		}, build(
 			&testpb.TestAllExtensions{},
 			extend(testpb.E_RepeatedNestedMessageExtension, []*testpb.TestAllTypes_NestedMessage{
 				{A: scalar.Int32(1)},
+				nil,
 				{A: scalar.Int32(2)},
 			}),
 		)},
@@ -534,6 +539,7 @@
 			pack.Tag{48, pack.BytesType}, pack.LengthPrefix(pack.Message{
 				pack.Tag{1, pack.VarintType}, pack.Varint(1),
 			}),
+			pack.Tag{48, pack.BytesType}, pack.LengthPrefix(pack.Message{}),
 			pack.Tag{48, pack.BytesType}, pack.LengthPrefix(pack.Message{
 				pack.Tag{1, pack.VarintType}, pack.Varint(2),
 			}),
@@ -544,12 +550,14 @@
 		decodeTo: []proto.Message{&testpb.TestAllTypes{
 			Repeatedgroup: []*testpb.TestAllTypes_RepeatedGroup{
 				{A: scalar.Int32(1017)},
+				nil,
 				{A: scalar.Int32(2017)},
 			},
 		}, build(
 			&testpb.TestAllExtensions{},
 			extend(testpb.E_RepeatedgroupExtension, []*testpb.RepeatedGroupExtension{
 				{A: scalar.Int32(1017)},
+				nil,
 				{A: scalar.Int32(2017)},
 			}),
 		)},
@@ -558,6 +566,8 @@
 			pack.Tag{47, pack.VarintType}, pack.Varint(1017),
 			pack.Tag{46, pack.EndGroupType},
 			pack.Tag{46, pack.StartGroupType},
+			pack.Tag{46, pack.EndGroupType},
+			pack.Tag{46, pack.StartGroupType},
 			pack.Tag{47, pack.VarintType}, pack.Varint(2017),
 			pack.Tag{46, pack.EndGroupType},
 		}.Marshal(),
@@ -778,6 +788,18 @@
 		})}.Marshal(),
 	},
 	{
+		desc: "oneof (empty message)",
+		decodeTo: []proto.Message{
+			&testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofNestedMessage{
+				&testpb.TestAllTypes_NestedMessage{},
+			}},
+			&test3pb.TestAllTypes{OneofField: &test3pb.TestAllTypes_OneofNestedMessage{
+				&test3pb.TestAllTypes_NestedMessage{},
+			}},
+		},
+		wire: pack.Message{pack.Tag{112, pack.BytesType}, pack.LengthPrefix(pack.Message{})}.Marshal(),
+	},
+	{
 		desc: "oneof (overridden message)",
 		decodeTo: []proto.Message{
 			&testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofNestedMessage{
@@ -861,6 +883,14 @@
 		wire: pack.Message{pack.Tag{119, pack.VarintType}, pack.Varint(int(testpb.TestAllTypes_BAR))}.Marshal(),
 	},
 	{
+		desc: "oneof (zero)",
+		decodeTo: []proto.Message{
+			&testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint64{0}},
+			&test3pb.TestAllTypes{OneofField: &test3pb.TestAllTypes_OneofUint64{0}},
+		},
+		wire: pack.Message{pack.Tag{116, pack.VarintType}, pack.Varint(0)}.Marshal(),
+	},
+	{
 		desc: "oneof (overridden value)",
 		decodeTo: []proto.Message{
 			&testpb.TestAllTypes{OneofField: &testpb.TestAllTypes_OneofUint64{2}},
@@ -1175,6 +1205,65 @@
 			}),
 		}.Marshal(),
 	},
+	{
+		desc:    "legacy",
+		partial: true,
+		decodeTo: []proto.Message{
+			&legacypb.Legacy{
+				F1: &legacy1pb.Message{
+					OptionalInt32:     scalar.Int32(1),
+					OptionalChildEnum: legacy1pb.Message_ALPHA.Enum(),
+					OptionalChildMessage: &legacy1pb.Message_ChildMessage{
+						F1: scalar.String("x"),
+					},
+					Optionalgroup: &legacy1pb.Message_OptionalGroup{
+						F1: scalar.String("x"),
+					},
+					RepeatedChildMessage: []*legacy1pb.Message_ChildMessage{
+						{F1: scalar.String("x")},
+					},
+					Repeatedgroup: []*legacy1pb.Message_RepeatedGroup{
+						{F1: scalar.String("x")},
+					},
+					MapBoolChildMessage: map[bool]*legacy1pb.Message_ChildMessage{
+						true: {F1: scalar.String("x")},
+					},
+					OneofUnion: &legacy1pb.Message_OneofChildMessage{
+						&legacy1pb.Message_ChildMessage{
+							F1: scalar.String("x"),
+						},
+					},
+				},
+			},
+		},
+		wire: pack.Message{
+			pack.Tag{1, pack.BytesType}, pack.LengthPrefix(pack.Message{
+				pack.Tag{101, pack.VarintType}, pack.Varint(1),
+				pack.Tag{115, pack.VarintType}, pack.Varint(0),
+				pack.Tag{116, pack.BytesType}, pack.LengthPrefix(pack.Message{
+					pack.Tag{1, pack.BytesType}, pack.String("x"),
+				}),
+				pack.Tag{120, pack.StartGroupType},
+				pack.Tag{1, pack.BytesType}, pack.String("x"),
+				pack.Tag{120, pack.EndGroupType},
+				pack.Tag{516, pack.BytesType}, pack.LengthPrefix(pack.Message{
+					pack.Tag{1, pack.BytesType}, pack.String("x"),
+				}),
+				pack.Tag{520, pack.StartGroupType},
+				pack.Tag{1, pack.BytesType}, pack.String("x"),
+				pack.Tag{520, pack.EndGroupType},
+				pack.Tag{616, pack.BytesType}, pack.LengthPrefix(pack.Message{
+					pack.Tag{1, pack.VarintType}, pack.Varint(1),
+					pack.Tag{2, pack.BytesType}, pack.LengthPrefix(pack.Message{
+						pack.Tag{1, pack.BytesType}, pack.String("x"),
+					}),
+				}),
+				pack.Tag{716, pack.BytesType}, pack.LengthPrefix(pack.Message{
+					pack.Tag{1, pack.BytesType}, pack.String("x"),
+				}),
+			}),
+		}.Marshal(),
+	},
 }
 
 var invalidUTF8TestProtos = []testProto{
@@ -1215,6 +1304,13 @@
 		}.Marshal(),
 	},
 	{
+		desc: "invalid UTF-8 in oneof field",
+		decodeTo: []proto.Message{
+			&test3pb.TestAllTypes{OneofField: &test3pb.TestAllTypes_OneofString{"abc\xff"}},
+		},
+		wire: pack.Message{pack.Tag{113, pack.BytesType}, pack.String("abc\xff")}.Marshal(),
+	},
+	{
 		desc: "invalid UTF-8 in map key",
 		decodeTo: []proto.Message{&test3pb.TestAllTypes{
 			MapStringString: map[string]string{"key\xff": "val"},
diff --git a/proto/encode.go b/proto/encode.go
index 187bfc6..b55389f 100644
--- a/proto/encode.go
+++ b/proto/encode.go
@@ -85,6 +85,10 @@
 // MarshalAppend appends the wire-format encoding of m to b,
 // returning the result.
 func (o MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error) {
+	// Set AllowPartial in recursive calls to marshal to avoid duplicating
+	// effort with the single initialization check below.
+	allowPartial := o.AllowPartial
+	o.AllowPartial = true
 	out, err := o.marshalMessageFast(b, m)
 	if err == errInternalNoFast {
 		out, err = o.marshalMessage(b, m.ProtoReflect())
@@ -93,7 +97,7 @@
 	if !nerr.Merge(err) {
 		return out, err
 	}
-	if !o.AllowPartial {
+	if !allowPartial {
 		nerr.Merge(IsInitialized(m))
 	}
 	return out, nerr.E
diff --git a/proto/encode_test.go b/proto/encode_test.go
index 3f015b7..539f704 100644
--- a/proto/encode_test.go
+++ b/proto/encode_test.go
@@ -1,3 +1,7 @@
+// Copyright 2019 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_test
 
 import (