Damien Neil b0d217f664 proto, internal/impl: don't create fast path Size for legacy Marshalers
Implementations of the legacy Marshaler type have no way to efficiently
compute the size of the message. Rather than generating an inefficient
fast-path Size method which marshals the message and examines the
length of the result, don't generate a fast-path at all.

Drop the requirement that a fast-path MarshalAppend requires a
corresponding Size.

Avoids O(N^2) behavior when marshaling a legacy Marshaler that
recursively calls proto.Marshal.

Change-Id: I4793cf32275d08f29c8e1a1a44a193d9a5724058
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/213443
Reviewed-by: Joe Tsai <joetsai@google.com>
2020-01-06 22:47:37 +00:00

83 lines
2.8 KiB
Go

// 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 protoiface contains types referenced or implemented by messages.
//
// WARNING: This package should only be imported by message implementations.
// The functionality found in this package should be accessed through
// higher-level abstractions provided by the proto package.
package protoiface
import (
"google.golang.org/protobuf/internal/pragma"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
// Methoder is an optional interface implemented by protoreflect.Message to
// provide fast-path implementations of various operations.
// The returned Methods struct must not be mutated.
type Methoder interface {
ProtoMethods() *Methods // may return nil
}
// Methods is a set of optional fast-path implementations of various operations.
type Methods struct {
pragma.NoUnkeyedLiterals
// Flags indicate support for optional features.
Flags SupportFlags
// Size returns the size in bytes of the wire-format encoding of m.
// MarshalAppend must be provided if a custom Size is provided.
Size func(m protoreflect.Message, opts MarshalOptions) int
// MarshalAppend appends the wire-format encoding of m to b, returning the result.
// Size should be provided if a custom MarshalAppend is provided.
// It must not perform required field checks.
MarshalAppend func(b []byte, m protoreflect.Message, opts MarshalOptions) ([]byte, error)
// Unmarshal parses the wire-format message in b and merges the result in m.
// It must not reset m or perform required field checks.
Unmarshal func(b []byte, m protoreflect.Message, opts UnmarshalOptions) error
// IsInitialized returns an error if any required fields in m are not set.
IsInitialized func(m protoreflect.Message) error
}
type SupportFlags uint64
const (
// SupportMarshalDeterministic reports whether MarshalOptions.Deterministic is supported.
SupportMarshalDeterministic SupportFlags = 1 << iota
// SupportUnmarshalDiscardUnknown reports whether UnmarshalOptions.DiscardUnknown is supported.
SupportUnmarshalDiscardUnknown
)
// MarshalOptions configure the marshaler.
//
// This type is identical to the one in package proto.
type MarshalOptions struct {
pragma.NoUnkeyedLiterals
AllowPartial bool // must be treated as true by method implementations
Deterministic bool
UseCachedSize bool
}
// UnmarshalOptions configures the unmarshaler.
//
// This type is identical to the one in package proto.
type UnmarshalOptions struct {
pragma.NoUnkeyedLiterals
Merge bool // must be treated as true by method implementations
AllowPartial bool // must be treated as true by method implementations
DiscardUnknown bool
Resolver interface {
protoregistry.ExtensionTypeResolver
}
}