vendor: update buildkit to master@31c870e82a48

Signed-off-by: Justin Chadwell <me@jedevc.com>
This commit is contained in:
Justin Chadwell
2023-05-15 18:32:31 +01:00
parent 167cd16acb
commit e61a8cf637
269 changed files with 25798 additions and 3371 deletions

View File

@ -228,6 +228,7 @@ func genEnum(g *protogen.GeneratedFile, f *fileInfo, e *enumInfo) {
// Enum type declaration.
g.Annotate(e.GoIdent.GoName, e.Location)
leadingComments := appendDeprecationSuffix(e.Comments.Leading,
e.Desc.ParentFile(),
e.Desc.Options().(*descriptorpb.EnumOptions).GetDeprecated())
g.P(leadingComments,
"type ", e.GoIdent, " int32")
@ -237,6 +238,7 @@ func genEnum(g *protogen.GeneratedFile, f *fileInfo, e *enumInfo) {
for _, value := range e.Values {
g.Annotate(value.GoIdent.GoName, value.Location)
leadingComments := appendDeprecationSuffix(value.Comments.Leading,
value.Desc.ParentFile(),
value.Desc.Options().(*descriptorpb.EnumValueOptions).GetDeprecated())
g.P(leadingComments,
value.GoIdent, " ", e.GoIdent, " = ", value.Desc.Number(),
@ -322,6 +324,7 @@ func genMessage(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo) {
// Message type declaration.
g.Annotate(m.GoIdent.GoName, m.Location)
leadingComments := appendDeprecationSuffix(m.Comments.Leading,
m.Desc.ParentFile(),
m.Desc.Options().(*descriptorpb.MessageOptions).GetDeprecated())
g.P(leadingComments,
"type ", m.GoIdent, " struct {")
@ -421,6 +424,7 @@ func genMessageField(g *protogen.GeneratedFile, f *fileInfo, m *messageInfo, fie
}
g.Annotate(m.GoIdent.GoName+"."+name, field.Location)
leadingComments := appendDeprecationSuffix(field.Comments.Leading,
field.Desc.ParentFile(),
field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
g.P(leadingComments,
name, " ", goType, tags,
@ -561,6 +565,7 @@ func genMessageGetterMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageI
defaultValue := fieldDefaultValue(g, f, m, field)
g.Annotate(m.GoIdent.GoName+".Get"+field.GoName, field.Location)
leadingComments := appendDeprecationSuffix("",
field.Desc.ParentFile(),
field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
switch {
case field.Desc.IsWeak():
@ -611,6 +616,7 @@ func genMessageSetterMethods(g *protogen.GeneratedFile, f *fileInfo, m *messageI
g.Annotate(m.GoIdent.GoName+".Set"+field.GoName, field.Location)
leadingComments := appendDeprecationSuffix("",
field.Desc.ParentFile(),
field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
g.P(leadingComments, "func (x *", m.GoIdent, ") Set", field.GoName, "(v ", protoPackage.Ident("Message"), ") {")
g.P("var w *", protoimplPackage.Ident("WeakFields"))
@ -773,6 +779,7 @@ func genExtensions(g *protogen.GeneratedFile, f *fileInfo) {
leadingComments += protogen.Comments(fmt.Sprintf(" %v %v %v = %v;\n",
xd.Cardinality(), typeName, fieldName, xd.Number()))
leadingComments = appendDeprecationSuffix(leadingComments,
x.Desc.ParentFile(),
x.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
g.P(leadingComments,
"E_", x.GoIdent, " = &", extensionTypesVarName(f), "[", allExtensionsByPtr[x], "]",
@ -807,6 +814,7 @@ func genMessageOneofWrapperTypes(g *protogen.GeneratedFile, f *fileInfo, m *mess
tags = append(tags, gotrackTags...)
}
leadingComments := appendDeprecationSuffix(field.Comments.Leading,
field.Desc.ParentFile(),
field.Desc.Options().(*descriptorpb.FieldOptions).GetDeprecated())
g.P(leadingComments,
field.GoName, " ", goType, tags,
@ -860,14 +868,18 @@ func (tags structTags) String() string {
}
// appendDeprecationSuffix optionally appends a deprecation notice as a suffix.
func appendDeprecationSuffix(prefix protogen.Comments, deprecated bool) protogen.Comments {
if !deprecated {
func appendDeprecationSuffix(prefix protogen.Comments, parentFile protoreflect.FileDescriptor, deprecated bool) protogen.Comments {
fileDeprecated := parentFile.Options().(*descriptorpb.FileOptions).GetDeprecated()
if !deprecated && !fileDeprecated {
return prefix
}
if prefix != "" {
prefix += "\n"
}
return prefix + " Deprecated: Do not use.\n"
if fileDeprecated {
return prefix + " Deprecated: The entire proto file " + protogen.Comments(parentFile.Path()) + " is marked as deprecated.\n"
}
return prefix + " Deprecated: Marked as deprecated in " + protogen.Comments(parentFile.Path()) + ".\n"
}
// trailingComment is like protogen.Comments, but lacks a trailing newline.

View File

@ -12,6 +12,8 @@ import (
"google.golang.org/protobuf/compiler/protogen"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protopath"
"google.golang.org/protobuf/reflect/protorange"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/types/descriptorpb"
@ -233,10 +235,29 @@ func genReflectFileDescriptor(gen *protogen.Plugin, g *protogen.GeneratedFile, f
g.P("}")
}
// stripSourceRetentionFieldsFromMessage walks the given message tree recursively
// and clears any fields with the field option: [retention = RETENTION_SOURCE]
func stripSourceRetentionFieldsFromMessage(m protoreflect.Message) {
protorange.Range(m, func(ppv protopath.Values) error {
m2, ok := ppv.Index(-1).Value.Interface().(protoreflect.Message)
if !ok {
return nil
}
m2.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
fdo, ok := fd.Options().(*descriptorpb.FieldOptions)
if ok && fdo.GetRetention() == descriptorpb.FieldOptions_RETENTION_SOURCE {
m2.Clear(fd)
}
return true
})
return nil
})
}
func genFileDescriptor(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo) {
descProto := proto.Clone(f.Proto).(*descriptorpb.FileDescriptorProto)
descProto.SourceCodeInfo = nil // drop source code information
stripSourceRetentionFieldsFromMessage(descProto.ProtoReflect())
b, err := proto.MarshalOptions{AllowPartial: true, Deterministic: true}.Marshal(descProto)
if err != nil {
gen.Error(err)

View File

@ -208,8 +208,7 @@ func genPackageKnownComment(f *fileInfo) protogen.Comments {
"google.golang.org/protobuf/encoding/protojson" package
ensures that they will be serialized as their JSON equivalent.
Conversion to and from a Go interface
# Conversion to and from a Go interface
The standard Go "encoding/json" package has functionality to serialize
arbitrary types to a large degree. The Value.AsInterface, Struct.AsMap, and
@ -222,8 +221,7 @@ func genPackageKnownComment(f *fileInfo) protogen.Comments {
forms back as Value, Struct, and ListValue messages, use the NewStruct,
NewList, and NewValue constructor functions.
Example usage
# Example usage
Consider the following example JSON object:
@ -282,7 +280,6 @@ func genPackageKnownComment(f *fileInfo) protogen.Comments {
... // handle error
}
... // make use of m as a *structpb.Value
`
case genid.File_google_protobuf_field_mask_proto:
return ` Package fieldmaskpb contains generated types for ` + genid.File_google_protobuf_field_mask_proto + `.
@ -656,8 +653,9 @@ func genMessageKnownFunctions(g *protogen.GeneratedFile, f *fileInfo, m *message
g.P("// AsMap converts x to a general-purpose Go map.")
g.P("// The map values are converted by calling Value.AsInterface.")
g.P("func (x *Struct) AsMap() map[string]interface{} {")
g.P(" vs := make(map[string]interface{})")
g.P(" for k, v := range x.GetFields() {")
g.P(" f := x.GetFields()")
g.P(" vs := make(map[string]interface{}, len(f))")
g.P(" for k, v := range f {")
g.P(" vs[k] = v.AsInterface()")
g.P(" }")
g.P(" return vs")
@ -693,8 +691,9 @@ func genMessageKnownFunctions(g *protogen.GeneratedFile, f *fileInfo, m *message
g.P("// AsSlice converts x to a general-purpose Go slice.")
g.P("// The slice elements are converted by calling Value.AsInterface.")
g.P("func (x *ListValue) AsSlice() []interface{} {")
g.P(" vs := make([]interface{}, len(x.GetValues()))")
g.P(" for i, v := range x.GetValues() {")
g.P(" vals := x.GetValues()")
g.P(" vs := make([]interface{}, len(vals))")
g.P(" for i, v := range vals {")
g.P(" vs[i] = v.AsInterface()")
g.P(" }")
g.P(" return vs")

View File

@ -36,10 +36,11 @@ import (
"google.golang.org/protobuf/reflect/protoregistry"
"google.golang.org/protobuf/types/descriptorpb"
"google.golang.org/protobuf/types/dynamicpb"
"google.golang.org/protobuf/types/pluginpb"
)
const goPackageDocURL = "https://developers.google.com/protocol-buffers/docs/reference/go-generated#package"
const goPackageDocURL = "https://protobuf.dev/reference/go/go-generated#package"
// Run executes a function as a protoc plugin.
//
@ -209,6 +210,7 @@ func (opts Options) New(req *pluginpb.CodeGeneratorRequest) (*Plugin, error) {
}
}
}
// When the module= option is provided, we strip the module name
// prefix from generated files. This only makes sense if generated
// filenames are based on the import path.
@ -298,6 +300,8 @@ func (opts Options) New(req *pluginpb.CodeGeneratorRequest) (*Plugin, error) {
}
}
// The extracted types from the full import set
typeRegistry := newExtensionRegistry()
for _, fdesc := range gen.Request.ProtoFile {
filename := fdesc.GetName()
if gen.FilesByPath[filename] != nil {
@ -309,6 +313,9 @@ func (opts Options) New(req *pluginpb.CodeGeneratorRequest) (*Plugin, error) {
}
gen.Files = append(gen.Files, f)
gen.FilesByPath[filename] = f
if err = typeRegistry.registerAllExtensionsFromFile(f.Desc); err != nil {
return nil, err
}
}
for _, filename := range gen.Request.FileToGenerate {
f, ok := gen.FilesByPath[filename]
@ -317,6 +324,20 @@ func (opts Options) New(req *pluginpb.CodeGeneratorRequest) (*Plugin, error) {
}
f.Generate = true
}
// Create fully-linked descriptors if new extensions were found
if typeRegistry.hasNovelExtensions() {
for _, f := range gen.Files {
b, err := proto.Marshal(f.Proto.ProtoReflect().Interface())
if err != nil {
return nil, err
}
err = proto.UnmarshalOptions{Resolver: typeRegistry}.Unmarshal(b, f.Proto)
if err != nil {
return nil, err
}
}
}
return gen, nil
}
@ -1259,3 +1280,78 @@ func (c Comments) String() string {
}
return string(b)
}
// extensionRegistry allows registration of new extensions defined in the .proto
// file for which we are generating bindings.
//
// Lookups consult the local type registry first and fall back to the base type
// registry which defaults to protoregistry.GlobalTypes
type extensionRegistry struct {
base *protoregistry.Types
local *protoregistry.Types
}
func newExtensionRegistry() *extensionRegistry {
return &extensionRegistry{
base: protoregistry.GlobalTypes,
local: &protoregistry.Types{},
}
}
// FindExtensionByName implements proto.UnmarshalOptions.FindExtensionByName
func (e *extensionRegistry) FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error) {
if xt, err := e.local.FindExtensionByName(field); err == nil {
return xt, nil
}
return e.base.FindExtensionByName(field)
}
// FindExtensionByNumber implements proto.UnmarshalOptions.FindExtensionByNumber
func (e *extensionRegistry) FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error) {
if xt, err := e.local.FindExtensionByNumber(message, field); err == nil {
return xt, nil
}
return e.base.FindExtensionByNumber(message, field)
}
func (e *extensionRegistry) hasNovelExtensions() bool {
return e.local.NumExtensions() > 0
}
func (e *extensionRegistry) registerAllExtensionsFromFile(f protoreflect.FileDescriptor) error {
if err := e.registerAllExtensions(f.Extensions()); err != nil {
return err
}
return nil
}
func (e *extensionRegistry) registerAllExtensionsFromMessage(ms protoreflect.MessageDescriptors) error {
for i := 0; i < ms.Len(); i++ {
m := ms.Get(i)
if err := e.registerAllExtensions(m.Extensions()); err != nil {
return err
}
}
return nil
}
func (e *extensionRegistry) registerAllExtensions(exts protoreflect.ExtensionDescriptors) error {
for i := 0; i < exts.Len(); i++ {
if err := e.registerExtension(exts.Get(i)); err != nil {
return err
}
}
return nil
}
// registerExtension adds the given extension to the type registry if an
// extension with that full name does not exist yet.
func (e *extensionRegistry) registerExtension(xd protoreflect.ExtensionDescriptor) error {
if _, err := e.FindExtensionByName(xd.FullName()); err != protoregistry.NotFound {
// Either the extension already exists or there was an error, either way we're done.
return err
}
return e.local.RegisterExtension(dynamicpb.NewExtensionType(xd))
}

View File

@ -4,7 +4,7 @@
// Package protojson marshals and unmarshals protocol buffer messages as JSON
// format. It follows the guide at
// https://developers.google.com/protocol-buffers/docs/proto3#json.
// https://protobuf.dev/programming-guides/proto3#json.
//
// This package produces a different output than the standard "encoding/json"
// package, which does not operate correctly on protocol buffer messages.

View File

@ -814,16 +814,22 @@ func (d decoder) unmarshalTimestamp(m protoreflect.Message) error {
return d.unexpectedTokenError(tok)
}
t, err := time.Parse(time.RFC3339Nano, tok.ParsedString())
s := tok.ParsedString()
t, err := time.Parse(time.RFC3339Nano, s)
if err != nil {
return d.newError(tok.Pos(), "invalid %v value %v", genid.Timestamp_message_fullname, tok.RawString())
}
// Validate seconds. No need to validate nanos because time.Parse would have
// covered that already.
// Validate seconds.
secs := t.Unix()
if secs < minTimestampSeconds || secs > maxTimestampSeconds {
return d.newError(tok.Pos(), "%v value out of range: %v", genid.Timestamp_message_fullname, tok.RawString())
}
// Validate subseconds.
i := strings.LastIndexByte(s, '.') // start of subsecond field
j := strings.LastIndexAny(s, "Z-+") // start of timezone field
if i >= 0 && j >= i && j-i > len(".999999999") {
return d.newError(tok.Pos(), "invalid %v value %v", genid.Timestamp_message_fullname, tok.RawString())
}
fds := m.Descriptor().Fields()
fdSeconds := fds.ByNumber(genid.Timestamp_Seconds_field_number)

View File

@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
// Package protowire parses and formats the raw wire encoding.
// See https://developers.google.com/protocol-buffers/docs/encoding.
// See https://protobuf.dev/programming-guides/encoding.
//
// For marshaling and unmarshaling entire protobuf messages,
// use the "google.golang.org/protobuf/proto" package instead.
@ -29,12 +29,8 @@ const (
)
// IsValid reports whether the field number is semantically valid.
//
// Note that while numbers within the reserved range are semantically invalid,
// they are syntactically valid in the wire format.
// Implementations may treat records with reserved field numbers as unknown.
func (n Number) IsValid() bool {
return MinValidNumber <= n && n < FirstReservedNumber || LastReservedNumber < n && n <= MaxValidNumber
return MinValidNumber <= n && n <= MaxValidNumber
}
// Type represents the wire type.

View File

@ -294,7 +294,7 @@ func (d *Decoder) isValueNext() bool {
}
// consumeToken constructs a Token for given Kind with raw value derived from
// current d.in and given size, and consumes the given size-lenght of it.
// current d.in and given size, and consumes the given size-length of it.
func (d *Decoder) consumeToken(kind Kind, size int) Token {
tok := Token{
kind: kind,

View File

@ -412,12 +412,13 @@ func (d *Decoder) parseFieldName() (tok Token, err error) {
// Field number. Identify if input is a valid number that is not negative
// and is decimal integer within 32-bit range.
if num := parseNumber(d.in); num.size > 0 {
str := num.string(d.in)
if !num.neg && num.kind == numDec {
if _, err := strconv.ParseInt(string(d.in[:num.size]), 10, 32); err == nil {
if _, err := strconv.ParseInt(str, 10, 32); err == nil {
return d.consumeToken(Name, num.size, uint8(FieldNumber)), nil
}
}
return Token{}, d.newSyntaxError("invalid field number: %s", d.in[:num.size])
return Token{}, d.newSyntaxError("invalid field number: %s", str)
}
return Token{}, d.newSyntaxError("invalid field name: %s", errId(d.in))

View File

@ -15,17 +15,12 @@ func (d *Decoder) parseNumberValue() (Token, bool) {
if num.neg {
numAttrs |= isNegative
}
strSize := num.size
last := num.size - 1
if num.kind == numFloat && (d.in[last] == 'f' || d.in[last] == 'F') {
strSize = last
}
tok := Token{
kind: Scalar,
attrs: numberValue,
pos: len(d.orig) - len(d.in),
raw: d.in[:num.size],
str: string(d.in[:strSize]),
str: num.string(d.in),
numAttrs: numAttrs,
}
d.consume(num.size)
@ -46,6 +41,27 @@ type number struct {
kind uint8
neg bool
size int
// if neg, this is the length of whitespace and comments between
// the minus sign and the rest fo the number literal
sep int
}
func (num number) string(data []byte) string {
strSize := num.size
last := num.size - 1
if num.kind == numFloat && (data[last] == 'f' || data[last] == 'F') {
strSize = last
}
if num.neg && num.sep > 0 {
// strip whitespace/comments between negative sign and the rest
strLen := strSize - num.sep
str := make([]byte, strLen)
str[0] = data[0]
copy(str[1:], data[num.sep+1:strSize])
return string(str)
}
return string(data[:strSize])
}
// parseNumber constructs a number object from given input. It allows for the
@ -67,19 +83,22 @@ func parseNumber(input []byte) number {
}
// Optional -
var sep int
if s[0] == '-' {
neg = true
s = s[1:]
size++
// Consume any whitespace or comments between the
// negative sign and the rest of the number
lenBefore := len(s)
s = consume(s, 0)
sep = lenBefore - len(s)
size += sep
if len(s) == 0 {
return number{}
}
}
// C++ allows for whitespace and comments in between the negative sign and
// the rest of the number. This logic currently does not but is consistent
// with v1.
switch {
case s[0] == '0':
if len(s) > 1 {
@ -116,7 +135,7 @@ func parseNumber(input []byte) number {
if len(s) > 0 && !isDelim(s[0]) {
return number{}
}
return number{kind: kind, neg: neg, size: size}
return number{kind: kind, neg: neg, size: size, sep: sep}
}
}
s = s[1:]
@ -188,5 +207,5 @@ func parseNumber(input []byte) number {
return number{}
}
return number{kind: kind, neg: neg, size: size}
return number{kind: kind, neg: neg, size: size, sep: sep}
}

View File

@ -50,6 +50,7 @@ const (
FileDescriptorProto_Options_field_name protoreflect.Name = "options"
FileDescriptorProto_SourceCodeInfo_field_name protoreflect.Name = "source_code_info"
FileDescriptorProto_Syntax_field_name protoreflect.Name = "syntax"
FileDescriptorProto_Edition_field_name protoreflect.Name = "edition"
FileDescriptorProto_Name_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.name"
FileDescriptorProto_Package_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.package"
@ -63,6 +64,7 @@ const (
FileDescriptorProto_Options_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.options"
FileDescriptorProto_SourceCodeInfo_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.source_code_info"
FileDescriptorProto_Syntax_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.syntax"
FileDescriptorProto_Edition_field_fullname protoreflect.FullName = "google.protobuf.FileDescriptorProto.edition"
)
// Field numbers for google.protobuf.FileDescriptorProto.
@ -79,6 +81,7 @@ const (
FileDescriptorProto_Options_field_number protoreflect.FieldNumber = 8
FileDescriptorProto_SourceCodeInfo_field_number protoreflect.FieldNumber = 9
FileDescriptorProto_Syntax_field_number protoreflect.FieldNumber = 12
FileDescriptorProto_Edition_field_number protoreflect.FieldNumber = 13
)
// Names for google.protobuf.DescriptorProto.
@ -494,26 +497,29 @@ const (
// Field names for google.protobuf.MessageOptions.
const (
MessageOptions_MessageSetWireFormat_field_name protoreflect.Name = "message_set_wire_format"
MessageOptions_NoStandardDescriptorAccessor_field_name protoreflect.Name = "no_standard_descriptor_accessor"
MessageOptions_Deprecated_field_name protoreflect.Name = "deprecated"
MessageOptions_MapEntry_field_name protoreflect.Name = "map_entry"
MessageOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
MessageOptions_MessageSetWireFormat_field_name protoreflect.Name = "message_set_wire_format"
MessageOptions_NoStandardDescriptorAccessor_field_name protoreflect.Name = "no_standard_descriptor_accessor"
MessageOptions_Deprecated_field_name protoreflect.Name = "deprecated"
MessageOptions_MapEntry_field_name protoreflect.Name = "map_entry"
MessageOptions_DeprecatedLegacyJsonFieldConflicts_field_name protoreflect.Name = "deprecated_legacy_json_field_conflicts"
MessageOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
MessageOptions_MessageSetWireFormat_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.message_set_wire_format"
MessageOptions_NoStandardDescriptorAccessor_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.no_standard_descriptor_accessor"
MessageOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.deprecated"
MessageOptions_MapEntry_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.map_entry"
MessageOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.uninterpreted_option"
MessageOptions_MessageSetWireFormat_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.message_set_wire_format"
MessageOptions_NoStandardDescriptorAccessor_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.no_standard_descriptor_accessor"
MessageOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.deprecated"
MessageOptions_MapEntry_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.map_entry"
MessageOptions_DeprecatedLegacyJsonFieldConflicts_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.deprecated_legacy_json_field_conflicts"
MessageOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.MessageOptions.uninterpreted_option"
)
// Field numbers for google.protobuf.MessageOptions.
const (
MessageOptions_MessageSetWireFormat_field_number protoreflect.FieldNumber = 1
MessageOptions_NoStandardDescriptorAccessor_field_number protoreflect.FieldNumber = 2
MessageOptions_Deprecated_field_number protoreflect.FieldNumber = 3
MessageOptions_MapEntry_field_number protoreflect.FieldNumber = 7
MessageOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
MessageOptions_MessageSetWireFormat_field_number protoreflect.FieldNumber = 1
MessageOptions_NoStandardDescriptorAccessor_field_number protoreflect.FieldNumber = 2
MessageOptions_Deprecated_field_number protoreflect.FieldNumber = 3
MessageOptions_MapEntry_field_number protoreflect.FieldNumber = 7
MessageOptions_DeprecatedLegacyJsonFieldConflicts_field_number protoreflect.FieldNumber = 11
MessageOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
// Names for google.protobuf.FieldOptions.
@ -528,16 +534,24 @@ const (
FieldOptions_Packed_field_name protoreflect.Name = "packed"
FieldOptions_Jstype_field_name protoreflect.Name = "jstype"
FieldOptions_Lazy_field_name protoreflect.Name = "lazy"
FieldOptions_UnverifiedLazy_field_name protoreflect.Name = "unverified_lazy"
FieldOptions_Deprecated_field_name protoreflect.Name = "deprecated"
FieldOptions_Weak_field_name protoreflect.Name = "weak"
FieldOptions_DebugRedact_field_name protoreflect.Name = "debug_redact"
FieldOptions_Retention_field_name protoreflect.Name = "retention"
FieldOptions_Target_field_name protoreflect.Name = "target"
FieldOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
FieldOptions_Ctype_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.ctype"
FieldOptions_Packed_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.packed"
FieldOptions_Jstype_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.jstype"
FieldOptions_Lazy_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.lazy"
FieldOptions_UnverifiedLazy_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.unverified_lazy"
FieldOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.deprecated"
FieldOptions_Weak_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.weak"
FieldOptions_DebugRedact_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.debug_redact"
FieldOptions_Retention_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.retention"
FieldOptions_Target_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.target"
FieldOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.FieldOptions.uninterpreted_option"
)
@ -547,8 +561,12 @@ const (
FieldOptions_Packed_field_number protoreflect.FieldNumber = 2
FieldOptions_Jstype_field_number protoreflect.FieldNumber = 6
FieldOptions_Lazy_field_number protoreflect.FieldNumber = 5
FieldOptions_UnverifiedLazy_field_number protoreflect.FieldNumber = 15
FieldOptions_Deprecated_field_number protoreflect.FieldNumber = 3
FieldOptions_Weak_field_number protoreflect.FieldNumber = 10
FieldOptions_DebugRedact_field_number protoreflect.FieldNumber = 16
FieldOptions_Retention_field_number protoreflect.FieldNumber = 17
FieldOptions_Target_field_number protoreflect.FieldNumber = 18
FieldOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
@ -564,6 +582,18 @@ const (
FieldOptions_JSType_enum_name = "JSType"
)
// Full and short names for google.protobuf.FieldOptions.OptionRetention.
const (
FieldOptions_OptionRetention_enum_fullname = "google.protobuf.FieldOptions.OptionRetention"
FieldOptions_OptionRetention_enum_name = "OptionRetention"
)
// Full and short names for google.protobuf.FieldOptions.OptionTargetType.
const (
FieldOptions_OptionTargetType_enum_fullname = "google.protobuf.FieldOptions.OptionTargetType"
FieldOptions_OptionTargetType_enum_name = "OptionTargetType"
)
// Names for google.protobuf.OneofOptions.
const (
OneofOptions_message_name protoreflect.Name = "OneofOptions"
@ -590,20 +620,23 @@ const (
// Field names for google.protobuf.EnumOptions.
const (
EnumOptions_AllowAlias_field_name protoreflect.Name = "allow_alias"
EnumOptions_Deprecated_field_name protoreflect.Name = "deprecated"
EnumOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
EnumOptions_AllowAlias_field_name protoreflect.Name = "allow_alias"
EnumOptions_Deprecated_field_name protoreflect.Name = "deprecated"
EnumOptions_DeprecatedLegacyJsonFieldConflicts_field_name protoreflect.Name = "deprecated_legacy_json_field_conflicts"
EnumOptions_UninterpretedOption_field_name protoreflect.Name = "uninterpreted_option"
EnumOptions_AllowAlias_field_fullname protoreflect.FullName = "google.protobuf.EnumOptions.allow_alias"
EnumOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.EnumOptions.deprecated"
EnumOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.EnumOptions.uninterpreted_option"
EnumOptions_AllowAlias_field_fullname protoreflect.FullName = "google.protobuf.EnumOptions.allow_alias"
EnumOptions_Deprecated_field_fullname protoreflect.FullName = "google.protobuf.EnumOptions.deprecated"
EnumOptions_DeprecatedLegacyJsonFieldConflicts_field_fullname protoreflect.FullName = "google.protobuf.EnumOptions.deprecated_legacy_json_field_conflicts"
EnumOptions_UninterpretedOption_field_fullname protoreflect.FullName = "google.protobuf.EnumOptions.uninterpreted_option"
)
// Field numbers for google.protobuf.EnumOptions.
const (
EnumOptions_AllowAlias_field_number protoreflect.FieldNumber = 2
EnumOptions_Deprecated_field_number protoreflect.FieldNumber = 3
EnumOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
EnumOptions_AllowAlias_field_number protoreflect.FieldNumber = 2
EnumOptions_Deprecated_field_number protoreflect.FieldNumber = 3
EnumOptions_DeprecatedLegacyJsonFieldConflicts_field_number protoreflect.FieldNumber = 6
EnumOptions_UninterpretedOption_field_number protoreflect.FieldNumber = 999
)
// Names for google.protobuf.EnumValueOptions.
@ -813,11 +846,13 @@ const (
GeneratedCodeInfo_Annotation_SourceFile_field_name protoreflect.Name = "source_file"
GeneratedCodeInfo_Annotation_Begin_field_name protoreflect.Name = "begin"
GeneratedCodeInfo_Annotation_End_field_name protoreflect.Name = "end"
GeneratedCodeInfo_Annotation_Semantic_field_name protoreflect.Name = "semantic"
GeneratedCodeInfo_Annotation_Path_field_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo.Annotation.path"
GeneratedCodeInfo_Annotation_SourceFile_field_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo.Annotation.source_file"
GeneratedCodeInfo_Annotation_Begin_field_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo.Annotation.begin"
GeneratedCodeInfo_Annotation_End_field_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo.Annotation.end"
GeneratedCodeInfo_Annotation_Semantic_field_fullname protoreflect.FullName = "google.protobuf.GeneratedCodeInfo.Annotation.semantic"
)
// Field numbers for google.protobuf.GeneratedCodeInfo.Annotation.
@ -826,4 +861,11 @@ const (
GeneratedCodeInfo_Annotation_SourceFile_field_number protoreflect.FieldNumber = 2
GeneratedCodeInfo_Annotation_Begin_field_number protoreflect.FieldNumber = 3
GeneratedCodeInfo_Annotation_End_field_number protoreflect.FieldNumber = 4
GeneratedCodeInfo_Annotation_Semantic_field_number protoreflect.FieldNumber = 5
)
// Full and short names for google.protobuf.GeneratedCodeInfo.Annotation.Semantic.
const (
GeneratedCodeInfo_Annotation_Semantic_enum_fullname = "google.protobuf.GeneratedCodeInfo.Annotation.Semantic"
GeneratedCodeInfo_Annotation_Semantic_enum_name = "Semantic"
)

View File

@ -59,7 +59,6 @@ func NewConverter(t reflect.Type, fd protoreflect.FieldDescriptor) Converter {
default:
return newSingularConverter(t, fd)
}
panic(fmt.Sprintf("invalid Go type %v for field %v", t, fd.FullName()))
}
var (

View File

@ -0,0 +1,261 @@
// 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 msgfmt implements a text marshaler combining the desirable features
// of both the JSON and proto text formats.
// It is optimized for human readability and has no associated deserializer.
package msgfmt
import (
"bytes"
"fmt"
"reflect"
"sort"
"strconv"
"strings"
"time"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/internal/detrand"
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/internal/order"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
// Format returns a formatted string for the message.
func Format(m proto.Message) string {
return string(appendMessage(nil, m.ProtoReflect()))
}
// FormatValue returns a formatted string for an arbitrary value.
func FormatValue(v protoreflect.Value, fd protoreflect.FieldDescriptor) string {
return string(appendValue(nil, v, fd))
}
func appendValue(b []byte, v protoreflect.Value, fd protoreflect.FieldDescriptor) []byte {
switch v := v.Interface().(type) {
case nil:
return append(b, "<invalid>"...)
case bool, int32, int64, uint32, uint64, float32, float64:
return append(b, fmt.Sprint(v)...)
case string:
return append(b, strconv.Quote(string(v))...)
case []byte:
return append(b, strconv.Quote(string(v))...)
case protoreflect.EnumNumber:
return appendEnum(b, v, fd)
case protoreflect.Message:
return appendMessage(b, v)
case protoreflect.List:
return appendList(b, v, fd)
case protoreflect.Map:
return appendMap(b, v, fd)
default:
panic(fmt.Sprintf("invalid type: %T", v))
}
}
func appendEnum(b []byte, v protoreflect.EnumNumber, fd protoreflect.FieldDescriptor) []byte {
if fd != nil {
if ev := fd.Enum().Values().ByNumber(v); ev != nil {
return append(b, ev.Name()...)
}
}
return strconv.AppendInt(b, int64(v), 10)
}
func appendMessage(b []byte, m protoreflect.Message) []byte {
if b2 := appendKnownMessage(b, m); b2 != nil {
return b2
}
b = append(b, '{')
order.RangeFields(m, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
b = append(b, fd.TextName()...)
b = append(b, ':')
b = appendValue(b, v, fd)
b = append(b, delim()...)
return true
})
b = appendUnknown(b, m.GetUnknown())
b = bytes.TrimRight(b, delim())
b = append(b, '}')
return b
}
var protocmpMessageType = reflect.TypeOf(map[string]interface{}(nil))
func appendKnownMessage(b []byte, m protoreflect.Message) []byte {
md := m.Descriptor()
fds := md.Fields()
switch md.FullName() {
case genid.Any_message_fullname:
var msgVal protoreflect.Message
url := m.Get(fds.ByNumber(genid.Any_TypeUrl_field_number)).String()
if v := reflect.ValueOf(m); v.Type().ConvertibleTo(protocmpMessageType) {
// For protocmp.Message, directly obtain the sub-message value
// which is stored in structured form, rather than as raw bytes.
m2 := v.Convert(protocmpMessageType).Interface().(map[string]interface{})
v, ok := m2[string(genid.Any_Value_field_name)].(proto.Message)
if !ok {
return nil
}
msgVal = v.ProtoReflect()
} else {
val := m.Get(fds.ByNumber(genid.Any_Value_field_number)).Bytes()
mt, err := protoregistry.GlobalTypes.FindMessageByURL(url)
if err != nil {
return nil
}
msgVal = mt.New()
err = proto.UnmarshalOptions{AllowPartial: true}.Unmarshal(val, msgVal.Interface())
if err != nil {
return nil
}
}
b = append(b, '{')
b = append(b, "["+url+"]"...)
b = append(b, ':')
b = appendMessage(b, msgVal)
b = append(b, '}')
return b
case genid.Timestamp_message_fullname:
secs := m.Get(fds.ByNumber(genid.Timestamp_Seconds_field_number)).Int()
nanos := m.Get(fds.ByNumber(genid.Timestamp_Nanos_field_number)).Int()
if nanos < 0 || nanos >= 1e9 {
return nil
}
t := time.Unix(secs, nanos).UTC()
x := t.Format("2006-01-02T15:04:05.000000000") // RFC 3339
x = strings.TrimSuffix(x, "000")
x = strings.TrimSuffix(x, "000")
x = strings.TrimSuffix(x, ".000")
return append(b, x+"Z"...)
case genid.Duration_message_fullname:
sign := ""
secs := m.Get(fds.ByNumber(genid.Duration_Seconds_field_number)).Int()
nanos := m.Get(fds.ByNumber(genid.Duration_Nanos_field_number)).Int()
if nanos <= -1e9 || nanos >= 1e9 || (secs > 0 && nanos < 0) || (secs < 0 && nanos > 0) {
return nil
}
if secs < 0 || nanos < 0 {
sign, secs, nanos = "-", -1*secs, -1*nanos
}
x := fmt.Sprintf("%s%d.%09d", sign, secs, nanos)
x = strings.TrimSuffix(x, "000")
x = strings.TrimSuffix(x, "000")
x = strings.TrimSuffix(x, ".000")
return append(b, x+"s"...)
case genid.BoolValue_message_fullname,
genid.Int32Value_message_fullname,
genid.Int64Value_message_fullname,
genid.UInt32Value_message_fullname,
genid.UInt64Value_message_fullname,
genid.FloatValue_message_fullname,
genid.DoubleValue_message_fullname,
genid.StringValue_message_fullname,
genid.BytesValue_message_fullname:
fd := fds.ByNumber(genid.WrapperValue_Value_field_number)
return appendValue(b, m.Get(fd), fd)
}
return nil
}
func appendUnknown(b []byte, raw protoreflect.RawFields) []byte {
rs := make(map[protoreflect.FieldNumber][]protoreflect.RawFields)
for len(raw) > 0 {
num, _, n := protowire.ConsumeField(raw)
rs[num] = append(rs[num], raw[:n])
raw = raw[n:]
}
var ns []protoreflect.FieldNumber
for n := range rs {
ns = append(ns, n)
}
sort.Slice(ns, func(i, j int) bool { return ns[i] < ns[j] })
for _, n := range ns {
var leftBracket, rightBracket string
if len(rs[n]) > 1 {
leftBracket, rightBracket = "[", "]"
}
b = strconv.AppendInt(b, int64(n), 10)
b = append(b, ':')
b = append(b, leftBracket...)
for _, r := range rs[n] {
num, typ, n := protowire.ConsumeTag(r)
r = r[n:]
switch typ {
case protowire.VarintType:
v, _ := protowire.ConsumeVarint(r)
b = strconv.AppendInt(b, int64(v), 10)
case protowire.Fixed32Type:
v, _ := protowire.ConsumeFixed32(r)
b = append(b, fmt.Sprintf("0x%08x", v)...)
case protowire.Fixed64Type:
v, _ := protowire.ConsumeFixed64(r)
b = append(b, fmt.Sprintf("0x%016x", v)...)
case protowire.BytesType:
v, _ := protowire.ConsumeBytes(r)
b = strconv.AppendQuote(b, string(v))
case protowire.StartGroupType:
v, _ := protowire.ConsumeGroup(num, r)
b = append(b, '{')
b = appendUnknown(b, v)
b = bytes.TrimRight(b, delim())
b = append(b, '}')
default:
panic(fmt.Sprintf("invalid type: %v", typ))
}
b = append(b, delim()...)
}
b = bytes.TrimRight(b, delim())
b = append(b, rightBracket...)
b = append(b, delim()...)
}
return b
}
func appendList(b []byte, v protoreflect.List, fd protoreflect.FieldDescriptor) []byte {
b = append(b, '[')
for i := 0; i < v.Len(); i++ {
b = appendValue(b, v.Get(i), fd)
b = append(b, delim()...)
}
b = bytes.TrimRight(b, delim())
b = append(b, ']')
return b
}
func appendMap(b []byte, v protoreflect.Map, fd protoreflect.FieldDescriptor) []byte {
b = append(b, '{')
order.RangeEntries(v, order.GenericKeyOrder, func(k protoreflect.MapKey, v protoreflect.Value) bool {
b = appendValue(b, k.Value(), fd.MapKey())
b = append(b, ':')
b = appendValue(b, v, fd.MapValue())
b = append(b, delim()...)
return true
})
b = bytes.TrimRight(b, delim())
b = append(b, '}')
return b
}
func delim() string {
// Deliberately introduce instability into the message string to
// discourage users from depending on it.
if detrand.Bool() {
return " "
}
return ", "
}

View File

@ -87,7 +87,7 @@ func (sb *Builder) grow(n int) {
// Unlike strings.Builder, we do not need to copy over the contents
// of the old buffer since our builder provides no API for
// retrieving previously created strings.
sb.buf = make([]byte, 2*(cap(sb.buf)+n))
sb.buf = make([]byte, 0, 2*(cap(sb.buf)+n))
}
func (sb *Builder) last(n int) string {

View File

@ -51,8 +51,8 @@ import (
// 10. Send out the CL for review and submit it.
const (
Major = 1
Minor = 28
Patch = 1
Minor = 30
Patch = 0
PreRelease = ""
)

View File

@ -5,16 +5,13 @@
// Package proto provides functions operating on protocol buffer messages.
//
// For documentation on protocol buffers in general, see:
//
// https://developers.google.com/protocol-buffers
// https://protobuf.dev.
//
// For a tutorial on using protocol buffers with Go, see:
//
// https://developers.google.com/protocol-buffers/docs/gotutorial
// https://protobuf.dev/getting-started/gotutorial.
//
// For a guide to generated Go protocol buffer code, see:
//
// https://developers.google.com/protocol-buffers/docs/reference/go-generated
// https://protobuf.dev/reference/go/go-generated.
//
// # Binary serialization
//

View File

@ -5,30 +5,39 @@
package proto
import (
"bytes"
"math"
"reflect"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/reflect/protoreflect"
)
// Equal reports whether two messages are equal.
// If two messages marshal to the same bytes under deterministic serialization,
// then Equal is guaranteed to report true.
// Equal reports whether two messages are equal,
// by recursively comparing the fields of the message.
//
// Two messages are equal if they belong to the same message descriptor,
// have the same set of populated known and extension field values,
// and the same set of unknown fields values. If either of the top-level
// messages are invalid, then Equal reports true only if both are invalid.
// - Bytes fields are equal if they contain identical bytes.
// Empty bytes (regardless of nil-ness) are considered equal.
//
// Scalar values are compared with the equivalent of the == operator in Go,
// except bytes values which are compared using bytes.Equal and
// floating point values which specially treat NaNs as equal.
// Message values are compared by recursively calling Equal.
// Lists are equal if each element value is also equal.
// Maps are equal if they have the same set of keys, where the pair of values
// for each key is also equal.
// - Floating-point fields are equal if they contain the same value.
// Unlike the == operator, a NaN is equal to another NaN.
//
// - Other scalar fields are equal if they contain the same value.
//
// - Message fields are equal if they have
// the same set of populated known and extension field values, and
// the same set of unknown fields values.
//
// - Lists are equal if they are the same length and
// each corresponding element is equal.
//
// - Maps are equal if they have the same set of keys and
// the corresponding value for each key is equal.
//
// An invalid message is not equal to a valid message.
// An invalid message is only equal to another invalid message of the
// same type. An invalid message often corresponds to a nil pointer
// of the concrete message type. For example, (*pb.M)(nil) is not equal
// to &pb.M{}.
// If two valid messages marshal to the same bytes under deterministic
// serialization, then Equal is guaranteed to report true.
func Equal(x, y Message) bool {
if x == nil || y == nil {
return x == nil && y == nil
@ -42,130 +51,7 @@ func Equal(x, y Message) bool {
if mx.IsValid() != my.IsValid() {
return false
}
return equalMessage(mx, my)
}
// equalMessage compares two messages.
func equalMessage(mx, my protoreflect.Message) bool {
if mx.Descriptor() != my.Descriptor() {
return false
}
nx := 0
equal := true
mx.Range(func(fd protoreflect.FieldDescriptor, vx protoreflect.Value) bool {
nx++
vy := my.Get(fd)
equal = my.Has(fd) && equalField(fd, vx, vy)
return equal
})
if !equal {
return false
}
ny := 0
my.Range(func(fd protoreflect.FieldDescriptor, vx protoreflect.Value) bool {
ny++
return true
})
if nx != ny {
return false
}
return equalUnknown(mx.GetUnknown(), my.GetUnknown())
}
// equalField compares two fields.
func equalField(fd protoreflect.FieldDescriptor, x, y protoreflect.Value) bool {
switch {
case fd.IsList():
return equalList(fd, x.List(), y.List())
case fd.IsMap():
return equalMap(fd, x.Map(), y.Map())
default:
return equalValue(fd, x, y)
}
}
// equalMap compares two maps.
func equalMap(fd protoreflect.FieldDescriptor, x, y protoreflect.Map) bool {
if x.Len() != y.Len() {
return false
}
equal := true
x.Range(func(k protoreflect.MapKey, vx protoreflect.Value) bool {
vy := y.Get(k)
equal = y.Has(k) && equalValue(fd.MapValue(), vx, vy)
return equal
})
return equal
}
// equalList compares two lists.
func equalList(fd protoreflect.FieldDescriptor, x, y protoreflect.List) bool {
if x.Len() != y.Len() {
return false
}
for i := x.Len() - 1; i >= 0; i-- {
if !equalValue(fd, x.Get(i), y.Get(i)) {
return false
}
}
return true
}
// equalValue compares two singular values.
func equalValue(fd protoreflect.FieldDescriptor, x, y protoreflect.Value) bool {
switch fd.Kind() {
case protoreflect.BoolKind:
return x.Bool() == y.Bool()
case protoreflect.EnumKind:
return x.Enum() == y.Enum()
case protoreflect.Int32Kind, protoreflect.Sint32Kind,
protoreflect.Int64Kind, protoreflect.Sint64Kind,
protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind:
return x.Int() == y.Int()
case protoreflect.Uint32Kind, protoreflect.Uint64Kind,
protoreflect.Fixed32Kind, protoreflect.Fixed64Kind:
return x.Uint() == y.Uint()
case protoreflect.FloatKind, protoreflect.DoubleKind:
fx := x.Float()
fy := y.Float()
if math.IsNaN(fx) || math.IsNaN(fy) {
return math.IsNaN(fx) && math.IsNaN(fy)
}
return fx == fy
case protoreflect.StringKind:
return x.String() == y.String()
case protoreflect.BytesKind:
return bytes.Equal(x.Bytes(), y.Bytes())
case protoreflect.MessageKind, protoreflect.GroupKind:
return equalMessage(x.Message(), y.Message())
default:
return x.Interface() == y.Interface()
}
}
// equalUnknown compares unknown fields by direct comparison on the raw bytes
// of each individual field number.
func equalUnknown(x, y protoreflect.RawFields) bool {
if len(x) != len(y) {
return false
}
if bytes.Equal([]byte(x), []byte(y)) {
return true
}
mx := make(map[protoreflect.FieldNumber]protoreflect.RawFields)
my := make(map[protoreflect.FieldNumber]protoreflect.RawFields)
for len(x) > 0 {
fnum, _, n := protowire.ConsumeField(x)
mx[fnum] = append(mx[fnum], x[:n]...)
x = x[n:]
}
for len(y) > 0 {
fnum, _, n := protowire.ConsumeField(y)
my[fnum] = append(my[fnum], y[:n]...)
y = y[n:]
}
return reflect.DeepEqual(mx, my)
vx := protoreflect.ValueOfMessage(mx)
vy := protoreflect.ValueOfMessage(my)
return vx.Equal(vy)
}

View File

@ -0,0 +1,122 @@
// Copyright 2020 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 protopath provides functionality for
// representing a sequence of protobuf reflection operations on a message.
package protopath
import (
"fmt"
"google.golang.org/protobuf/internal/msgfmt"
"google.golang.org/protobuf/reflect/protoreflect"
)
// NOTE: The Path and Values are separate types here since there are use cases
// where you would like to "address" some value in a message with just the path
// and don't have the value information available.
//
// This is different from how "github.com/google/go-cmp/cmp".Path operates,
// which combines both path and value information together.
// Since the cmp package itself is the only one ever constructing a cmp.Path,
// it will always have the value available.
// Path is a sequence of protobuf reflection steps applied to some root
// protobuf message value to arrive at the current value.
// The first step must be a Root step.
type Path []Step
// TODO: Provide a Parse function that parses something similar to or
// perhaps identical to the output of Path.String.
// Index returns the ith step in the path and supports negative indexing.
// A negative index starts counting from the tail of the Path such that -1
// refers to the last step, -2 refers to the second-to-last step, and so on.
// It returns a zero Step value if the index is out-of-bounds.
func (p Path) Index(i int) Step {
if i < 0 {
i = len(p) + i
}
if i < 0 || i >= len(p) {
return Step{}
}
return p[i]
}
// String returns a structured representation of the path
// by concatenating the string representation of every path step.
func (p Path) String() string {
var b []byte
for _, s := range p {
b = s.appendString(b)
}
return string(b)
}
// Values is a Path paired with a sequence of values at each step.
// The lengths of Path and Values must be identical.
// The first step must be a Root step and
// the first value must be a concrete message value.
type Values struct {
Path Path
Values []protoreflect.Value
}
// Len reports the length of the path and values.
// If the path and values have differing length, it returns the minimum length.
func (p Values) Len() int {
n := len(p.Path)
if n > len(p.Values) {
n = len(p.Values)
}
return n
}
// Index returns the ith step and value and supports negative indexing.
// A negative index starts counting from the tail of the Values such that -1
// refers to the last pair, -2 refers to the second-to-last pair, and so on.
func (p Values) Index(i int) (out struct {
Step Step
Value protoreflect.Value
}) {
// NOTE: This returns a single struct instead of two return values so that
// callers can make use of the the value in an expression:
// vs.Index(i).Value.Interface()
n := p.Len()
if i < 0 {
i = n + i
}
if i < 0 || i >= n {
return out
}
out.Step = p.Path[i]
out.Value = p.Values[i]
return out
}
// String returns a humanly readable representation of the path and last value.
// Do not depend on the output being stable.
//
// For example:
//
// (path.to.MyMessage).list_field[5].map_field["hello"] = {hello: "world"}
func (p Values) String() string {
n := p.Len()
if n == 0 {
return ""
}
// Determine the field descriptor associated with the last step.
var fd protoreflect.FieldDescriptor
last := p.Index(-1)
switch last.Step.kind {
case FieldAccessStep:
fd = last.Step.FieldDescriptor()
case MapIndexStep, ListIndexStep:
fd = p.Index(-2).Step.FieldDescriptor()
}
// Format the full path with the last value.
return fmt.Sprintf("%v = %v", p.Path[:n], msgfmt.FormatValue(last.Value, fd))
}

View File

@ -0,0 +1,241 @@
// Copyright 2020 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 protopath
import (
"fmt"
"strconv"
"strings"
"google.golang.org/protobuf/internal/encoding/text"
"google.golang.org/protobuf/reflect/protoreflect"
)
// StepKind identifies the kind of step operation.
// Each kind of step corresponds with some protobuf reflection operation.
type StepKind int
const (
invalidStep StepKind = iota
// RootStep identifies a step as the Root step operation.
RootStep
// FieldAccessStep identifies a step as the FieldAccess step operation.
FieldAccessStep
// UnknownAccessStep identifies a step as the UnknownAccess step operation.
UnknownAccessStep
// ListIndexStep identifies a step as the ListIndex step operation.
ListIndexStep
// MapIndexStep identifies a step as the MapIndex step operation.
MapIndexStep
// AnyExpandStep identifies a step as the AnyExpand step operation.
AnyExpandStep
)
func (k StepKind) String() string {
switch k {
case invalidStep:
return "<invalid>"
case RootStep:
return "Root"
case FieldAccessStep:
return "FieldAccess"
case UnknownAccessStep:
return "UnknownAccess"
case ListIndexStep:
return "ListIndex"
case MapIndexStep:
return "MapIndex"
case AnyExpandStep:
return "AnyExpand"
default:
return fmt.Sprintf("<unknown:%d>", k)
}
}
// Step is a union where only one step operation may be specified at a time.
// The different kinds of steps are specified by the constants defined for
// the StepKind type.
type Step struct {
kind StepKind
desc protoreflect.Descriptor
key protoreflect.Value
}
// Root indicates the root message that a path is relative to.
// It should always (and only ever) be the first step in a path.
func Root(md protoreflect.MessageDescriptor) Step {
if md == nil {
panic("nil message descriptor")
}
return Step{kind: RootStep, desc: md}
}
// FieldAccess describes access of a field within a message.
// Extension field accesses are also represented using a FieldAccess and
// must be provided with a protoreflect.FieldDescriptor
//
// Within the context of Values,
// the type of the previous step value is always a message, and
// the type of the current step value is determined by the field descriptor.
func FieldAccess(fd protoreflect.FieldDescriptor) Step {
if fd == nil {
panic("nil field descriptor")
} else if _, ok := fd.(protoreflect.ExtensionTypeDescriptor); !ok && fd.IsExtension() {
panic(fmt.Sprintf("extension field %q must implement protoreflect.ExtensionTypeDescriptor", fd.FullName()))
}
return Step{kind: FieldAccessStep, desc: fd}
}
// UnknownAccess describes access to the unknown fields within a message.
//
// Within the context of Values,
// the type of the previous step value is always a message, and
// the type of the current step value is always a bytes type.
func UnknownAccess() Step {
return Step{kind: UnknownAccessStep}
}
// ListIndex describes index of an element within a list.
//
// Within the context of Values,
// the type of the previous, previous step value is always a message,
// the type of the previous step value is always a list, and
// the type of the current step value is determined by the field descriptor.
func ListIndex(i int) Step {
if i < 0 {
panic(fmt.Sprintf("invalid list index: %v", i))
}
return Step{kind: ListIndexStep, key: protoreflect.ValueOfInt64(int64(i))}
}
// MapIndex describes index of an entry within a map.
// The key type is determined by field descriptor that the map belongs to.
//
// Within the context of Values,
// the type of the previous previous step value is always a message,
// the type of the previous step value is always a map, and
// the type of the current step value is determined by the field descriptor.
func MapIndex(k protoreflect.MapKey) Step {
if !k.IsValid() {
panic("invalid map index")
}
return Step{kind: MapIndexStep, key: k.Value()}
}
// AnyExpand describes expansion of a google.protobuf.Any message into
// a structured representation of the underlying message.
//
// Within the context of Values,
// the type of the previous step value is always a google.protobuf.Any message, and
// the type of the current step value is always a message.
func AnyExpand(md protoreflect.MessageDescriptor) Step {
if md == nil {
panic("nil message descriptor")
}
return Step{kind: AnyExpandStep, desc: md}
}
// MessageDescriptor returns the message descriptor for Root or AnyExpand steps,
// otherwise it returns nil.
func (s Step) MessageDescriptor() protoreflect.MessageDescriptor {
switch s.kind {
case RootStep, AnyExpandStep:
return s.desc.(protoreflect.MessageDescriptor)
default:
return nil
}
}
// FieldDescriptor returns the field descriptor for FieldAccess steps,
// otherwise it returns nil.
func (s Step) FieldDescriptor() protoreflect.FieldDescriptor {
switch s.kind {
case FieldAccessStep:
return s.desc.(protoreflect.FieldDescriptor)
default:
return nil
}
}
// ListIndex returns the list index for ListIndex steps,
// otherwise it returns 0.
func (s Step) ListIndex() int {
switch s.kind {
case ListIndexStep:
return int(s.key.Int())
default:
return 0
}
}
// MapIndex returns the map key for MapIndex steps,
// otherwise it returns an invalid map key.
func (s Step) MapIndex() protoreflect.MapKey {
switch s.kind {
case MapIndexStep:
return s.key.MapKey()
default:
return protoreflect.MapKey{}
}
}
// Kind reports which kind of step this is.
func (s Step) Kind() StepKind {
return s.kind
}
func (s Step) String() string {
return string(s.appendString(nil))
}
func (s Step) appendString(b []byte) []byte {
switch s.kind {
case RootStep:
b = append(b, '(')
b = append(b, s.desc.FullName()...)
b = append(b, ')')
case FieldAccessStep:
b = append(b, '.')
if fd := s.desc.(protoreflect.FieldDescriptor); fd.IsExtension() {
b = append(b, '(')
b = append(b, strings.Trim(fd.TextName(), "[]")...)
b = append(b, ')')
} else {
b = append(b, fd.TextName()...)
}
case UnknownAccessStep:
b = append(b, '.')
b = append(b, '?')
case ListIndexStep:
b = append(b, '[')
b = strconv.AppendInt(b, s.key.Int(), 10)
b = append(b, ']')
case MapIndexStep:
b = append(b, '[')
switch k := s.key.Interface().(type) {
case bool:
b = strconv.AppendBool(b, bool(k)) // e.g., "true" or "false"
case int32:
b = strconv.AppendInt(b, int64(k), 10) // e.g., "-32"
case int64:
b = strconv.AppendInt(b, int64(k), 10) // e.g., "-64"
case uint32:
b = strconv.AppendUint(b, uint64(k), 10) // e.g., "32"
case uint64:
b = strconv.AppendUint(b, uint64(k), 10) // e.g., "64"
case string:
b = text.AppendString(b, k) // e.g., `"hello, world"`
}
b = append(b, ']')
case AnyExpandStep:
b = append(b, '.')
b = append(b, '(')
b = append(b, s.desc.FullName()...)
b = append(b, ')')
default:
b = append(b, "<invalid>"...)
}
return b
}

View File

@ -0,0 +1,316 @@
// Copyright 2020 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 protorange provides functionality to traverse a message value.
package protorange
import (
"bytes"
"errors"
"google.golang.org/protobuf/internal/genid"
"google.golang.org/protobuf/internal/order"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/reflect/protopath"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
)
var (
// Break breaks traversal of children in the current value.
// It has no effect when traversing values that are not composite types
// (e.g., messages, lists, and maps).
Break = errors.New("break traversal of children in current value")
// Terminate terminates the entire range operation.
// All necessary Pop operations continue to be called.
Terminate = errors.New("terminate range operation")
)
// Range performs a depth-first traversal over reachable values in a message.
//
// See Options.Range for details.
func Range(m protoreflect.Message, f func(protopath.Values) error) error {
return Options{}.Range(m, f, nil)
}
// Options configures traversal of a message value tree.
type Options struct {
// Stable specifies whether to visit message fields and map entries
// in a stable ordering. If false, then the ordering is undefined and
// may be non-deterministic.
//
// Message fields are visited in ascending order by field number.
// Map entries are visited in ascending order, where
// boolean keys are ordered such that false sorts before true,
// numeric keys are ordered based on the numeric value, and
// string keys are lexicographically ordered by Unicode codepoints.
Stable bool
// Resolver is used for looking up types when expanding google.protobuf.Any
// messages. If nil, this defaults to using protoregistry.GlobalTypes.
// To prevent expansion of Any messages, pass an empty protoregistry.Types:
//
// Options{Resolver: (*protoregistry.Types)(nil)}
//
Resolver interface {
protoregistry.ExtensionTypeResolver
protoregistry.MessageTypeResolver
}
}
// Range performs a depth-first traversal over reachable values in a message.
// The first push and the last pop are to push/pop a protopath.Root step.
// If push or pop return any non-nil error (other than Break or Terminate),
// it terminates the traversal and is returned by Range.
//
// The rules for traversing a message is as follows:
//
// • For messages, iterate over every populated known and extension field.
// Each field is preceded by a push of a protopath.FieldAccess step,
// followed by recursive application of the rules on the field value,
// and succeeded by a pop of that step.
// If the message has unknown fields, then push an protopath.UnknownAccess step
// followed immediately by pop of that step.
//
// • As an exception to the above rule, if the current message is a
// google.protobuf.Any message, expand the underlying message (if resolvable).
// The expanded message is preceded by a push of a protopath.AnyExpand step,
// followed by recursive application of the rules on the underlying message,
// and succeeded by a pop of that step. Mutations to the expanded message
// are written back to the Any message when popping back out.
//
// • For lists, iterate over every element. Each element is preceded by a push
// of a protopath.ListIndex step, followed by recursive application of the rules
// on the list element, and succeeded by a pop of that step.
//
// • For maps, iterate over every entry. Each entry is preceded by a push
// of a protopath.MapIndex step, followed by recursive application of the rules
// on the map entry value, and succeeded by a pop of that step.
//
// Mutations should only be made to the last value, otherwise the effects on
// traversal will be undefined. If the mutation is made to the last value
// during to a push, then the effects of the mutation will affect traversal.
// For example, if the last value is currently a message, and the push function
// populates a few fields in that message, then the newly modified fields
// will be traversed.
//
// The protopath.Values provided to push functions is only valid until the
// corresponding pop call and the values provided to a pop call is only valid
// for the duration of the pop call itself.
func (o Options) Range(m protoreflect.Message, push, pop func(protopath.Values) error) error {
var err error
p := new(protopath.Values)
if o.Resolver == nil {
o.Resolver = protoregistry.GlobalTypes
}
pushStep(p, protopath.Root(m.Descriptor()), protoreflect.ValueOfMessage(m))
if push != nil {
err = amendError(err, push(*p))
}
if err == nil {
err = o.rangeMessage(p, m, push, pop)
}
if pop != nil {
err = amendError(err, pop(*p))
}
popStep(p)
if err == Break || err == Terminate {
err = nil
}
return err
}
func (o Options) rangeMessage(p *protopath.Values, m protoreflect.Message, push, pop func(protopath.Values) error) (err error) {
if ok, err := o.rangeAnyMessage(p, m, push, pop); ok {
return err
}
fieldOrder := order.AnyFieldOrder
if o.Stable {
fieldOrder = order.NumberFieldOrder
}
order.RangeFields(m, fieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
pushStep(p, protopath.FieldAccess(fd), v)
if push != nil {
err = amendError(err, push(*p))
}
if err == nil {
switch {
case fd.IsMap():
err = o.rangeMap(p, fd, v.Map(), push, pop)
case fd.IsList():
err = o.rangeList(p, fd, v.List(), push, pop)
case fd.Message() != nil:
err = o.rangeMessage(p, v.Message(), push, pop)
}
}
if pop != nil {
err = amendError(err, pop(*p))
}
popStep(p)
return err == nil
})
if b := m.GetUnknown(); len(b) > 0 && err == nil {
pushStep(p, protopath.UnknownAccess(), protoreflect.ValueOfBytes(b))
if push != nil {
err = amendError(err, push(*p))
}
if pop != nil {
err = amendError(err, pop(*p))
}
popStep(p)
}
if err == Break {
err = nil
}
return err
}
func (o Options) rangeAnyMessage(p *protopath.Values, m protoreflect.Message, push, pop func(protopath.Values) error) (ok bool, err error) {
md := m.Descriptor()
if md.FullName() != "google.protobuf.Any" {
return false, nil
}
fds := md.Fields()
url := m.Get(fds.ByNumber(genid.Any_TypeUrl_field_number)).String()
val := m.Get(fds.ByNumber(genid.Any_Value_field_number)).Bytes()
mt, errFind := o.Resolver.FindMessageByURL(url)
if errFind != nil {
return false, nil
}
// Unmarshal the raw encoded message value into a structured message value.
m2 := mt.New()
errUnmarshal := proto.UnmarshalOptions{
Merge: true,
AllowPartial: true,
Resolver: o.Resolver,
}.Unmarshal(val, m2.Interface())
if errUnmarshal != nil {
// If the the underlying message cannot be unmarshaled,
// then just treat this as an normal message type.
return false, nil
}
// Marshal Any before ranging to detect possible mutations.
b1, errMarshal := proto.MarshalOptions{
AllowPartial: true,
Deterministic: true,
}.Marshal(m2.Interface())
if errMarshal != nil {
return true, errMarshal
}
pushStep(p, protopath.AnyExpand(m2.Descriptor()), protoreflect.ValueOfMessage(m2))
if push != nil {
err = amendError(err, push(*p))
}
if err == nil {
err = o.rangeMessage(p, m2, push, pop)
}
if pop != nil {
err = amendError(err, pop(*p))
}
popStep(p)
// Marshal Any after ranging to detect possible mutations.
b2, errMarshal := proto.MarshalOptions{
AllowPartial: true,
Deterministic: true,
}.Marshal(m2.Interface())
if errMarshal != nil {
return true, errMarshal
}
// Mutations detected, write the new sequence of bytes to the Any message.
if !bytes.Equal(b1, b2) {
m.Set(fds.ByNumber(genid.Any_Value_field_number), protoreflect.ValueOfBytes(b2))
}
if err == Break {
err = nil
}
return true, err
}
func (o Options) rangeList(p *protopath.Values, fd protoreflect.FieldDescriptor, ls protoreflect.List, push, pop func(protopath.Values) error) (err error) {
for i := 0; i < ls.Len() && err == nil; i++ {
v := ls.Get(i)
pushStep(p, protopath.ListIndex(i), v)
if push != nil {
err = amendError(err, push(*p))
}
if err == nil && fd.Message() != nil {
err = o.rangeMessage(p, v.Message(), push, pop)
}
if pop != nil {
err = amendError(err, pop(*p))
}
popStep(p)
}
if err == Break {
err = nil
}
return err
}
func (o Options) rangeMap(p *protopath.Values, fd protoreflect.FieldDescriptor, ms protoreflect.Map, push, pop func(protopath.Values) error) (err error) {
keyOrder := order.AnyKeyOrder
if o.Stable {
keyOrder = order.GenericKeyOrder
}
order.RangeEntries(ms, keyOrder, func(k protoreflect.MapKey, v protoreflect.Value) bool {
pushStep(p, protopath.MapIndex(k), v)
if push != nil {
err = amendError(err, push(*p))
}
if err == nil && fd.MapValue().Message() != nil {
err = o.rangeMessage(p, v.Message(), push, pop)
}
if pop != nil {
err = amendError(err, pop(*p))
}
popStep(p)
return err == nil
})
if err == Break {
err = nil
}
return err
}
func pushStep(p *protopath.Values, s protopath.Step, v protoreflect.Value) {
p.Path = append(p.Path, s)
p.Values = append(p.Values, v)
}
func popStep(p *protopath.Values) {
p.Path = p.Path[:len(p.Path)-1]
p.Values = p.Values[:len(p.Values)-1]
}
// amendError amends the previous error with the current error if it is
// considered more serious. The precedence order for errors is:
//
// nil < Break < Terminate < previous non-nil < current non-nil
func amendError(prev, curr error) error {
switch {
case curr == nil:
return prev
case curr == Break && prev != nil:
return prev
case curr == Terminate && prev != nil && prev != Break:
return prev
default:
return curr
}
}

View File

@ -35,6 +35,8 @@ func (p *SourcePath) appendFileDescriptorProto(b []byte) []byte {
b = p.appendSingularField(b, "source_code_info", (*SourcePath).appendSourceCodeInfo)
case 12:
b = p.appendSingularField(b, "syntax", nil)
case 13:
b = p.appendSingularField(b, "edition", nil)
}
return b
}
@ -236,6 +238,8 @@ func (p *SourcePath) appendMessageOptions(b []byte) []byte {
b = p.appendSingularField(b, "deprecated", nil)
case 7:
b = p.appendSingularField(b, "map_entry", nil)
case 11:
b = p.appendSingularField(b, "deprecated_legacy_json_field_conflicts", nil)
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}
@ -279,6 +283,8 @@ func (p *SourcePath) appendEnumOptions(b []byte) []byte {
b = p.appendSingularField(b, "allow_alias", nil)
case 3:
b = p.appendSingularField(b, "deprecated", nil)
case 6:
b = p.appendSingularField(b, "deprecated_legacy_json_field_conflicts", nil)
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}
@ -345,10 +351,18 @@ func (p *SourcePath) appendFieldOptions(b []byte) []byte {
b = p.appendSingularField(b, "jstype", nil)
case 5:
b = p.appendSingularField(b, "lazy", nil)
case 15:
b = p.appendSingularField(b, "unverified_lazy", nil)
case 3:
b = p.appendSingularField(b, "deprecated", nil)
case 10:
b = p.appendSingularField(b, "weak", nil)
case 16:
b = p.appendSingularField(b, "debug_redact", nil)
case 17:
b = p.appendSingularField(b, "retention", nil)
case 18:
b = p.appendSingularField(b, "target", nil)
case 999:
b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption)
}

View File

@ -148,7 +148,7 @@ type Message interface {
// be preserved in marshaling or other operations.
IsValid() bool
// ProtoMethods returns optional fast-path implementions of various operations.
// ProtoMethods returns optional fast-path implementations of various operations.
// This method may return nil.
//
// The returned methods type is identical to

View File

@ -0,0 +1,168 @@
// Copyright 2022 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 protoreflect
import (
"bytes"
"fmt"
"math"
"reflect"
"google.golang.org/protobuf/encoding/protowire"
)
// Equal reports whether v1 and v2 are recursively equal.
//
// - Values of different types are always unequal.
//
// - Bytes values are equal if they contain identical bytes.
// Empty bytes (regardless of nil-ness) are considered equal.
//
// - Floating point values are equal if they contain the same value.
// Unlike the == operator, a NaN is equal to another NaN.
//
// - Enums are equal if they contain the same number.
// Since Value does not contain an enum descriptor,
// enum values do not consider the type of the enum.
//
// - Other scalar values are equal if they contain the same value.
//
// - Message values are equal if they belong to the same message descriptor,
// have the same set of populated known and extension field values,
// and the same set of unknown fields values.
//
// - Lists are equal if they are the same length and
// each corresponding element is equal.
//
// - Maps are equal if they have the same set of keys and
// the corresponding value for each key is equal.
func (v1 Value) Equal(v2 Value) bool {
return equalValue(v1, v2)
}
func equalValue(x, y Value) bool {
eqType := x.typ == y.typ
switch x.typ {
case nilType:
return eqType
case boolType:
return eqType && x.Bool() == y.Bool()
case int32Type, int64Type:
return eqType && x.Int() == y.Int()
case uint32Type, uint64Type:
return eqType && x.Uint() == y.Uint()
case float32Type, float64Type:
return eqType && equalFloat(x.Float(), y.Float())
case stringType:
return eqType && x.String() == y.String()
case bytesType:
return eqType && bytes.Equal(x.Bytes(), y.Bytes())
case enumType:
return eqType && x.Enum() == y.Enum()
default:
switch x := x.Interface().(type) {
case Message:
y, ok := y.Interface().(Message)
return ok && equalMessage(x, y)
case List:
y, ok := y.Interface().(List)
return ok && equalList(x, y)
case Map:
y, ok := y.Interface().(Map)
return ok && equalMap(x, y)
default:
panic(fmt.Sprintf("unknown type: %T", x))
}
}
}
// equalFloat compares two floats, where NaNs are treated as equal.
func equalFloat(x, y float64) bool {
if math.IsNaN(x) || math.IsNaN(y) {
return math.IsNaN(x) && math.IsNaN(y)
}
return x == y
}
// equalMessage compares two messages.
func equalMessage(mx, my Message) bool {
if mx.Descriptor() != my.Descriptor() {
return false
}
nx := 0
equal := true
mx.Range(func(fd FieldDescriptor, vx Value) bool {
nx++
vy := my.Get(fd)
equal = my.Has(fd) && equalValue(vx, vy)
return equal
})
if !equal {
return false
}
ny := 0
my.Range(func(fd FieldDescriptor, vx Value) bool {
ny++
return true
})
if nx != ny {
return false
}
return equalUnknown(mx.GetUnknown(), my.GetUnknown())
}
// equalList compares two lists.
func equalList(x, y List) bool {
if x.Len() != y.Len() {
return false
}
for i := x.Len() - 1; i >= 0; i-- {
if !equalValue(x.Get(i), y.Get(i)) {
return false
}
}
return true
}
// equalMap compares two maps.
func equalMap(x, y Map) bool {
if x.Len() != y.Len() {
return false
}
equal := true
x.Range(func(k MapKey, vx Value) bool {
vy := y.Get(k)
equal = y.Has(k) && equalValue(vx, vy)
return equal
})
return equal
}
// equalUnknown compares unknown fields by direct comparison on the raw bytes
// of each individual field number.
func equalUnknown(x, y RawFields) bool {
if len(x) != len(y) {
return false
}
if bytes.Equal([]byte(x), []byte(y)) {
return true
}
mx := make(map[FieldNumber]RawFields)
my := make(map[FieldNumber]RawFields)
for len(x) > 0 {
fnum, _, n := protowire.ConsumeField(x)
mx[fnum] = append(mx[fnum], x[:n]...)
x = x[n:]
}
for len(y) > 0 {
fnum, _, n := protowire.ConsumeField(y)
my[fnum] = append(my[fnum], y[:n]...)
y = y[n:]
}
return reflect.DeepEqual(mx, my)
}

View File

@ -54,11 +54,11 @@ import (
// // Append a 0 to a "repeated int32" field.
// // Since the Value returned by Mutable is guaranteed to alias
// // the source message, modifying the Value modifies the message.
// message.Mutable(fieldDesc).(List).Append(protoreflect.ValueOfInt32(0))
// message.Mutable(fieldDesc).List().Append(protoreflect.ValueOfInt32(0))
//
// // Assign [0] to a "repeated int32" field by creating a new Value,
// // modifying it, and assigning it.
// list := message.NewField(fieldDesc).(List)
// list := message.NewField(fieldDesc).List()
// list.Append(protoreflect.ValueOfInt32(0))
// message.Set(fieldDesc, list)
// // ERROR: Since it is not defined whether Set aliases the source,

View File

@ -46,7 +46,7 @@ var conflictPolicy = "panic" // "panic" | "warn" | "ignore"
// It is a variable so that the behavior is easily overridden in another file.
var ignoreConflict = func(d protoreflect.Descriptor, err error) bool {
const env = "GOLANG_PROTOBUF_REGISTRATION_CONFLICT"
const faq = "https://developers.google.com/protocol-buffers/docs/reference/go/faq#namespace-conflict"
const faq = "https://protobuf.dev/reference/go/faq#namespace-conflict"
policy := conflictPolicy
if v := os.Getenv(env); v != "" {
policy = v

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,717 @@
// 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 dynamicpb creates protocol buffer messages using runtime type information.
package dynamicpb
import (
"math"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoiface"
"google.golang.org/protobuf/runtime/protoimpl"
)
// enum is a dynamic protoreflect.Enum.
type enum struct {
num protoreflect.EnumNumber
typ protoreflect.EnumType
}
func (e enum) Descriptor() protoreflect.EnumDescriptor { return e.typ.Descriptor() }
func (e enum) Type() protoreflect.EnumType { return e.typ }
func (e enum) Number() protoreflect.EnumNumber { return e.num }
// enumType is a dynamic protoreflect.EnumType.
type enumType struct {
desc protoreflect.EnumDescriptor
}
// NewEnumType creates a new EnumType with the provided descriptor.
//
// EnumTypes created by this package are equal if their descriptors are equal.
// That is, if ed1 == ed2, then NewEnumType(ed1) == NewEnumType(ed2).
//
// Enum values created by the EnumType are equal if their numbers are equal.
func NewEnumType(desc protoreflect.EnumDescriptor) protoreflect.EnumType {
return enumType{desc}
}
func (et enumType) New(n protoreflect.EnumNumber) protoreflect.Enum { return enum{n, et} }
func (et enumType) Descriptor() protoreflect.EnumDescriptor { return et.desc }
// extensionType is a dynamic protoreflect.ExtensionType.
type extensionType struct {
desc extensionTypeDescriptor
}
// A Message is a dynamically constructed protocol buffer message.
//
// Message implements the proto.Message interface, and may be used with all
// standard proto package functions such as Marshal, Unmarshal, and so forth.
//
// Message also implements the protoreflect.Message interface. See the protoreflect
// package documentation for that interface for how to get and set fields and
// otherwise interact with the contents of a Message.
//
// Reflection API functions which construct messages, such as NewField,
// return new dynamic messages of the appropriate type. Functions which take
// messages, such as Set for a message-value field, will accept any message
// with a compatible type.
//
// Operations which modify a Message are not safe for concurrent use.
type Message struct {
typ messageType
known map[protoreflect.FieldNumber]protoreflect.Value
ext map[protoreflect.FieldNumber]protoreflect.FieldDescriptor
unknown protoreflect.RawFields
}
var (
_ protoreflect.Message = (*Message)(nil)
_ protoreflect.ProtoMessage = (*Message)(nil)
_ protoiface.MessageV1 = (*Message)(nil)
)
// NewMessage creates a new message with the provided descriptor.
func NewMessage(desc protoreflect.MessageDescriptor) *Message {
return &Message{
typ: messageType{desc},
known: make(map[protoreflect.FieldNumber]protoreflect.Value),
ext: make(map[protoreflect.FieldNumber]protoreflect.FieldDescriptor),
}
}
// ProtoMessage implements the legacy message interface.
func (m *Message) ProtoMessage() {}
// ProtoReflect implements the protoreflect.ProtoMessage interface.
func (m *Message) ProtoReflect() protoreflect.Message {
return m
}
// String returns a string representation of a message.
func (m *Message) String() string {
return protoimpl.X.MessageStringOf(m)
}
// Reset clears the message to be empty, but preserves the dynamic message type.
func (m *Message) Reset() {
m.known = make(map[protoreflect.FieldNumber]protoreflect.Value)
m.ext = make(map[protoreflect.FieldNumber]protoreflect.FieldDescriptor)
m.unknown = nil
}
// Descriptor returns the message descriptor.
func (m *Message) Descriptor() protoreflect.MessageDescriptor {
return m.typ.desc
}
// Type returns the message type.
func (m *Message) Type() protoreflect.MessageType {
return m.typ
}
// New returns a newly allocated empty message with the same descriptor.
// See protoreflect.Message for details.
func (m *Message) New() protoreflect.Message {
return m.Type().New()
}
// Interface returns the message.
// See protoreflect.Message for details.
func (m *Message) Interface() protoreflect.ProtoMessage {
return m
}
// ProtoMethods is an internal detail of the protoreflect.Message interface.
// Users should never call this directly.
func (m *Message) ProtoMethods() *protoiface.Methods {
return nil
}
// Range visits every populated field in undefined order.
// See protoreflect.Message for details.
func (m *Message) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
for num, v := range m.known {
fd := m.ext[num]
if fd == nil {
fd = m.Descriptor().Fields().ByNumber(num)
}
if !isSet(fd, v) {
continue
}
if !f(fd, v) {
return
}
}
}
// Has reports whether a field is populated.
// See protoreflect.Message for details.
func (m *Message) Has(fd protoreflect.FieldDescriptor) bool {
m.checkField(fd)
if fd.IsExtension() && m.ext[fd.Number()] != fd {
return false
}
v, ok := m.known[fd.Number()]
if !ok {
return false
}
return isSet(fd, v)
}
// Clear clears a field.
// See protoreflect.Message for details.
func (m *Message) Clear(fd protoreflect.FieldDescriptor) {
m.checkField(fd)
num := fd.Number()
delete(m.known, num)
delete(m.ext, num)
}
// Get returns the value of a field.
// See protoreflect.Message for details.
func (m *Message) Get(fd protoreflect.FieldDescriptor) protoreflect.Value {
m.checkField(fd)
num := fd.Number()
if fd.IsExtension() {
if fd != m.ext[num] {
return fd.(protoreflect.ExtensionTypeDescriptor).Type().Zero()
}
return m.known[num]
}
if v, ok := m.known[num]; ok {
switch {
case fd.IsMap():
if v.Map().Len() > 0 {
return v
}
case fd.IsList():
if v.List().Len() > 0 {
return v
}
default:
return v
}
}
switch {
case fd.IsMap():
return protoreflect.ValueOfMap(&dynamicMap{desc: fd})
case fd.IsList():
return protoreflect.ValueOfList(emptyList{desc: fd})
case fd.Message() != nil:
return protoreflect.ValueOfMessage(&Message{typ: messageType{fd.Message()}})
case fd.Kind() == protoreflect.BytesKind:
return protoreflect.ValueOfBytes(append([]byte(nil), fd.Default().Bytes()...))
default:
return fd.Default()
}
}
// Mutable returns a mutable reference to a repeated, map, or message field.
// See protoreflect.Message for details.
func (m *Message) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value {
m.checkField(fd)
if !fd.IsMap() && !fd.IsList() && fd.Message() == nil {
panic(errors.New("%v: getting mutable reference to non-composite type", fd.FullName()))
}
if m.known == nil {
panic(errors.New("%v: modification of read-only message", fd.FullName()))
}
num := fd.Number()
if fd.IsExtension() {
if fd != m.ext[num] {
m.ext[num] = fd
m.known[num] = fd.(protoreflect.ExtensionTypeDescriptor).Type().New()
}
return m.known[num]
}
if v, ok := m.known[num]; ok {
return v
}
m.clearOtherOneofFields(fd)
m.known[num] = m.NewField(fd)
if fd.IsExtension() {
m.ext[num] = fd
}
return m.known[num]
}
// Set stores a value in a field.
// See protoreflect.Message for details.
func (m *Message) Set(fd protoreflect.FieldDescriptor, v protoreflect.Value) {
m.checkField(fd)
if m.known == nil {
panic(errors.New("%v: modification of read-only message", fd.FullName()))
}
if fd.IsExtension() {
isValid := true
switch {
case !fd.(protoreflect.ExtensionTypeDescriptor).Type().IsValidValue(v):
isValid = false
case fd.IsList():
isValid = v.List().IsValid()
case fd.IsMap():
isValid = v.Map().IsValid()
case fd.Message() != nil:
isValid = v.Message().IsValid()
}
if !isValid {
panic(errors.New("%v: assigning invalid type %T", fd.FullName(), v.Interface()))
}
m.ext[fd.Number()] = fd
} else {
typecheck(fd, v)
}
m.clearOtherOneofFields(fd)
m.known[fd.Number()] = v
}
func (m *Message) clearOtherOneofFields(fd protoreflect.FieldDescriptor) {
od := fd.ContainingOneof()
if od == nil {
return
}
num := fd.Number()
for i := 0; i < od.Fields().Len(); i++ {
if n := od.Fields().Get(i).Number(); n != num {
delete(m.known, n)
}
}
}
// NewField returns a new value for assignable to the field of a given descriptor.
// See protoreflect.Message for details.
func (m *Message) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value {
m.checkField(fd)
switch {
case fd.IsExtension():
return fd.(protoreflect.ExtensionTypeDescriptor).Type().New()
case fd.IsMap():
return protoreflect.ValueOfMap(&dynamicMap{
desc: fd,
mapv: make(map[interface{}]protoreflect.Value),
})
case fd.IsList():
return protoreflect.ValueOfList(&dynamicList{desc: fd})
case fd.Message() != nil:
return protoreflect.ValueOfMessage(NewMessage(fd.Message()).ProtoReflect())
default:
return fd.Default()
}
}
// WhichOneof reports which field in a oneof is populated, returning nil if none are populated.
// See protoreflect.Message for details.
func (m *Message) WhichOneof(od protoreflect.OneofDescriptor) protoreflect.FieldDescriptor {
for i := 0; i < od.Fields().Len(); i++ {
fd := od.Fields().Get(i)
if m.Has(fd) {
return fd
}
}
return nil
}
// GetUnknown returns the raw unknown fields.
// See protoreflect.Message for details.
func (m *Message) GetUnknown() protoreflect.RawFields {
return m.unknown
}
// SetUnknown sets the raw unknown fields.
// See protoreflect.Message for details.
func (m *Message) SetUnknown(r protoreflect.RawFields) {
if m.known == nil {
panic(errors.New("%v: modification of read-only message", m.typ.desc.FullName()))
}
m.unknown = r
}
// IsValid reports whether the message is valid.
// See protoreflect.Message for details.
func (m *Message) IsValid() bool {
return m.known != nil
}
func (m *Message) checkField(fd protoreflect.FieldDescriptor) {
if fd.IsExtension() && fd.ContainingMessage().FullName() == m.Descriptor().FullName() {
if _, ok := fd.(protoreflect.ExtensionTypeDescriptor); !ok {
panic(errors.New("%v: extension field descriptor does not implement ExtensionTypeDescriptor", fd.FullName()))
}
return
}
if fd.Parent() == m.Descriptor() {
return
}
fields := m.Descriptor().Fields()
index := fd.Index()
if index >= fields.Len() || fields.Get(index) != fd {
panic(errors.New("%v: field descriptor does not belong to this message", fd.FullName()))
}
}
type messageType struct {
desc protoreflect.MessageDescriptor
}
// NewMessageType creates a new MessageType with the provided descriptor.
//
// MessageTypes created by this package are equal if their descriptors are equal.
// That is, if md1 == md2, then NewMessageType(md1) == NewMessageType(md2).
func NewMessageType(desc protoreflect.MessageDescriptor) protoreflect.MessageType {
return messageType{desc}
}
func (mt messageType) New() protoreflect.Message { return NewMessage(mt.desc) }
func (mt messageType) Zero() protoreflect.Message { return &Message{typ: messageType{mt.desc}} }
func (mt messageType) Descriptor() protoreflect.MessageDescriptor { return mt.desc }
func (mt messageType) Enum(i int) protoreflect.EnumType {
if ed := mt.desc.Fields().Get(i).Enum(); ed != nil {
return NewEnumType(ed)
}
return nil
}
func (mt messageType) Message(i int) protoreflect.MessageType {
if md := mt.desc.Fields().Get(i).Message(); md != nil {
return NewMessageType(md)
}
return nil
}
type emptyList struct {
desc protoreflect.FieldDescriptor
}
func (x emptyList) Len() int { return 0 }
func (x emptyList) Get(n int) protoreflect.Value { panic(errors.New("out of range")) }
func (x emptyList) Set(n int, v protoreflect.Value) {
panic(errors.New("modification of immutable list"))
}
func (x emptyList) Append(v protoreflect.Value) { panic(errors.New("modification of immutable list")) }
func (x emptyList) AppendMutable() protoreflect.Value {
panic(errors.New("modification of immutable list"))
}
func (x emptyList) Truncate(n int) { panic(errors.New("modification of immutable list")) }
func (x emptyList) NewElement() protoreflect.Value { return newListEntry(x.desc) }
func (x emptyList) IsValid() bool { return false }
type dynamicList struct {
desc protoreflect.FieldDescriptor
list []protoreflect.Value
}
func (x *dynamicList) Len() int {
return len(x.list)
}
func (x *dynamicList) Get(n int) protoreflect.Value {
return x.list[n]
}
func (x *dynamicList) Set(n int, v protoreflect.Value) {
typecheckSingular(x.desc, v)
x.list[n] = v
}
func (x *dynamicList) Append(v protoreflect.Value) {
typecheckSingular(x.desc, v)
x.list = append(x.list, v)
}
func (x *dynamicList) AppendMutable() protoreflect.Value {
if x.desc.Message() == nil {
panic(errors.New("%v: invalid AppendMutable on list with non-message type", x.desc.FullName()))
}
v := x.NewElement()
x.Append(v)
return v
}
func (x *dynamicList) Truncate(n int) {
// Zero truncated elements to avoid keeping data live.
for i := n; i < len(x.list); i++ {
x.list[i] = protoreflect.Value{}
}
x.list = x.list[:n]
}
func (x *dynamicList) NewElement() protoreflect.Value {
return newListEntry(x.desc)
}
func (x *dynamicList) IsValid() bool {
return true
}
type dynamicMap struct {
desc protoreflect.FieldDescriptor
mapv map[interface{}]protoreflect.Value
}
func (x *dynamicMap) Get(k protoreflect.MapKey) protoreflect.Value { return x.mapv[k.Interface()] }
func (x *dynamicMap) Set(k protoreflect.MapKey, v protoreflect.Value) {
typecheckSingular(x.desc.MapKey(), k.Value())
typecheckSingular(x.desc.MapValue(), v)
x.mapv[k.Interface()] = v
}
func (x *dynamicMap) Has(k protoreflect.MapKey) bool { return x.Get(k).IsValid() }
func (x *dynamicMap) Clear(k protoreflect.MapKey) { delete(x.mapv, k.Interface()) }
func (x *dynamicMap) Mutable(k protoreflect.MapKey) protoreflect.Value {
if x.desc.MapValue().Message() == nil {
panic(errors.New("%v: invalid Mutable on map with non-message value type", x.desc.FullName()))
}
v := x.Get(k)
if !v.IsValid() {
v = x.NewValue()
x.Set(k, v)
}
return v
}
func (x *dynamicMap) Len() int { return len(x.mapv) }
func (x *dynamicMap) NewValue() protoreflect.Value {
if md := x.desc.MapValue().Message(); md != nil {
return protoreflect.ValueOfMessage(NewMessage(md).ProtoReflect())
}
return x.desc.MapValue().Default()
}
func (x *dynamicMap) IsValid() bool {
return x.mapv != nil
}
func (x *dynamicMap) Range(f func(protoreflect.MapKey, protoreflect.Value) bool) {
for k, v := range x.mapv {
if !f(protoreflect.ValueOf(k).MapKey(), v) {
return
}
}
}
func isSet(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
switch {
case fd.IsMap():
return v.Map().Len() > 0
case fd.IsList():
return v.List().Len() > 0
case fd.ContainingOneof() != nil:
return true
case fd.Syntax() == protoreflect.Proto3 && !fd.IsExtension():
switch fd.Kind() {
case protoreflect.BoolKind:
return v.Bool()
case protoreflect.EnumKind:
return v.Enum() != 0
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind:
return v.Int() != 0
case protoreflect.Uint32Kind, protoreflect.Uint64Kind, protoreflect.Fixed32Kind, protoreflect.Fixed64Kind:
return v.Uint() != 0
case protoreflect.FloatKind, protoreflect.DoubleKind:
return v.Float() != 0 || math.Signbit(v.Float())
case protoreflect.StringKind:
return v.String() != ""
case protoreflect.BytesKind:
return len(v.Bytes()) > 0
}
}
return true
}
func typecheck(fd protoreflect.FieldDescriptor, v protoreflect.Value) {
if err := typeIsValid(fd, v); err != nil {
panic(err)
}
}
func typeIsValid(fd protoreflect.FieldDescriptor, v protoreflect.Value) error {
switch {
case !v.IsValid():
return errors.New("%v: assigning invalid value", fd.FullName())
case fd.IsMap():
if mapv, ok := v.Interface().(*dynamicMap); !ok || mapv.desc != fd || !mapv.IsValid() {
return errors.New("%v: assigning invalid type %T", fd.FullName(), v.Interface())
}
return nil
case fd.IsList():
switch list := v.Interface().(type) {
case *dynamicList:
if list.desc == fd && list.IsValid() {
return nil
}
case emptyList:
if list.desc == fd && list.IsValid() {
return nil
}
}
return errors.New("%v: assigning invalid type %T", fd.FullName(), v.Interface())
default:
return singularTypeIsValid(fd, v)
}
}
func typecheckSingular(fd protoreflect.FieldDescriptor, v protoreflect.Value) {
if err := singularTypeIsValid(fd, v); err != nil {
panic(err)
}
}
func singularTypeIsValid(fd protoreflect.FieldDescriptor, v protoreflect.Value) error {
vi := v.Interface()
var ok bool
switch fd.Kind() {
case protoreflect.BoolKind:
_, ok = vi.(bool)
case protoreflect.EnumKind:
// We could check against the valid set of enum values, but do not.
_, ok = vi.(protoreflect.EnumNumber)
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
_, ok = vi.(int32)
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
_, ok = vi.(uint32)
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
_, ok = vi.(int64)
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
_, ok = vi.(uint64)
case protoreflect.FloatKind:
_, ok = vi.(float32)
case protoreflect.DoubleKind:
_, ok = vi.(float64)
case protoreflect.StringKind:
_, ok = vi.(string)
case protoreflect.BytesKind:
_, ok = vi.([]byte)
case protoreflect.MessageKind, protoreflect.GroupKind:
var m protoreflect.Message
m, ok = vi.(protoreflect.Message)
if ok && m.Descriptor().FullName() != fd.Message().FullName() {
return errors.New("%v: assigning invalid message type %v", fd.FullName(), m.Descriptor().FullName())
}
if dm, ok := vi.(*Message); ok && dm.known == nil {
return errors.New("%v: assigning invalid zero-value message", fd.FullName())
}
}
if !ok {
return errors.New("%v: assigning invalid type %T", fd.FullName(), v.Interface())
}
return nil
}
func newListEntry(fd protoreflect.FieldDescriptor) protoreflect.Value {
switch fd.Kind() {
case protoreflect.BoolKind:
return protoreflect.ValueOfBool(false)
case protoreflect.EnumKind:
return protoreflect.ValueOfEnum(fd.Enum().Values().Get(0).Number())
case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
return protoreflect.ValueOfInt32(0)
case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
return protoreflect.ValueOfUint32(0)
case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
return protoreflect.ValueOfInt64(0)
case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
return protoreflect.ValueOfUint64(0)
case protoreflect.FloatKind:
return protoreflect.ValueOfFloat32(0)
case protoreflect.DoubleKind:
return protoreflect.ValueOfFloat64(0)
case protoreflect.StringKind:
return protoreflect.ValueOfString("")
case protoreflect.BytesKind:
return protoreflect.ValueOfBytes(nil)
case protoreflect.MessageKind, protoreflect.GroupKind:
return protoreflect.ValueOfMessage(NewMessage(fd.Message()).ProtoReflect())
}
panic(errors.New("%v: unknown kind %v", fd.FullName(), fd.Kind()))
}
// NewExtensionType creates a new ExtensionType with the provided descriptor.
//
// Dynamic ExtensionTypes with the same descriptor compare as equal. That is,
// if xd1 == xd2, then NewExtensionType(xd1) == NewExtensionType(xd2).
//
// The InterfaceOf and ValueOf methods of the extension type are defined as:
//
// func (xt extensionType) ValueOf(iv interface{}) protoreflect.Value {
// return protoreflect.ValueOf(iv)
// }
//
// func (xt extensionType) InterfaceOf(v protoreflect.Value) interface{} {
// return v.Interface()
// }
//
// The Go type used by the proto.GetExtension and proto.SetExtension functions
// is determined by these methods, and is therefore equivalent to the Go type
// used to represent a protoreflect.Value. See the protoreflect.Value
// documentation for more details.
func NewExtensionType(desc protoreflect.ExtensionDescriptor) protoreflect.ExtensionType {
if xt, ok := desc.(protoreflect.ExtensionTypeDescriptor); ok {
desc = xt.Descriptor()
}
return extensionType{extensionTypeDescriptor{desc}}
}
func (xt extensionType) New() protoreflect.Value {
switch {
case xt.desc.IsMap():
return protoreflect.ValueOfMap(&dynamicMap{
desc: xt.desc,
mapv: make(map[interface{}]protoreflect.Value),
})
case xt.desc.IsList():
return protoreflect.ValueOfList(&dynamicList{desc: xt.desc})
case xt.desc.Message() != nil:
return protoreflect.ValueOfMessage(NewMessage(xt.desc.Message()))
default:
return xt.desc.Default()
}
}
func (xt extensionType) Zero() protoreflect.Value {
switch {
case xt.desc.IsMap():
return protoreflect.ValueOfMap(&dynamicMap{desc: xt.desc})
case xt.desc.Cardinality() == protoreflect.Repeated:
return protoreflect.ValueOfList(emptyList{desc: xt.desc})
case xt.desc.Message() != nil:
return protoreflect.ValueOfMessage(&Message{typ: messageType{xt.desc.Message()}})
default:
return xt.desc.Default()
}
}
func (xt extensionType) TypeDescriptor() protoreflect.ExtensionTypeDescriptor {
return xt.desc
}
func (xt extensionType) ValueOf(iv interface{}) protoreflect.Value {
v := protoreflect.ValueOf(iv)
typecheck(xt.desc, v)
return v
}
func (xt extensionType) InterfaceOf(v protoreflect.Value) interface{} {
typecheck(xt.desc, v)
return v.Interface()
}
func (xt extensionType) IsValidInterface(iv interface{}) bool {
return typeIsValid(xt.desc, protoreflect.ValueOf(iv)) == nil
}
func (xt extensionType) IsValidValue(v protoreflect.Value) bool {
return typeIsValid(xt.desc, v) == nil
}
type extensionTypeDescriptor struct {
protoreflect.ExtensionDescriptor
}
func (xt extensionTypeDescriptor) Type() protoreflect.ExtensionType {
return extensionType{xt}
}
func (xt extensionTypeDescriptor) Descriptor() protoreflect.ExtensionDescriptor {
return xt.ExtensionDescriptor
}

View File

@ -37,8 +37,7 @@
// It is functionally a tuple of the full name of the remote message type and
// the serialized bytes of the remote message value.
//
//
// Constructing an Any
// # Constructing an Any
//
// An Any message containing another message value is constructed using New:
//
@ -48,8 +47,7 @@
// }
// ... // make use of any
//
//
// Unmarshaling an Any
// # Unmarshaling an Any
//
// With a populated Any message, the underlying message can be serialized into
// a remote concrete message value in a few ways.
@ -95,8 +93,7 @@
// listed in the case clauses are linked into the Go binary and therefore also
// registered in the global registry.
//
//
// Type checking an Any
// # Type checking an Any
//
// In order to type check whether an Any message represents some other message,
// then use the MessageIs method:
@ -115,7 +112,6 @@
// }
// ... // make use of m
// }
//
package anypb
import (
@ -136,45 +132,49 @@ import (
//
// Example 1: Pack and unpack a message in C++.
//
// Foo foo = ...;
// Any any;
// any.PackFrom(foo);
// ...
// if (any.UnpackTo(&foo)) {
// ...
// }
// Foo foo = ...;
// Any any;
// any.PackFrom(foo);
// ...
// if (any.UnpackTo(&foo)) {
// ...
// }
//
// Example 2: Pack and unpack a message in Java.
//
// Foo foo = ...;
// Any any = Any.pack(foo);
// ...
// if (any.is(Foo.class)) {
// foo = any.unpack(Foo.class);
// }
// Foo foo = ...;
// Any any = Any.pack(foo);
// ...
// if (any.is(Foo.class)) {
// foo = any.unpack(Foo.class);
// }
// // or ...
// if (any.isSameTypeAs(Foo.getDefaultInstance())) {
// foo = any.unpack(Foo.getDefaultInstance());
// }
//
// Example 3: Pack and unpack a message in Python.
// Example 3: Pack and unpack a message in Python.
//
// foo = Foo(...)
// any = Any()
// any.Pack(foo)
// ...
// if any.Is(Foo.DESCRIPTOR):
// any.Unpack(foo)
// ...
// foo = Foo(...)
// any = Any()
// any.Pack(foo)
// ...
// if any.Is(Foo.DESCRIPTOR):
// any.Unpack(foo)
// ...
//
// Example 4: Pack and unpack a message in Go
// Example 4: Pack and unpack a message in Go
//
// foo := &pb.Foo{...}
// any, err := anypb.New(foo)
// if err != nil {
// ...
// }
// ...
// foo := &pb.Foo{}
// if err := any.UnmarshalTo(foo); err != nil {
// ...
// }
// foo := &pb.Foo{...}
// any, err := anypb.New(foo)
// if err != nil {
// ...
// }
// ...
// foo := &pb.Foo{}
// if err := any.UnmarshalTo(foo); err != nil {
// ...
// }
//
// The pack methods provided by protobuf library will by default use
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
@ -182,35 +182,33 @@ import (
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
// name "y.z".
//
// # JSON
//
// JSON
// ====
// The JSON representation of an `Any` value uses the regular
// representation of the deserialized, embedded message, with an
// additional field `@type` which contains the type URL. Example:
//
// package google.profile;
// message Person {
// string first_name = 1;
// string last_name = 2;
// }
// package google.profile;
// message Person {
// string first_name = 1;
// string last_name = 2;
// }
//
// {
// "@type": "type.googleapis.com/google.profile.Person",
// "firstName": <string>,
// "lastName": <string>
// }
// {
// "@type": "type.googleapis.com/google.profile.Person",
// "firstName": <string>,
// "lastName": <string>
// }
//
// If the embedded message type is well-known and has a custom JSON
// representation, that representation will be embedded adding a field
// `value` which holds the custom JSON in addition to the `@type`
// field. Example (for message [google.protobuf.Duration][]):
//
// {
// "@type": "type.googleapis.com/google.protobuf.Duration",
// "value": "1.212s"
// }
//
// {
// "@type": "type.googleapis.com/google.protobuf.Duration",
// "value": "1.212s"
// }
type Any struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -228,14 +226,14 @@ type Any struct {
// scheme `http`, `https`, or no scheme, one can optionally set up a type
// server that maps type URLs to message definitions as follows:
//
// * If no scheme is provided, `https` is assumed.
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// * Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
// lookup. Therefore, binary compatibility needs to be preserved
// on changes to types. (Use versioned type names to manage
// breaking changes.)
// - If no scheme is provided, `https` is assumed.
// - An HTTP GET on the URL must yield a [google.protobuf.Type][]
// value in binary format, or produce an error.
// - Applications are allowed to cache lookup results based on the
// URL, or have them precompiled into a binary to avoid any
// lookup. Therefore, binary compatibility needs to be preserved
// on changes to types. (Use versioned type names to manage
// breaking changes.)
//
// Note: this functionality is not currently available in the official
// protobuf release, and it is not used for type URLs beginning with
@ -243,7 +241,6 @@ type Any struct {
//
// Schemes other than `http`, `https` (or the empty scheme) might be
// used with implementation specific semantics.
//
TypeUrl string `protobuf:"bytes,1,opt,name=type_url,json=typeUrl,proto3" json:"type_url,omitempty"`
// Must be a valid serialized protocol buffer of the above specified type.
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`

View File

@ -35,8 +35,7 @@
//
// The Duration message represents a signed span of time.
//
//
// Conversion to a Go Duration
// # Conversion to a Go Duration
//
// The AsDuration method can be used to convert a Duration message to a
// standard Go time.Duration value:
@ -65,15 +64,13 @@
// the resulting value to the closest representable value (e.g., math.MaxInt64
// for positive overflow and math.MinInt64 for negative overflow).
//
//
// Conversion from a Go Duration
// # Conversion from a Go Duration
//
// The durationpb.New function can be used to construct a Duration message
// from a standard Go time.Duration value:
//
// dur := durationpb.New(d)
// ... // make use of d as a *durationpb.Duration
//
package durationpb
import (
@ -96,43 +93,43 @@ import (
//
// Example 1: Compute Duration from two Timestamps in pseudo code.
//
// Timestamp start = ...;
// Timestamp end = ...;
// Duration duration = ...;
// Timestamp start = ...;
// Timestamp end = ...;
// Duration duration = ...;
//
// duration.seconds = end.seconds - start.seconds;
// duration.nanos = end.nanos - start.nanos;
// duration.seconds = end.seconds - start.seconds;
// duration.nanos = end.nanos - start.nanos;
//
// if (duration.seconds < 0 && duration.nanos > 0) {
// duration.seconds += 1;
// duration.nanos -= 1000000000;
// } else if (duration.seconds > 0 && duration.nanos < 0) {
// duration.seconds -= 1;
// duration.nanos += 1000000000;
// }
// if (duration.seconds < 0 && duration.nanos > 0) {
// duration.seconds += 1;
// duration.nanos -= 1000000000;
// } else if (duration.seconds > 0 && duration.nanos < 0) {
// duration.seconds -= 1;
// duration.nanos += 1000000000;
// }
//
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
//
// Timestamp start = ...;
// Duration duration = ...;
// Timestamp end = ...;
// Timestamp start = ...;
// Duration duration = ...;
// Timestamp end = ...;
//
// end.seconds = start.seconds + duration.seconds;
// end.nanos = start.nanos + duration.nanos;
// end.seconds = start.seconds + duration.seconds;
// end.nanos = start.nanos + duration.nanos;
//
// if (end.nanos < 0) {
// end.seconds -= 1;
// end.nanos += 1000000000;
// } else if (end.nanos >= 1000000000) {
// end.seconds += 1;
// end.nanos -= 1000000000;
// }
// if (end.nanos < 0) {
// end.seconds -= 1;
// end.nanos += 1000000000;
// } else if (end.nanos >= 1000000000) {
// end.seconds += 1;
// end.nanos -= 1000000000;
// }
//
// Example 3: Compute Duration from datetime.timedelta in Python.
//
// td = datetime.timedelta(days=3, minutes=10)
// duration = Duration()
// duration.FromTimedelta(td)
// td = datetime.timedelta(days=3, minutes=10)
// duration = Duration()
// duration.FromTimedelta(td)
//
// # JSON Mapping
//
@ -143,8 +140,6 @@ import (
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
// microsecond should be expressed in JSON format as "3.000001s".
//
//
type Duration struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache

View File

@ -44,11 +44,9 @@ import (
// empty messages in your APIs. A typical example is to use it as the request
// or the response type of an API method. For instance:
//
// service Foo {
// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
// }
//
// The JSON representation for `Empty` is empty JSON object `{}`.
// service Foo {
// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
// }
type Empty struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache

View File

@ -37,8 +37,7 @@
// The paths are specific to some target message type,
// which is not stored within the FieldMask message itself.
//
//
// Constructing a FieldMask
// # Constructing a FieldMask
//
// The New function is used construct a FieldMask:
//
@ -61,8 +60,7 @@
// ... // handle error
// }
//
//
// Type checking a FieldMask
// # Type checking a FieldMask
//
// In order to verify that a FieldMask represents a set of fields that are
// reachable from some target message type, use the IsValid method:
@ -89,8 +87,8 @@ import (
// `FieldMask` represents a set of symbolic field paths, for example:
//
// paths: "f.a"
// paths: "f.b.d"
// paths: "f.a"
// paths: "f.b.d"
//
// Here `f` represents a field in some root message, `a` and `b`
// fields in the message found in `f`, and `d` a field found in the
@ -107,27 +105,26 @@ import (
// specified in the mask. For example, if the mask in the previous
// example is applied to a response message as follows:
//
// f {
// a : 22
// b {
// d : 1
// x : 2
// }
// y : 13
// }
// z: 8
// f {
// a : 22
// b {
// d : 1
// x : 2
// }
// y : 13
// }
// z: 8
//
// The result will not contain specific values for fields x,y and z
// (their value will be set to the default, and omitted in proto text
// output):
//
//
// f {
// a : 22
// b {
// d : 1
// }
// }
// f {
// a : 22
// b {
// d : 1
// }
// }
//
// A repeated field is not allowed except at the last position of a
// paths string.
@ -165,36 +162,36 @@ import (
//
// For example, given the target message:
//
// f {
// b {
// d: 1
// x: 2
// }
// c: [1]
// }
// f {
// b {
// d: 1
// x: 2
// }
// c: [1]
// }
//
// And an update message:
//
// f {
// b {
// d: 10
// }
// c: [2]
// }
// f {
// b {
// d: 10
// }
// c: [2]
// }
//
// then if the field mask is:
//
// paths: ["f.b", "f.c"]
// paths: ["f.b", "f.c"]
//
// then the result will be:
//
// f {
// b {
// d: 10
// x: 2
// }
// c: [1, 2]
// }
// f {
// b {
// d: 10
// x: 2
// }
// c: [1, 2]
// }
//
// An implementation may provide options to override this default behavior for
// repeated and message fields.
@ -232,51 +229,51 @@ import (
//
// As an example, consider the following message declarations:
//
// message Profile {
// User user = 1;
// Photo photo = 2;
// }
// message User {
// string display_name = 1;
// string address = 2;
// }
// message Profile {
// User user = 1;
// Photo photo = 2;
// }
// message User {
// string display_name = 1;
// string address = 2;
// }
//
// In proto a field mask for `Profile` may look as such:
//
// mask {
// paths: "user.display_name"
// paths: "photo"
// }
// mask {
// paths: "user.display_name"
// paths: "photo"
// }
//
// In JSON, the same mask is represented as below:
//
// {
// mask: "user.displayName,photo"
// }
// {
// mask: "user.displayName,photo"
// }
//
// # Field Masks and Oneof Fields
//
// Field masks treat fields in oneofs just as regular fields. Consider the
// following message:
//
// message SampleMessage {
// oneof test_oneof {
// string name = 4;
// SubMessage sub_message = 9;
// }
// }
// message SampleMessage {
// oneof test_oneof {
// string name = 4;
// SubMessage sub_message = 9;
// }
// }
//
// The field mask can be:
//
// mask {
// paths: "name"
// }
// mask {
// paths: "name"
// }
//
// Or:
//
// mask {
// paths: "sub_message"
// }
// mask {
// paths: "sub_message"
// }
//
// Note that oneof type names ("test_oneof" in this case) cannot be used in
// paths.

View File

@ -44,8 +44,7 @@
// "google.golang.org/protobuf/encoding/protojson" package
// ensures that they will be serialized as their JSON equivalent.
//
//
// Conversion to and from a Go interface
// # Conversion to and from a Go interface
//
// The standard Go "encoding/json" package has functionality to serialize
// arbitrary types to a large degree. The Value.AsInterface, Struct.AsMap, and
@ -58,8 +57,7 @@
// forms back as Value, Struct, and ListValue messages, use the NewStruct,
// NewList, and NewValue constructor functions.
//
//
// Example usage
// # Example usage
//
// Consider the following example JSON object:
//
@ -118,7 +116,6 @@
// ... // handle error
// }
// ... // make use of m as a *structpb.Value
//
package structpb
import (
@ -135,7 +132,7 @@ import (
// `NullValue` is a singleton enumeration to represent the null value for the
// `Value` type union.
//
// The JSON representation for `NullValue` is JSON `null`.
// The JSON representation for `NullValue` is JSON `null`.
type NullValue int32
const (
@ -218,8 +215,9 @@ func NewStruct(v map[string]interface{}) (*Struct, error) {
// AsMap converts x to a general-purpose Go map.
// The map values are converted by calling Value.AsInterface.
func (x *Struct) AsMap() map[string]interface{} {
vs := make(map[string]interface{})
for k, v := range x.GetFields() {
f := x.GetFields()
vs := make(map[string]interface{}, len(f))
for k, v := range f {
vs[k] = v.AsInterface()
}
return vs
@ -274,8 +272,8 @@ func (x *Struct) GetFields() map[string]*Value {
// `Value` represents a dynamically typed value which can be either
// null, a number, a string, a boolean, a recursive struct value, or a
// list of values. A producer of value is expected to set one of that
// variants, absence of any variant indicates an error.
// list of values. A producer of value is expected to set one of these
// variants. Absence of any variant indicates an error.
//
// The JSON representation for `Value` is JSON value.
type Value struct {
@ -286,6 +284,7 @@ type Value struct {
// The kind of value.
//
// Types that are assignable to Kind:
//
// *Value_NullValue
// *Value_NumberValue
// *Value_StringValue
@ -596,8 +595,9 @@ func NewList(v []interface{}) (*ListValue, error) {
// AsSlice converts x to a general-purpose Go slice.
// The slice elements are converted by calling Value.AsInterface.
func (x *ListValue) AsSlice() []interface{} {
vs := make([]interface{}, len(x.GetValues()))
for i, v := range x.GetValues() {
vals := x.GetValues()
vs := make([]interface{}, len(vals))
for i, v := range vals {
vs[i] = v.AsInterface()
}
return vs

View File

@ -36,8 +36,7 @@
// The Timestamp message represents a timestamp,
// an instant in time since the Unix epoch (January 1st, 1970).
//
//
// Conversion to a Go Time
// # Conversion to a Go Time
//
// The AsTime method can be used to convert a Timestamp message to a
// standard Go time.Time value in UTC:
@ -59,8 +58,7 @@
// ... // handle error
// }
//
//
// Conversion from a Go Time
// # Conversion from a Go Time
//
// The timestamppb.New function can be used to construct a Timestamp message
// from a standard Go time.Time value:
@ -72,7 +70,6 @@
//
// ts := timestamppb.Now()
// ... // make use of ts as a *timestamppb.Timestamp
//
package timestamppb
import (
@ -101,52 +98,50 @@ import (
//
// Example 1: Compute Timestamp from POSIX `time()`.
//
// Timestamp timestamp;
// timestamp.set_seconds(time(NULL));
// timestamp.set_nanos(0);
// Timestamp timestamp;
// timestamp.set_seconds(time(NULL));
// timestamp.set_nanos(0);
//
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
//
// struct timeval tv;
// gettimeofday(&tv, NULL);
// struct timeval tv;
// gettimeofday(&tv, NULL);
//
// Timestamp timestamp;
// timestamp.set_seconds(tv.tv_sec);
// timestamp.set_nanos(tv.tv_usec * 1000);
// Timestamp timestamp;
// timestamp.set_seconds(tv.tv_sec);
// timestamp.set_nanos(tv.tv_usec * 1000);
//
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
//
// FILETIME ft;
// GetSystemTimeAsFileTime(&ft);
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
// FILETIME ft;
// GetSystemTimeAsFileTime(&ft);
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
//
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
// Timestamp timestamp;
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
// Timestamp timestamp;
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
//
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
//
// long millis = System.currentTimeMillis();
//
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
// .setNanos((int) ((millis % 1000) * 1000000)).build();
// long millis = System.currentTimeMillis();
//
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
// .setNanos((int) ((millis % 1000) * 1000000)).build();
//
// Example 5: Compute Timestamp from Java `Instant.now()`.
//
// Instant now = Instant.now();
//
// Timestamp timestamp =
// Timestamp.newBuilder().setSeconds(now.getEpochSecond())
// .setNanos(now.getNano()).build();
// Instant now = Instant.now();
//
// Timestamp timestamp =
// Timestamp.newBuilder().setSeconds(now.getEpochSecond())
// .setNanos(now.getNano()).build();
//
// Example 6: Compute Timestamp from current time in Python.
//
// timestamp = Timestamp()
// timestamp.GetCurrentTime()
// timestamp = Timestamp()
// timestamp.GetCurrentTime()
//
// # JSON Mapping
//
@ -174,8 +169,6 @@ import (
// the Joda Time's [`ISODateTimeFormat.dateTime()`](
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
// ) to obtain a formatter capable of generating timestamps in this format.
//
//
type Timestamp struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache

View File

@ -27,7 +27,7 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Wrappers for primitive (non-message) types. These types are useful
// for embedding primitives in the `google.protobuf.Any` type and for places
// where we need to distinguish between the absence of a primitive

View File

@ -30,9 +30,6 @@
// Author: kenton@google.com (Kenton Varda)
//
// WARNING: The plugin interface is currently EXPERIMENTAL and is subject to
// change.
//
// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is
// just a program that reads a CodeGeneratorRequest from stdin and writes a
// CodeGeneratorResponse to stdout.
@ -377,7 +374,9 @@ type CodeGeneratorResponse_File struct {
// produced by another code generator. The original generator may provide
// insertion points by placing special annotations in the file that look
// like:
// @@protoc_insertion_point(NAME)
//
// @@protoc_insertion_point(NAME)
//
// The annotation can have arbitrary text before and after it on the line,
// which allows it to be placed in a comment. NAME should be replaced with
// an identifier naming the point -- this is what other generators will use
@ -389,7 +388,9 @@ type CodeGeneratorResponse_File struct {
//
// For example, the C++ code generator places the following line in the
// .pb.h files that it generates:
// // @@protoc_insertion_point(namespace_scope)
//
// // @@protoc_insertion_point(namespace_scope)
//
// This line appears within the scope of the file's package namespace, but
// outside of any particular class. Another plugin can then specify the
// insertion_point "namespace_scope" to generate additional classes or
@ -533,12 +534,14 @@ var file_google_protobuf_compiler_plugin_proto_rawDesc = []byte{
0x74, 0x75, 0x72, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x5f,
0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52,
0x45, 0x5f, 0x50, 0x52, 0x4f, 0x54, 0x4f, 0x33, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41,
0x4c, 0x10, 0x01, 0x42, 0x57, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x4c, 0x10, 0x01, 0x42, 0x72, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x63, 0x6f, 0x6d, 0x70, 0x69,
0x6c, 0x65, 0x72, 0x42, 0x0c, 0x50, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f,
0x73, 0x5a, 0x29, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67,
0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x79,
0x70, 0x65, 0x73, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x70, 0x62,
0x70, 0x65, 0x73, 0x2f, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x70, 0x62, 0xaa, 0x02, 0x18, 0x47,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x43,
0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x72,
}
var (