mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-02-20 15:41:07 +00:00
all: abstract fast-path marshal and unmarshal inputs and outputs
We may want to make changes to the inputs and outputs of the fast-path functions in the future. For example, we likely want to add the ability for the fast-path unmarshal to report back whether the unmarshaled message is known to be initialized. Change the signatures of these functions to take in and return struct types which can be extended with whatever fields we want in the future. Change-Id: Idead360785df730283a4630ea405265b72482e62 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/215719 Reviewed-by: Joe Tsai <joetsai@google.com>
This commit is contained in:
parent
f12fb45fd6
commit
61781dd92f
@ -134,9 +134,9 @@ func (mi *MessageInfo) makeCoderMethods(t reflect.Type, si structInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mi.needsInitCheck = needsInitCheck(mi.Desc)
|
mi.needsInitCheck = needsInitCheck(mi.Desc)
|
||||||
if mi.methods.MarshalAppend == nil && mi.methods.Size == nil {
|
if mi.methods.Marshal == nil && mi.methods.Size == nil {
|
||||||
mi.methods.Flags |= piface.SupportMarshalDeterministic
|
mi.methods.Flags |= piface.SupportMarshalDeterministic
|
||||||
mi.methods.MarshalAppend = mi.marshalAppend
|
mi.methods.Marshal = mi.marshal
|
||||||
mi.methods.Size = mi.size
|
mi.methods.Size = mi.size
|
||||||
}
|
}
|
||||||
if mi.methods.Unmarshal == nil {
|
if mi.methods.Unmarshal == nil {
|
||||||
|
@ -58,15 +58,15 @@ func (o unmarshalOptions) DiscardUnknown() bool { return o.flags
|
|||||||
func (o unmarshalOptions) Resolver() preg.ExtensionTypeResolver { return o.resolver }
|
func (o unmarshalOptions) Resolver() preg.ExtensionTypeResolver { return o.resolver }
|
||||||
|
|
||||||
// unmarshal is protoreflect.Methods.Unmarshal.
|
// unmarshal is protoreflect.Methods.Unmarshal.
|
||||||
func (mi *MessageInfo) unmarshal(b []byte, m pref.Message, opts piface.UnmarshalOptions) error {
|
func (mi *MessageInfo) unmarshal(m pref.Message, in piface.UnmarshalInput) (piface.UnmarshalOutput, error) {
|
||||||
var p pointer
|
var p pointer
|
||||||
if ms, ok := m.(*messageState); ok {
|
if ms, ok := m.(*messageState); ok {
|
||||||
p = ms.pointer()
|
p = ms.pointer()
|
||||||
} else {
|
} else {
|
||||||
p = m.(*messageReflectWrapper).pointer()
|
p = m.(*messageReflectWrapper).pointer()
|
||||||
}
|
}
|
||||||
_, err := mi.unmarshalPointer(b, p, 0, newUnmarshalOptions(opts))
|
_, err := mi.unmarshalPointer(in.Buf, p, 0, newUnmarshalOptions(in.Options))
|
||||||
return err
|
return piface.UnmarshalOutput{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// errUnknown is returned during unmarshaling to indicate a parse error that
|
// errUnknown is returned during unmarshaling to indicate a parse error that
|
||||||
|
@ -101,15 +101,16 @@ func (mi *MessageInfo) sizePointerSlow(p pointer, opts marshalOptions) (size int
|
|||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
// marshalAppend is protoreflect.Methods.MarshalAppend.
|
// marshal is protoreflect.Methods.Marshal.
|
||||||
func (mi *MessageInfo) marshalAppend(b []byte, m pref.Message, opts piface.MarshalOptions) ([]byte, error) {
|
func (mi *MessageInfo) marshal(m pref.Message, in piface.MarshalInput) (piface.MarshalOutput, error) {
|
||||||
var p pointer
|
var p pointer
|
||||||
if ms, ok := m.(*messageState); ok {
|
if ms, ok := m.(*messageState); ok {
|
||||||
p = ms.pointer()
|
p = ms.pointer()
|
||||||
} else {
|
} else {
|
||||||
p = m.(*messageReflectWrapper).pointer()
|
p = m.(*messageReflectWrapper).pointer()
|
||||||
}
|
}
|
||||||
return mi.marshalAppendPointer(b, p, newMarshalOptions(opts))
|
b, err := mi.marshalAppendPointer(in.Buf, p, newMarshalOptions(in.Options))
|
||||||
|
return piface.MarshalOutput{Buf: b}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mi *MessageInfo) marshalAppendPointer(b []byte, p pointer, opts marshalOptions) ([]byte, error) {
|
func (mi *MessageInfo) marshalAppendPointer(b []byte, p pointer, opts marshalOptions) ([]byte, error) {
|
||||||
|
@ -50,7 +50,7 @@ func legacyLoadMessageInfo(t reflect.Type, name pref.FullName) *MessageInfo {
|
|||||||
|
|
||||||
v := reflect.Zero(t).Interface()
|
v := reflect.Zero(t).Interface()
|
||||||
if _, ok := v.(legacyMarshaler); ok {
|
if _, ok := v.(legacyMarshaler); ok {
|
||||||
mi.methods.MarshalAppend = legacyMarshalAppend
|
mi.methods.Marshal = legacyMarshal
|
||||||
|
|
||||||
// We have no way to tell whether the type's Marshal method
|
// We have no way to tell whether the type's Marshal method
|
||||||
// supports deterministic serialization or not, but this
|
// supports deterministic serialization or not, but this
|
||||||
@ -363,8 +363,8 @@ type legacyUnmarshaler interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var legacyProtoMethods = &piface.Methods{
|
var legacyProtoMethods = &piface.Methods{
|
||||||
MarshalAppend: legacyMarshalAppend,
|
Marshal: legacyMarshal,
|
||||||
Unmarshal: legacyUnmarshal,
|
Unmarshal: legacyUnmarshal,
|
||||||
|
|
||||||
// We have no way to tell whether the type's Marshal method
|
// We have no way to tell whether the type's Marshal method
|
||||||
// supports deterministic serialization or not, but this
|
// supports deterministic serialization or not, but this
|
||||||
@ -373,26 +373,28 @@ var legacyProtoMethods = &piface.Methods{
|
|||||||
Flags: piface.SupportMarshalDeterministic,
|
Flags: piface.SupportMarshalDeterministic,
|
||||||
}
|
}
|
||||||
|
|
||||||
func legacyMarshalAppend(b []byte, m protoreflect.Message, opts piface.MarshalOptions) ([]byte, error) {
|
func legacyMarshal(m protoreflect.Message, in piface.MarshalInput) (piface.MarshalOutput, error) {
|
||||||
v := m.(unwrapper).protoUnwrap()
|
v := m.(unwrapper).protoUnwrap()
|
||||||
marshaler, ok := v.(legacyMarshaler)
|
marshaler, ok := v.(legacyMarshaler)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("%T does not implement Marshal", v)
|
return piface.MarshalOutput{}, errors.New("%T does not implement Marshal", v)
|
||||||
}
|
}
|
||||||
out, err := marshaler.Marshal()
|
out, err := marshaler.Marshal()
|
||||||
if b != nil {
|
if in.Buf != nil {
|
||||||
out = append(b, out...)
|
out = append(in.Buf, out...)
|
||||||
}
|
}
|
||||||
return out, err
|
return piface.MarshalOutput{
|
||||||
|
Buf: out,
|
||||||
|
}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func legacyUnmarshal(b []byte, m protoreflect.Message, opts piface.UnmarshalOptions) error {
|
func legacyUnmarshal(m protoreflect.Message, in piface.UnmarshalInput) (piface.UnmarshalOutput, error) {
|
||||||
v := m.(unwrapper).protoUnwrap()
|
v := m.(unwrapper).protoUnwrap()
|
||||||
unmarshaler, ok := v.(legacyUnmarshaler)
|
unmarshaler, ok := v.(legacyUnmarshaler)
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("%T does not implement Marshal", v)
|
return piface.UnmarshalOutput{}, errors.New("%T does not implement Marshal", v)
|
||||||
}
|
}
|
||||||
return unmarshaler.Unmarshal(b)
|
return piface.UnmarshalOutput{}, unmarshaler.Unmarshal(in.Buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// aberrantMessageType implements MessageType for all types other than pointer-to-struct.
|
// aberrantMessageType implements MessageType for all types other than pointer-to-struct.
|
||||||
|
@ -72,7 +72,11 @@ func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error {
|
|||||||
func (o UnmarshalOptions) unmarshalMessage(b []byte, m protoreflect.Message) error {
|
func (o UnmarshalOptions) unmarshalMessage(b []byte, m protoreflect.Message) error {
|
||||||
if methods := protoMethods(m); methods != nil && methods.Unmarshal != nil &&
|
if methods := protoMethods(m); methods != nil && methods.Unmarshal != nil &&
|
||||||
!(o.DiscardUnknown && methods.Flags&protoiface.SupportUnmarshalDiscardUnknown == 0) {
|
!(o.DiscardUnknown && methods.Flags&protoiface.SupportUnmarshalDiscardUnknown == 0) {
|
||||||
return methods.Unmarshal(b, m, protoiface.UnmarshalOptions(o))
|
_, err := methods.Unmarshal(m, protoiface.UnmarshalInput{
|
||||||
|
Buf: b,
|
||||||
|
Options: protoiface.UnmarshalOptions(o),
|
||||||
|
})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
return o.unmarshalMessageSlow(b, m)
|
return o.unmarshalMessageSlow(b, m)
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ func (o MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o MarshalOptions) marshalMessage(b []byte, m protoreflect.Message) ([]byte, error) {
|
func (o MarshalOptions) marshalMessage(b []byte, m protoreflect.Message) ([]byte, error) {
|
||||||
if methods := protoMethods(m); methods != nil && methods.MarshalAppend != nil &&
|
if methods := protoMethods(m); methods != nil && methods.Marshal != nil &&
|
||||||
!(o.Deterministic && methods.Flags&protoiface.SupportMarshalDeterministic == 0) {
|
!(o.Deterministic && methods.Flags&protoiface.SupportMarshalDeterministic == 0) {
|
||||||
if methods.Size != nil {
|
if methods.Size != nil {
|
||||||
sz := methods.Size(m, protoiface.MarshalOptions(o))
|
sz := methods.Size(m, protoiface.MarshalOptions(o))
|
||||||
@ -109,7 +109,11 @@ func (o MarshalOptions) marshalMessage(b []byte, m protoreflect.Message) ([]byte
|
|||||||
}
|
}
|
||||||
o.UseCachedSize = true
|
o.UseCachedSize = true
|
||||||
}
|
}
|
||||||
return methods.MarshalAppend(b, m, protoiface.MarshalOptions(o))
|
out, err := methods.Marshal(m, protoiface.MarshalInput{
|
||||||
|
Buf: b,
|
||||||
|
Options: protoiface.MarshalOptions(o),
|
||||||
|
})
|
||||||
|
return out.Buf, err
|
||||||
}
|
}
|
||||||
return o.marshalMessageSlow(b, m)
|
return o.marshalMessageSlow(b, m)
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,11 @@ func sizeMessage(m protoreflect.Message) (size int) {
|
|||||||
if methods != nil && methods.Size != nil {
|
if methods != nil && methods.Size != nil {
|
||||||
return methods.Size(m, protoiface.MarshalOptions{})
|
return methods.Size(m, protoiface.MarshalOptions{})
|
||||||
}
|
}
|
||||||
if methods != nil && methods.MarshalAppend != nil {
|
if methods != nil && methods.Marshal != nil {
|
||||||
// This is not efficient, but we don't have any choice.
|
// This is not efficient, but we don't have any choice.
|
||||||
// This case is mainly used for legacy types with a Marshal method.
|
// This case is mainly used for legacy types with a Marshal method.
|
||||||
b, _ := methods.MarshalAppend(nil, m, protoiface.MarshalOptions{})
|
out, _ := methods.Marshal(m, protoiface.MarshalInput{})
|
||||||
return len(b)
|
return len(out.Buf)
|
||||||
}
|
}
|
||||||
return sizeMessageSlow(m)
|
return sizeMessageSlow(m)
|
||||||
}
|
}
|
||||||
|
@ -19,18 +19,34 @@ type (
|
|||||||
pragma.NoUnkeyedLiterals
|
pragma.NoUnkeyedLiterals
|
||||||
Flags supportFlags
|
Flags supportFlags
|
||||||
Size func(m Message, opts marshalOptions) int
|
Size func(m Message, opts marshalOptions) int
|
||||||
MarshalAppend func(b []byte, m Message, opts marshalOptions) ([]byte, error)
|
Marshal func(m Message, in marshalInput) (marshalOutput, error)
|
||||||
Unmarshal func(b []byte, m Message, opts unmarshalOptions) error
|
Unmarshal func(m Message, in unmarshalInput) (unmarshalOutput, error)
|
||||||
IsInitialized func(m Message) error
|
IsInitialized func(m Message) error
|
||||||
}
|
}
|
||||||
supportFlags = uint64
|
supportFlags = uint64
|
||||||
|
marshalInput = struct {
|
||||||
|
pragma.NoUnkeyedLiterals
|
||||||
|
Buf []byte
|
||||||
|
Options marshalOptions
|
||||||
|
}
|
||||||
|
marshalOutput = struct {
|
||||||
|
pragma.NoUnkeyedLiterals
|
||||||
|
Buf []byte
|
||||||
|
}
|
||||||
marshalOptions = struct {
|
marshalOptions = struct {
|
||||||
pragma.NoUnkeyedLiterals
|
pragma.NoUnkeyedLiterals
|
||||||
AllowPartial bool
|
AllowPartial bool
|
||||||
Deterministic bool
|
Deterministic bool
|
||||||
UseCachedSize bool
|
UseCachedSize bool
|
||||||
}
|
}
|
||||||
|
unmarshalInput = struct {
|
||||||
|
pragma.NoUnkeyedLiterals
|
||||||
|
Buf []byte
|
||||||
|
Options unmarshalOptions
|
||||||
|
}
|
||||||
|
unmarshalOutput = struct {
|
||||||
|
pragma.NoUnkeyedLiterals
|
||||||
|
}
|
||||||
unmarshalOptions = struct {
|
unmarshalOptions = struct {
|
||||||
pragma.NoUnkeyedLiterals
|
pragma.NoUnkeyedLiterals
|
||||||
Merge bool
|
Merge bool
|
||||||
|
@ -25,14 +25,14 @@ type Methods = struct {
|
|||||||
// MarshalAppend must be provided if a custom Size is provided.
|
// MarshalAppend must be provided if a custom Size is provided.
|
||||||
Size func(m protoreflect.Message, opts MarshalOptions) int
|
Size func(m protoreflect.Message, opts MarshalOptions) int
|
||||||
|
|
||||||
// MarshalAppend appends the wire-format encoding of m to b, returning the result.
|
// Marshal writes the wire-format encoding of m to the provided buffer.
|
||||||
// Size should be provided if a custom MarshalAppend is provided.
|
// Size should be provided if a custom MarshalAppend is provided.
|
||||||
// It must not perform required field checks.
|
// It must not perform required field checks.
|
||||||
MarshalAppend func(b []byte, m protoreflect.Message, opts MarshalOptions) ([]byte, error)
|
Marshal func(m protoreflect.Message, in MarshalInput) (MarshalOutput, error)
|
||||||
|
|
||||||
// Unmarshal parses the wire-format message in b and merges the result in m.
|
// Unmarshal parses the wire-format encoding of a message and merges the result to m.
|
||||||
// It must not reset m or perform required field checks.
|
// It must not reset m or perform required field checks.
|
||||||
Unmarshal func(b []byte, m protoreflect.Message, opts UnmarshalOptions) error
|
Unmarshal func(m protoreflect.Message, in UnmarshalInput) (UnmarshalOutput, error)
|
||||||
|
|
||||||
// IsInitialized returns an error if any required fields in m are not set.
|
// IsInitialized returns an error if any required fields in m are not set.
|
||||||
IsInitialized func(m protoreflect.Message) error
|
IsInitialized func(m protoreflect.Message) error
|
||||||
@ -48,6 +48,21 @@ const (
|
|||||||
SupportUnmarshalDiscardUnknown
|
SupportUnmarshalDiscardUnknown
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// MarshalInput is input to the marshaler.
|
||||||
|
type MarshalInput = struct {
|
||||||
|
pragma.NoUnkeyedLiterals
|
||||||
|
|
||||||
|
Buf []byte // output is appended to this buffer
|
||||||
|
Options MarshalOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalOutput is output from the marshaler.
|
||||||
|
type MarshalOutput = struct {
|
||||||
|
pragma.NoUnkeyedLiterals
|
||||||
|
|
||||||
|
Buf []byte // contains marshaled message
|
||||||
|
}
|
||||||
|
|
||||||
// MarshalOptions configure the marshaler.
|
// MarshalOptions configure the marshaler.
|
||||||
//
|
//
|
||||||
// This type is identical to the one in package proto.
|
// This type is identical to the one in package proto.
|
||||||
@ -59,6 +74,21 @@ type MarshalOptions = struct {
|
|||||||
UseCachedSize bool
|
UseCachedSize bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnmarshalInput is input to the unmarshaler.
|
||||||
|
type UnmarshalInput = struct {
|
||||||
|
pragma.NoUnkeyedLiterals
|
||||||
|
|
||||||
|
Buf []byte // input buffer
|
||||||
|
Options UnmarshalOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalOutput is output from the unmarshaler.
|
||||||
|
type UnmarshalOutput = struct {
|
||||||
|
pragma.NoUnkeyedLiterals
|
||||||
|
|
||||||
|
// Contents available for future expansion.
|
||||||
|
}
|
||||||
|
|
||||||
// UnmarshalOptions configures the unmarshaler.
|
// UnmarshalOptions configures the unmarshaler.
|
||||||
//
|
//
|
||||||
// This type is identical to the one in package proto.
|
// This type is identical to the one in package proto.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user