proto, runtime/protoiface: add support for fast-path marshaling

Allow message implementations to provide optimized versions of standard
operations. Generated messages now include a ProtoReflectMethods method,
returning a protoiface.Methods struct containing pointers to assorted
optional functions.

The Methods struct also includes a Flags field indicating support for
optional features such as deterministic marshaling.

Implementation of the fast paths (and tests) will come in later CLs.

Change-Id: Idd1beed0ecf43ec5e5e7b8da2ee1e08d3ce32213
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/170340
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/proto/decode.go b/proto/decode.go
index c0934c6..4928ace 100644
--- a/proto/decode.go
+++ b/proto/decode.go
@@ -10,6 +10,7 @@
 	"github.com/golang/protobuf/v2/internal/encoding/wire"
 	"github.com/golang/protobuf/v2/internal/pragma"
 	"github.com/golang/protobuf/v2/reflect/protoreflect"
+	"github.com/golang/protobuf/v2/runtime/protoiface"
 )
 
 // UnmarshalOptions configures the unmarshaler.
@@ -20,9 +21,15 @@
 	// If DiscardUnknown is set, unknown fields are ignored.
 	DiscardUnknown bool
 
+	// Reflection forces use of the reflection-based decoder, even for
+	// messages which implement fast-path deserialization.
+	Reflection bool
+
 	pragma.NoUnkeyedLiterals
 }
 
+var _ = protoiface.UnmarshalOptions(UnmarshalOptions{})
+
 // Unmarshal parses the wire-format message in b and places the result in m.
 func Unmarshal(b []byte, m Message) error {
 	return UnmarshalOptions{}.Unmarshal(b, m)
@@ -31,9 +38,23 @@
 // Unmarshal parses the wire-format message in b and places the result in m.
 func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error {
 	// TODO: Reset m?
+	if err := o.unmarshalMessageFast(b, m); err != errInternalNoFast {
+		return err
+	}
 	return o.unmarshalMessage(b, m.ProtoReflect())
 }
 
+func (o UnmarshalOptions) unmarshalMessageFast(b []byte, m Message) error {
+	if o.Reflection {
+		return errInternalNoFast
+	}
+	methods := protoMethods(m)
+	if methods == nil || methods.Unmarshal == nil {
+		return errInternalNoFast
+	}
+	return methods.Unmarshal(b, m, protoiface.UnmarshalOptions(o))
+}
+
 func (o UnmarshalOptions) unmarshalMessage(b []byte, m protoreflect.Message) error {
 	messageType := m.Type()
 	fieldTypes := messageType.Fields()