reflect/protoreflect: add Descriptor.Options method

Add a method to fetch descriptor options. Since options are proto
messages (e.g., google.protobuf.FieldOptions), and proto message
packages depend on the protoreflect package, returning the actual option
type would cause a dependency cycle. Instead, we return an interface
value which can be type asserted to the appropriate concrete type.

Add options support to the prototype package.

Some of the prototype constructors included fields (such as
Field.IsPacked) which represent information from the options
(such as google.protobuf.FieldOptions.packed). To avoid confusion about
the canonical source of information, drop these fields in favor of the
options.

Drop the unimplemented Descriptor.DescriptorOptionsProto.

Change-Id: I66579b6a7d10d99eb6977402a247306a78913e74
Reviewed-on: https://go-review.googlesource.com/c/144277
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
This commit is contained in:
Damien Neil 2018-10-23 15:03:38 -07:00
parent 90fe996bd1
commit 204f1c0ad8
20 changed files with 466 additions and 649 deletions

View File

@ -10,6 +10,7 @@ import (
"strconv"
"strings"
descpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/v2/protogen"
)
@ -56,7 +57,7 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated
g.P("// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.")
// Client interface.
if serviceOptions(gen, service).GetDeprecated() {
if service.Desc.Options().(*descpb.ServiceOptions).GetDeprecated() {
g.P("//")
g.P(deprecationComment)
}
@ -77,7 +78,7 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated
g.P()
// NewClient factory.
if serviceOptions(gen, service).GetDeprecated() {
if service.Desc.Options().(*descpb.ServiceOptions).GetDeprecated() {
g.P(deprecationComment)
}
g.P("func New", clientName, " (cc *", ident("grpc.ClientConn"), ") ", clientName, " {")
@ -102,7 +103,7 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated
// Server interface.
serverType := service.GoName + "Server"
g.P("// ", serverType, " is the server API for ", service.GoName, " service.")
if serviceOptions(gen, service).GetDeprecated() {
if service.Desc.Options().(*descpb.ServiceOptions).GetDeprecated() {
g.P("//")
g.P(deprecationComment)
}
@ -117,7 +118,7 @@ func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.Generated
g.P()
// Server registration.
if serviceOptions(gen, service).GetDeprecated() {
if service.Desc.Options().(*descpb.ServiceOptions).GetDeprecated() {
g.P(deprecationComment)
}
serviceDescVar := "_" + service.GoName + "_serviceDesc"
@ -189,7 +190,7 @@ func genClientMethod(gen *protogen.Plugin, file *protogen.File, g *protogen.Gene
service := method.ParentService
sname := fmt.Sprintf("/%s/%s", service.Desc.FullName(), method.Desc.Name())
if methodOptions(gen, method).GetDeprecated() {
if method.Desc.Options().(*descpb.MethodOptions).GetDeprecated() {
g.P(deprecationComment)
}
g.P("func (c *", unexport(service.GoName), "Client) ", clientSignature(g, method), "{")

View File

@ -1,116 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains functions for fetching the options for a protoreflect descriptor.
//
// TODO: Replace this with the appropriate protoreflect API, once it exists.
package internal_gengogrpc
import (
"github.com/golang/protobuf/proto"
descpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/v2/protogen"
"github.com/golang/protobuf/v2/reflect/protoreflect"
)
// serviceOptions returns the options for a service.
func serviceOptions(gen *protogen.Plugin, service *protogen.Service) *descpb.ServiceOptions {
d := getDescriptorProto(gen, service.Desc, service.Location.Path)
if d == nil {
return nil
}
return d.(*descpb.ServiceDescriptorProto).GetOptions()
}
// methodOptions returns the options for a method.
func methodOptions(gen *protogen.Plugin, method *protogen.Method) *descpb.MethodOptions {
d := getDescriptorProto(gen, method.Desc, method.Location.Path)
if d == nil {
return nil
}
return d.(*descpb.MethodDescriptorProto).GetOptions()
}
func getDescriptorProto(gen *protogen.Plugin, desc protoreflect.Descriptor, path []int32) proto.Message {
var p proto.Message
// Look up the FileDescriptorProto.
for {
if fdesc, ok := desc.(protoreflect.FileDescriptor); ok {
file, ok := gen.FileByName(fdesc.Path())
if !ok {
return nil
}
p = file.Proto
break
}
var ok bool
desc, ok = desc.Parent()
if !ok {
return nil
}
}
const (
// field numbers in FileDescriptorProto
filePackageField = 2 // package
fileMessageField = 4 // message_type
fileEnumField = 5 // enum_type
fileServiceField = 6 // service
fileExtensionField = 7 // extension
// field numbers in DescriptorProto
messageFieldField = 2 // field
messageMessageField = 3 // nested_type
messageEnumField = 4 // enum_type
messageExtensionField = 6 // extension
messageOneofField = 8 // oneof_decl
// field numbers in EnumDescriptorProto
enumValueField = 2 // value
// field numbers in ServiceDescriptorProto
serviceMethodField = 2 // method
)
for len(path) > 1 {
switch d := p.(type) {
case *descpb.FileDescriptorProto:
switch path[0] {
case fileMessageField:
p = d.MessageType[path[1]]
case fileEnumField:
p = d.EnumType[path[1]]
case fileServiceField:
p = d.Service[path[1]]
default:
return nil
}
case *descpb.DescriptorProto:
switch path[0] {
case messageFieldField:
p = d.Field[path[1]]
case messageMessageField:
p = d.NestedType[path[1]]
case messageEnumField:
p = d.EnumType[path[1]]
default:
return nil
}
case *descpb.EnumDescriptorProto:
switch path[0] {
case enumValueField:
p = d.Value[path[1]]
default:
return nil
}
case *descpb.ServiceDescriptorProto:
switch path[0] {
case serviceMethodField:
p = d.Method[path[1]]
default:
return nil
}
default:
return nil
}
path = path[2:]
}
return p
}

View File

@ -237,13 +237,13 @@ func genEnum(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, enum
g.PrintLeadingComments(enum.Location)
g.Annotate(enum.GoIdent.GoName, enum.Location)
g.P("type ", enum.GoIdent, " int32",
deprecationComment(enumOptions(gen, enum).GetDeprecated()))
deprecationComment(enum.Desc.Options().(*descpb.EnumOptions).GetDeprecated()))
g.P("const (")
for _, value := range enum.Values {
g.PrintLeadingComments(value.Location)
g.Annotate(value.GoIdent.GoName, value.Location)
g.P(value.GoIdent, " ", enum.GoIdent, " = ", value.Desc.Number(),
deprecationComment(enumValueOptions(gen, value).GetDeprecated()))
deprecationComment(value.Desc.Options().(*descpb.EnumValueOptions).GetDeprecated()))
}
g.P(")")
g.P()
@ -333,7 +333,7 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, me
}
hasComment := g.PrintLeadingComments(message.Location)
if messageOptions(gen, message).GetDeprecated() {
if message.Desc.Options().(*descpb.MessageOptions).GetDeprecated() {
if hasComment {
g.P("//")
}
@ -371,13 +371,13 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, me
}
g.Annotate(message.GoIdent.GoName+"."+field.GoName, field.Location)
g.P(field.GoName, " ", goType, " `", strings.Join(tags, " "), "`",
deprecationComment(fieldOptions(gen, field).GetDeprecated()))
deprecationComment(field.Desc.Options().(*descpb.FieldOptions).GetDeprecated()))
}
g.P("XXX_NoUnkeyedLiteral struct{} `json:\"-\"`")
if message.Desc.ExtensionRanges().Len() > 0 {
var tags []string
if messageOptions(gen, message).GetMessageSetWireFormat() {
if message.Desc.Options().(*descpb.MessageOptions).GetMessageSetWireFormat() {
tags = append(tags, `protobuf_messageset:"1"`)
}
tags = append(tags, `json:"-"`)
@ -413,7 +413,7 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, me
// ExtensionRangeArray
if extranges := message.Desc.ExtensionRanges(); extranges.Len() > 0 {
if messageOptions(gen, message).GetMessageSetWireFormat() {
if message.Desc.Options().(*descpb.MessageOptions).GetMessageSetWireFormat() {
g.P("func (m *", message.GoIdent, ") MarshalJSON() ([]byte, error) {")
g.P("return ", protogen.GoIdent{
GoImportPath: protoPackage,
@ -545,7 +545,7 @@ func genMessage(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo, me
}
goType, pointer := fieldGoType(g, field)
defaultValue := fieldDefaultValue(g, message, field)
if fieldOptions(gen, field).GetDeprecated() {
if field.Desc.Options().(*descpb.FieldOptions).GetDeprecated() {
g.P(deprecationComment(true))
}
g.Annotate(message.GoIdent.GoName+".Get"+field.GoName, field.Location)
@ -836,7 +836,7 @@ func genExtension(gen *protogen.Plugin, g *protogen.GeneratedFile, f *fileInfo,
func isExtensionMessageSetElement(gen *protogen.Plugin, extension *protogen.Extension) bool {
return extension.ParentMessage != nil &&
messageOptions(gen, extension.ExtendedType).GetMessageSetWireFormat() &&
extension.ExtendedType.Desc.Options().(*descpb.MessageOptions).GetMessageSetWireFormat() &&
extension.Desc.Name() == "message_set_extension"
}

View File

@ -1,122 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains functions for fetching the options for a protoreflect descriptor.
//
// TODO: Replace this with the appropriate protoreflect API, once it exists.
package internal_gengo
import (
"github.com/golang/protobuf/proto"
descpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/v2/protogen"
"github.com/golang/protobuf/v2/reflect/protoreflect"
)
// messageOptions returns the MessageOptions for a message.
func messageOptions(gen *protogen.Plugin, message *protogen.Message) *descpb.MessageOptions {
d := getDescriptorProto(gen, message.Desc, message.Location.Path)
if d == nil {
return nil
}
return d.(*descpb.DescriptorProto).GetOptions()
}
// fieldOptions returns the FieldOptions for a message.
func fieldOptions(gen *protogen.Plugin, field *protogen.Field) *descpb.FieldOptions {
d := getDescriptorProto(gen, field.Desc, field.Location.Path)
if d == nil {
return nil
}
return d.(*descpb.FieldDescriptorProto).GetOptions()
}
// enumOptions returns the EnumOptions for an enum
func enumOptions(gen *protogen.Plugin, enum *protogen.Enum) *descpb.EnumOptions {
d := getDescriptorProto(gen, enum.Desc, enum.Location.Path)
if d == nil {
return nil
}
return d.(*descpb.EnumDescriptorProto).GetOptions()
}
// enumValueOptions returns the EnumValueOptions for an enum value
func enumValueOptions(gen *protogen.Plugin, value *protogen.EnumValue) *descpb.EnumValueOptions {
d := getDescriptorProto(gen, value.Desc, value.Location.Path)
if d == nil {
return nil
}
return d.(*descpb.EnumValueDescriptorProto).GetOptions()
}
func getDescriptorProto(gen *protogen.Plugin, desc protoreflect.Descriptor, path []int32) proto.Message {
var p proto.Message
// Look up the FileDescriptorProto.
for {
if fdesc, ok := desc.(protoreflect.FileDescriptor); ok {
file, ok := gen.FileByName(fdesc.Path())
if !ok {
return nil
}
p = file.Proto
break
}
var ok bool
desc, ok = desc.Parent()
if !ok {
return nil
}
}
const (
// field numbers in FileDescriptorProto
filePackageField = 2 // package
fileMessageField = 4 // message_type
fileEnumField = 5 // enum_type
fileExtensionField = 7 // extension
// field numbers in DescriptorProto
messageFieldField = 2 // field
messageMessageField = 3 // nested_type
messageEnumField = 4 // enum_type
messageExtensionField = 6 // extension
messageOneofField = 8 // oneof_decl
// field numbers in EnumDescriptorProto
enumValueField = 2 // value
)
for len(path) > 1 {
switch d := p.(type) {
case *descpb.FileDescriptorProto:
switch path[0] {
case fileMessageField:
p = d.MessageType[path[1]]
case fileEnumField:
p = d.EnumType[path[1]]
default:
return nil
}
case *descpb.DescriptorProto:
switch path[0] {
case messageFieldField:
p = d.Field[path[1]]
case messageMessageField:
p = d.NestedType[path[1]]
case messageEnumField:
p = d.EnumType[path[1]]
default:
return nil
}
case *descpb.EnumDescriptorProto:
switch path[0] {
case enumValueField:
p = d.Value[path[1]]
default:
return nil
}
default:
return nil
}
path = path[2:]
}
return p
}

View File

@ -17,6 +17,8 @@ import (
"strconv"
"strings"
protoV1 "github.com/golang/protobuf/proto"
descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/v2/internal/encoding/pack"
"github.com/golang/protobuf/v2/internal/encoding/wire"
"github.com/golang/protobuf/v2/reflect/protoreflect"
@ -227,7 +229,7 @@ func (fs fields) messageDescriptor(name protoreflect.FullName) prototype.Message
protoreflect.Sfixed32Kind, protoreflect.Fixed32Kind, protoreflect.FloatKind,
protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind, protoreflect.DoubleKind:
f.Cardinality = protoreflect.Repeated
f.IsPacked = true
f.Options = &descriptorV1.FieldOptions{Packed: protoV1.Bool(true)}
case protoreflect.MessageKind, protoreflect.GroupKind:
s := name.Append(protoreflect.Name(fmt.Sprintf("M%d", n)))
f.MessageType = prototype.PlaceholderMessage(s)

View File

@ -67,7 +67,7 @@ func TestFields(t *testing.T) {
Name: "M20",
Fields: []ptype.Field{
{Name: "f30", Number: 30, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("M.M10.M20.M30")},
{Name: "f31", Number: 31, Cardinality: pref.Repeated, IsPacked: true, Kind: pref.Int32Kind},
{Name: "f31", Number: 31, Cardinality: pref.Repeated, Kind: pref.Int32Kind},
},
Messages: []ptype.Message{{
Name: "M30",
@ -87,6 +87,7 @@ func TestFields(t *testing.T) {
return x.FullName() == y.FullName()
}),
cmpopts.IgnoreFields(ptype.Field{}, "Default"),
cmpopts.IgnoreFields(ptype.Field{}, "Options"),
cmpopts.IgnoreUnexported(ptype.Message{}, ptype.Field{}),
}
for _, tt := range tests {

View File

@ -11,6 +11,7 @@ import (
"math"
"testing"
descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
ptype "github.com/golang/protobuf/v2/reflect/prototype"
"github.com/google/go-cmp/cmp"
@ -21,16 +22,16 @@ var msgDesc = func() pref.MessageDescriptor {
Syntax: pref.Proto2,
FullName: "Message",
Fields: []ptype.Field{
{Name: "F1", Number: 1, Cardinality: pref.Repeated, Kind: pref.BoolKind, IsPacked: true},
{Name: "F2", Number: 2, Cardinality: pref.Repeated, Kind: pref.Int64Kind, IsPacked: true},
{Name: "F3", Number: 3, Cardinality: pref.Repeated, Kind: pref.Sint64Kind, IsPacked: true},
{Name: "F4", Number: 4, Cardinality: pref.Repeated, Kind: pref.Uint64Kind, IsPacked: true},
{Name: "F5", Number: 5, Cardinality: pref.Repeated, Kind: pref.Fixed32Kind, IsPacked: true},
{Name: "F6", Number: 6, Cardinality: pref.Repeated, Kind: pref.Sfixed32Kind, IsPacked: true},
{Name: "F7", Number: 7, Cardinality: pref.Repeated, Kind: pref.FloatKind, IsPacked: true},
{Name: "F8", Number: 8, Cardinality: pref.Repeated, Kind: pref.Fixed64Kind, IsPacked: true},
{Name: "F9", Number: 9, Cardinality: pref.Repeated, Kind: pref.Sfixed64Kind, IsPacked: true},
{Name: "F10", Number: 10, Cardinality: pref.Repeated, Kind: pref.DoubleKind, IsPacked: true},
{Name: "F1", Number: 1, Cardinality: pref.Repeated, Kind: pref.BoolKind, Options: packedOpt(true)},
{Name: "F2", Number: 2, Cardinality: pref.Repeated, Kind: pref.Int64Kind, Options: packedOpt(true)},
{Name: "F3", Number: 3, Cardinality: pref.Repeated, Kind: pref.Sint64Kind, Options: packedOpt(true)},
{Name: "F4", Number: 4, Cardinality: pref.Repeated, Kind: pref.Uint64Kind, Options: packedOpt(true)},
{Name: "F5", Number: 5, Cardinality: pref.Repeated, Kind: pref.Fixed32Kind, Options: packedOpt(true)},
{Name: "F6", Number: 6, Cardinality: pref.Repeated, Kind: pref.Sfixed32Kind, Options: packedOpt(true)},
{Name: "F7", Number: 7, Cardinality: pref.Repeated, Kind: pref.FloatKind, Options: packedOpt(true)},
{Name: "F8", Number: 8, Cardinality: pref.Repeated, Kind: pref.Fixed64Kind, Options: packedOpt(true)},
{Name: "F9", Number: 9, Cardinality: pref.Repeated, Kind: pref.Sfixed64Kind, Options: packedOpt(true)},
{Name: "F10", Number: 10, Cardinality: pref.Repeated, Kind: pref.DoubleKind, Options: packedOpt(true)},
{Name: "F11", Number: 11, Cardinality: pref.Optional, Kind: pref.StringKind},
{Name: "F12", Number: 12, Cardinality: pref.Optional, Kind: pref.BytesKind},
{Name: "F13", Number: 13, Cardinality: pref.Optional, Kind: pref.MessageKind, MessageType: ptype.PlaceholderMessage("Message")},
@ -42,6 +43,10 @@ var msgDesc = func() pref.MessageDescriptor {
return mtyp
}()
func packedOpt(b bool) *descriptorV1.FieldOptions {
return &descriptorV1.FieldOptions{Packed: &b}
}
// dhex decodes a hex-string and returns the bytes and panics if s is invalid.
func dhex(s string) []byte {
b, err := hex.DecodeString(s)

View File

@ -13,6 +13,8 @@ import (
"sync"
"unicode"
protoV1 "github.com/golang/protobuf/proto"
descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/v2/internal/encoding/text"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
ptype "github.com/golang/protobuf/v2/reflect/prototype"
@ -179,6 +181,9 @@ func (ms *messageDescSet) parseField(tag, tagKey, tagVal string, t reflect.Type,
t = t.Elem()
}
f.Options = &descriptorV1.FieldOptions{
Packed: protoV1.Bool(false),
}
for len(tag) > 0 {
i := strings.IndexByte(tag, ',')
if i < 0 {
@ -251,9 +256,9 @@ func (ms *messageDescSet) parseField(tag, tagKey, tagVal string, t reflect.Type,
case strings.HasPrefix(s, "json="):
f.JSONName = s[len("json="):]
case s == "packed":
f.IsPacked = true
*f.Options.Packed = true
case strings.HasPrefix(s, "weak="):
f.IsWeak = true
f.Options.Weak = protoV1.Bool(true)
f.MessageType = ptype.PlaceholderMessage(pref.FullName(s[len("weak="):]))
case strings.HasPrefix(s, "def="):
// The default tag is special in that everything afterwards is the
@ -333,9 +338,9 @@ func (ms *messageDescSet) parseField(tag, tagKey, tagVal string, t reflect.Type,
f.MessageType = mv.ProtoReflect().Type()
} else if t.Kind() == reflect.Map {
m := &ptype.StandaloneMessage{
Syntax: parent.Syntax,
FullName: parent.FullName.Append(mapEntryName(f.Name)),
IsMapEntry: true,
Syntax: parent.Syntax,
FullName: parent.FullName.Append(mapEntryName(f.Name)),
Options: &descriptorV1.MessageOptions{MapEntry: protoV1.Bool(true)},
Fields: []ptype.Field{
ms.parseField(tagKey, "", "", t.Key(), nil),
ms.parseField(tagVal, "", "", t.Elem(), nil),

View File

@ -99,6 +99,8 @@ func TestLegacy(t *testing.T) {
switch name {
case "Index":
// Ignore index since legacy descriptors have no parent.
case "Options":
// Ignore descriptor options since protos are not cmperable.
case "Messages", "Enums":
// Ignore nested message and enum declarations since
// legacy descriptors are all created standalone.

View File

@ -14,6 +14,8 @@ import (
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/golang/protobuf/proto"
protoV1 "github.com/golang/protobuf/proto"
descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
ptype "github.com/golang/protobuf/v2/reflect/prototype"
)
@ -461,7 +463,7 @@ func TestMapScalars(t *testing.T) {
{Name: "key", Number: 1, Cardinality: pref.Optional, Kind: keyKind},
{Name: "value", Number: 2, Cardinality: pref.Optional, Kind: valKind},
},
IsMapEntry: true,
Options: &descriptorV1.MessageOptions{MapEntry: protoV1.Bool(true)},
}),
}
}

View File

@ -104,57 +104,30 @@ type Descriptor interface {
// Support for this functionality is optional and may return (nil, false).
DescriptorProto() (Message, bool)
// DescriptorOptions is a helper for accessing the proto options specified
// on any of the descriptor types. It is functionally equivalent to
// accessing the "options" field in the descriptor and providing a set of
// efficient lookup methods.
// Options returns the descriptor options. The caller must not modify
// the returned value.
//
// Support for this functionality is optional and may return (nil, false).
DescriptorOptions() (DescriptorOptions, bool)
doNotImplement
}
// DescriptorOptions is a wrapper around proto options.
//
// The proto message type for each descriptor type is as follows:
// +---------------------+----------------------------------+
// | Go type | Proto message type |
// +---------------------+----------------------------------+
// | FileDescriptor | google.protobuf.FileOptions |
// | MessageDescriptor | google.protobuf.MessageOptions |
// | FieldDescriptor | google.protobuf.FieldOptions |
// | OneofDescriptor | google.protobuf.OneofOptions |
// | EnumDescriptor | google.protobuf.EnumOptions |
// | EnumValueDescriptor | google.protobuf.EnumValueOptions |
// | ServiceDescriptor | google.protobuf.ServiceOptions |
// | MethodDescriptor | google.protobuf.MethodOptions |
// +---------------------+----------------------------------+
//
// The values returned by Get, ByName, and ByNumber are considered frozen and
// mutating operations must not be performed on values returned by them.
type DescriptorOptions interface {
// Len reports the total number of option fields,
// including both fields declared in the options proto and extensions, and
// including fields that are declared but not set in the proto file.
Len() int
// Get returns the ith field. It panics if out of bounds.
// The FieldDescriptor is guaranteed to be non-nil, while the Value
// may be invalid if the proto file did not specify this option.
Get(i int) (FieldDescriptor, Value)
// ByName looks a field up by full name and
// returns (nil, Value{}) if not found.
// To avoid a dependency cycle, this function returns an interface value.
// The proto message type returned for each descriptor type is as follows:
// +---------------------+------------------------------------------+
// | Go type | Proto message type |
// +---------------------+------------------------------------------+
// | FileDescriptor | google.protobuf.FileOptions |
// | MessageDescriptor | google.protobuf.MessageOptions |
// | FieldDescriptor | google.protobuf.FieldOptions |
// | OneofDescriptor | google.protobuf.OneofOptions |
// | EnumDescriptor | google.protobuf.EnumOptions |
// | EnumValueDescriptor | google.protobuf.EnumValueOptions |
// | ServiceDescriptor | google.protobuf.ServiceOptions |
// | MethodDescriptor | google.protobuf.MethodOptions |
// +---------------------+------------------------------------------+
//
// As a special-case, non-extension fields in the options type can be
// directly accessed by the field name alone (e.g., "map_entry" may be used
// instead of "google.protobuf.MessageOptions.map_entry").
ByName(s FullName) (FieldDescriptor, Value)
// ByNumber looks a field up by the field number and
// returns (nil, Value{}) if not found.
ByNumber(n FieldNumber) (FieldDescriptor, Value)
// This method will never return a nil interface value, although the
// concrete value contained in the interface may be nil (e.g.,
// (*descpb.FileOptions)(nil)).
//
// TODO: Return ProtoMessage instead of interface{}.
Options() interface{}
doNotImplement
}

View File

@ -1,29 +0,0 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package prototype
import (
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
)
// TODO: This cannot be implemented without proto.Unmarshal.
type descriptorFileMeta struct{}
func (p *descriptorFileMeta) lazyInit(t fileDesc) (pref.Message, bool) {
return nil, false
}
type descriptorSubMeta struct{}
func (p *descriptorSubMeta) lazyInit(t pref.Descriptor) (pref.Message, bool) {
return nil, false
}
type descriptorOptionsMeta struct{}
func (p *descriptorOptionsMeta) lazyInit(t pref.Descriptor) (pref.DescriptorOptions, bool) {
return nil, false
}

View File

@ -7,6 +7,7 @@ package prototype
import (
"fmt"
descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/v2/internal/pragma"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
)
@ -26,21 +27,21 @@ var (
type placeholderName pref.FullName
func (t placeholderName) Parent() (pref.Descriptor, bool) { return nil, false }
func (t placeholderName) Index() int { return 0 }
func (t placeholderName) Syntax() pref.Syntax { return 0 }
func (t placeholderName) Name() pref.Name { return pref.FullName(t).Name() }
func (t placeholderName) FullName() pref.FullName { return pref.FullName(t) }
func (t placeholderName) IsPlaceholder() bool { return true }
func (t placeholderName) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t placeholderName) DescriptorOptions() (pref.DescriptorOptions, bool) { return nil, false }
func (t placeholderName) ProtoInternal(pragma.DoNotImplement) {}
func (t placeholderName) Parent() (pref.Descriptor, bool) { return nil, false }
func (t placeholderName) Index() int { return 0 }
func (t placeholderName) Syntax() pref.Syntax { return 0 }
func (t placeholderName) Name() pref.Name { return pref.FullName(t).Name() }
func (t placeholderName) FullName() pref.FullName { return pref.FullName(t) }
func (t placeholderName) IsPlaceholder() bool { return true }
func (t placeholderName) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t placeholderName) ProtoInternal(pragma.DoNotImplement) {}
type placeholderFile struct {
path string
placeholderName
}
func (t placeholderFile) Options() interface{} { return (*descriptorV1.FileOptions)(nil) }
func (t placeholderFile) Path() string { return t.path }
func (t placeholderFile) Package() pref.FullName { return t.FullName() }
func (t placeholderFile) Imports() pref.FileImports { return &emptyFiles }
@ -56,6 +57,7 @@ type placeholderMessage struct {
placeholderName
}
func (t placeholderMessage) Options() interface{} { return (*descriptorV1.MessageOptions)(nil) }
func (t placeholderMessage) IsMapEntry() bool { return false }
func (t placeholderMessage) Fields() pref.FieldDescriptors { return &emptyFields }
func (t placeholderMessage) Oneofs() pref.OneofDescriptors { return &emptyOneofs }
@ -71,6 +73,7 @@ type placeholderEnum struct {
placeholderName
}
func (t placeholderEnum) Options() interface{} { return (*descriptorV1.EnumOptions)(nil) }
func (t placeholderEnum) Values() pref.EnumValueDescriptors { return &emptyEnumValues }
func (t placeholderEnum) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t placeholderEnum) ProtoType(pref.EnumDescriptor) {}

View File

@ -14,6 +14,7 @@
package prototype
import (
descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/v2/reflect/protoreflect"
)
@ -35,15 +36,15 @@ import (
// File is a constructor for protoreflect.FileDescriptor.
type File struct {
Syntax protoreflect.Syntax
Path string
Package protoreflect.FullName
Imports []protoreflect.FileImport
Syntax protoreflect.Syntax
Path string
Package protoreflect.FullName
Imports []protoreflect.FileImport
Messages []Message
Enums []Enum
Extensions []Extension
Services []Service
Options *descriptorV1.FileOptions
*fileMeta
}
@ -72,14 +73,13 @@ func NewFile(t *File) (protoreflect.FileDescriptor, error) {
// Message is a constructor for protoreflect.MessageDescriptor.
type Message struct {
Name protoreflect.Name
IsMapEntry bool
Fields []Field
Oneofs []Oneof
ExtensionRanges [][2]protoreflect.FieldNumber
Messages []Message
Enums []Enum
Extensions []Extension
Messages []Message
Enums []Enum
Extensions []Extension
Options *descriptorV1.MessageOptions
*messageMeta
}
@ -91,19 +91,19 @@ type Field struct {
Cardinality protoreflect.Cardinality
Kind protoreflect.Kind
JSONName string
IsPacked bool
IsWeak bool
Default protoreflect.Value
OneofName protoreflect.Name
MessageType protoreflect.MessageDescriptor
EnumType protoreflect.EnumDescriptor
Options *descriptorV1.FieldOptions
*fieldMeta
}
// Oneof is a constructor for protoreflect.OneofDescriptor.
type Oneof struct {
Name protoreflect.Name
Name protoreflect.Name
Options *descriptorV1.OneofOptions
*oneofMeta
}
@ -114,27 +114,29 @@ type Extension struct {
Number protoreflect.FieldNumber
Cardinality protoreflect.Cardinality
Kind protoreflect.Kind
IsPacked bool
Default protoreflect.Value
MessageType protoreflect.MessageDescriptor
EnumType protoreflect.EnumDescriptor
ExtendedType protoreflect.MessageDescriptor
Options *descriptorV1.FieldOptions
*extensionMeta
}
// Enum is a constructor for protoreflect.EnumDescriptor.
type Enum struct {
Name protoreflect.Name
Values []EnumValue
Name protoreflect.Name
Values []EnumValue
Options *descriptorV1.EnumOptions
*enumMeta
}
// EnumValue is a constructor for protoreflect.EnumValueDescriptor.
type EnumValue struct {
Name protoreflect.Name
Number protoreflect.EnumNumber
Name protoreflect.Name
Number protoreflect.EnumNumber
Options *descriptorV1.EnumValueOptions
*enumValueMeta
}
@ -143,6 +145,7 @@ type EnumValue struct {
type Service struct {
Name protoreflect.Name
Methods []Method
Options *descriptorV1.ServiceOptions
*serviceMeta
}
@ -154,6 +157,7 @@ type Method struct {
OutputType protoreflect.MessageDescriptor
IsStreamingClient bool
IsStreamingServer bool
Options *descriptorV1.MethodOptions
*methodMeta
}

View File

@ -64,6 +64,7 @@ func NewFileFromDescriptorProto(fd *descriptorV1.FileDescriptorProto, r *protore
}
f.Path = fd.GetName()
f.Package = protoreflect.FullName(fd.GetPackage())
f.Options = fd.GetOptions()
f.Imports = make([]protoreflect.FileImport, len(fd.GetDependency()))
for _, i := range fd.GetPublicDependency() {
@ -119,25 +120,15 @@ func messagesFromDescriptorProto(mds []*descriptorV1.DescriptorProto, syntax pro
for _, md := range mds {
var m Message
m.Name = protoreflect.Name(md.GetName())
m.IsMapEntry = md.GetOptions().GetMapEntry()
m.Options = md.GetOptions()
for _, fd := range md.GetField() {
var f Field
f.Name = protoreflect.Name(fd.GetName())
f.Number = protoreflect.FieldNumber(fd.GetNumber())
f.Cardinality = protoreflect.Cardinality(fd.GetLabel())
f.Kind = protoreflect.Kind(fd.GetType())
f.Options = fd.GetOptions()
f.JSONName = fd.GetJsonName()
if opts := fd.GetOptions(); opts != nil && opts.Packed != nil {
f.IsPacked = *opts.Packed
} else {
// https://developers.google.com/protocol-buffers/docs/proto3:
// "In proto3, repeated fields of scalar numeric types use packed
// encoding by default."
f.IsPacked = (syntax == protoreflect.Proto3 &&
f.Cardinality == protoreflect.Repeated &&
isScalarNumeric[f.Kind])
}
f.IsWeak = fd.GetOptions().GetWeak()
if fd.DefaultValue != nil {
f.Default, err = parseDefault(fd.GetDefaultValue(), f.Kind)
if err != nil {
@ -157,7 +148,7 @@ func messagesFromDescriptorProto(mds []*descriptorV1.DescriptorProto, syntax pro
if err != nil {
return nil, err
}
if f.IsWeak && !f.EnumType.IsPlaceholder() {
if f.Options.GetWeak() && !f.EnumType.IsPlaceholder() {
f.EnumType = PlaceholderEnum(f.EnumType.FullName())
}
case protoreflect.MessageKind, protoreflect.GroupKind:
@ -165,16 +156,20 @@ func messagesFromDescriptorProto(mds []*descriptorV1.DescriptorProto, syntax pro
if err != nil {
return nil, err
}
if f.IsWeak && !f.MessageType.IsPlaceholder() {
if f.Options.GetWeak() && !f.MessageType.IsPlaceholder() {
f.MessageType = PlaceholderMessage(f.MessageType.FullName())
}
}
m.Fields = append(m.Fields, f)
}
for _, od := range md.GetOneofDecl() {
m.Oneofs = append(m.Oneofs, Oneof{Name: protoreflect.Name(od.GetName())})
m.Oneofs = append(m.Oneofs, Oneof{
Name: protoreflect.Name(od.GetName()),
Options: od.Options,
})
}
for _, xr := range md.GetExtensionRange() {
// TODO: Extension range options.
m.ExtensionRanges = append(m.ExtensionRanges, [2]protoreflect.FieldNumber{
protoreflect.FieldNumber(xr.GetStart()),
protoreflect.FieldNumber(xr.GetEnd()),
@ -199,31 +194,16 @@ func messagesFromDescriptorProto(mds []*descriptorV1.DescriptorProto, syntax pro
return ms, nil
}
var isScalarNumeric = map[protoreflect.Kind]bool{
protoreflect.BoolKind: true,
protoreflect.EnumKind: true,
protoreflect.Int32Kind: true,
protoreflect.Sint32Kind: true,
protoreflect.Uint32Kind: true,
protoreflect.Int64Kind: true,
protoreflect.Sint64Kind: true,
protoreflect.Uint64Kind: true,
protoreflect.Sfixed32Kind: true,
protoreflect.Fixed32Kind: true,
protoreflect.FloatKind: true,
protoreflect.Sfixed64Kind: true,
protoreflect.Fixed64Kind: true,
protoreflect.DoubleKind: true,
}
func enumsFromDescriptorProto(eds []*descriptorV1.EnumDescriptorProto, r *protoregistry.Files) (es []Enum, err error) {
for _, ed := range eds {
var e Enum
e.Name = protoreflect.Name(ed.GetName())
e.Options = ed.GetOptions()
for _, vd := range ed.GetValue() {
e.Values = append(e.Values, EnumValue{
Name: protoreflect.Name(vd.GetName()),
Number: protoreflect.EnumNumber(vd.GetNumber()),
Name: protoreflect.Name(vd.GetName()),
Number: protoreflect.EnumNumber(vd.GetNumber()),
Options: vd.Options,
})
}
es = append(es, e)
@ -238,12 +218,7 @@ func extensionsFromDescriptorProto(xds []*descriptorV1.FieldDescriptorProto, r *
x.Number = protoreflect.FieldNumber(xd.GetNumber())
x.Cardinality = protoreflect.Cardinality(xd.GetLabel())
x.Kind = protoreflect.Kind(xd.GetType())
// TODO: When a proto3 file extends a proto2 message (permitted only for
// extending descriptor options), does the extension have proto2 or proto3
// semantics? If the latter, repeated, scalar, numeric, proto3 extension
// fields should default to packed. If the former, perhaps the extension syntax
// should be protoreflect.Proto2.
x.IsPacked = xd.GetOptions().GetPacked()
x.Options = xd.GetOptions()
if xd.DefaultValue != nil {
x.Default, err = parseDefault(xd.GetDefaultValue(), x.Kind)
if err != nil {
@ -275,9 +250,11 @@ func servicesFromDescriptorProto(sds []*descriptorV1.ServiceDescriptorProto, r *
for _, sd := range sds {
var s Service
s.Name = protoreflect.Name(sd.GetName())
s.Options = sd.GetOptions()
for _, md := range sd.GetMethod() {
var m Method
m.Name = protoreflect.Name(md.GetName())
m.Options = md.GetOptions()
m.InputType, err = findMessageDescriptor(md.GetInputType(), r)
if err != nil {
return nil, err

View File

@ -10,6 +10,7 @@ import (
"strings"
"sync"
descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/v2/internal/pragma"
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
)
@ -20,9 +21,6 @@ type inheritedMeta struct {
index int
syntax pref.Syntax
fullName pref.FullName
desc descriptorSubMeta
opts descriptorOptionsMeta
}
func (m *inheritedMeta) init(nb *nameBuilder, parent pref.Descriptor, index int, name pref.Name, child bool) {
@ -41,9 +39,6 @@ func (m *inheritedMeta) init(nb *nameBuilder, parent pref.Descriptor, index int,
}
type fileMeta struct {
desc descriptorFileMeta
opts descriptorOptionsMeta
ms messagesMeta
es enumsMeta
xs extensionsMeta
@ -59,25 +54,25 @@ func newFile(f *File) fileDesc {
f.fileMeta = new(fileMeta)
return fileDesc{f}
}
func (t fileDesc) Parent() (pref.Descriptor, bool) { return nil, false }
func (t fileDesc) Index() int { return 0 }
func (t fileDesc) Syntax() pref.Syntax { return t.f.Syntax }
func (t fileDesc) Name() pref.Name { return t.f.Package.Name() }
func (t fileDesc) FullName() pref.FullName { return t.f.Package }
func (t fileDesc) IsPlaceholder() bool { return false }
func (t fileDesc) DescriptorProto() (pref.Message, bool) { return t.f.desc.lazyInit(t) }
func (t fileDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.f.opts.lazyInit(t) }
func (t fileDesc) Path() string { return t.f.Path }
func (t fileDesc) Package() pref.FullName { return t.f.Package }
func (t fileDesc) Imports() pref.FileImports { return (*fileImports)(&t.f.Imports) }
func (t fileDesc) Messages() pref.MessageDescriptors { return t.f.ms.lazyInit(t, t.f.Messages) }
func (t fileDesc) Enums() pref.EnumDescriptors { return t.f.es.lazyInit(t, t.f.Enums) }
func (t fileDesc) Extensions() pref.ExtensionDescriptors { return t.f.xs.lazyInit(t, t.f.Extensions) }
func (t fileDesc) Services() pref.ServiceDescriptors { return t.f.ss.lazyInit(t, t.f.Services) }
func (t fileDesc) DescriptorByName(s pref.FullName) pref.Descriptor { return t.f.ds.lookup(t, s) }
func (t fileDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t fileDesc) ProtoType(pref.FileDescriptor) {}
func (t fileDesc) ProtoInternal(pragma.DoNotImplement) {}
func (t fileDesc) Parent() (pref.Descriptor, bool) { return nil, false }
func (t fileDesc) Index() int { return 0 }
func (t fileDesc) Syntax() pref.Syntax { return t.f.Syntax }
func (t fileDesc) Name() pref.Name { return t.f.Package.Name() }
func (t fileDesc) FullName() pref.FullName { return t.f.Package }
func (t fileDesc) IsPlaceholder() bool { return false }
func (t fileDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t fileDesc) Options() interface{} { return t.f.Options }
func (t fileDesc) Path() string { return t.f.Path }
func (t fileDesc) Package() pref.FullName { return t.f.Package }
func (t fileDesc) Imports() pref.FileImports { return (*fileImports)(&t.f.Imports) }
func (t fileDesc) Messages() pref.MessageDescriptors { return t.f.ms.lazyInit(t, t.f.Messages) }
func (t fileDesc) Enums() pref.EnumDescriptors { return t.f.es.lazyInit(t, t.f.Enums) }
func (t fileDesc) Extensions() pref.ExtensionDescriptors { return t.f.xs.lazyInit(t, t.f.Extensions) }
func (t fileDesc) Services() pref.ServiceDescriptors { return t.f.ss.lazyInit(t, t.f.Services) }
func (t fileDesc) DescriptorByName(s pref.FullName) pref.Descriptor { return t.f.ds.lookup(t, s) }
func (t fileDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t fileDesc) ProtoType(pref.FileDescriptor) {}
func (t fileDesc) ProtoInternal(pragma.DoNotImplement) {}
// descriptorsMeta is a lazily initialized map of all descriptors declared in
// the file by full name.
@ -166,25 +161,25 @@ type messageMeta struct {
}
type messageDesc struct{ m *Message }
func (t messageDesc) Parent() (pref.Descriptor, bool) { return t.m.parent, true }
func (t messageDesc) Index() int { return t.m.index }
func (t messageDesc) Syntax() pref.Syntax { return t.m.syntax }
func (t messageDesc) Name() pref.Name { return t.m.Name }
func (t messageDesc) FullName() pref.FullName { return t.m.fullName }
func (t messageDesc) IsPlaceholder() bool { return false }
func (t messageDesc) DescriptorProto() (pref.Message, bool) { return t.m.desc.lazyInit(t) }
func (t messageDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.m.opts.lazyInit(t) }
func (t messageDesc) IsMapEntry() bool { return t.m.IsMapEntry }
func (t messageDesc) Fields() pref.FieldDescriptors { return t.m.fs.lazyInit(t, t.m.Fields) }
func (t messageDesc) Oneofs() pref.OneofDescriptors { return t.m.os.lazyInit(t, t.m.Oneofs) }
func (t messageDesc) RequiredNumbers() pref.FieldNumbers { return t.m.ns.lazyInit(t.m.Fields) }
func (t messageDesc) ExtensionRanges() pref.FieldRanges { return (*ranges)(&t.m.ExtensionRanges) }
func (t messageDesc) Messages() pref.MessageDescriptors { return t.m.ms.lazyInit(t, t.m.Messages) }
func (t messageDesc) Enums() pref.EnumDescriptors { return t.m.es.lazyInit(t, t.m.Enums) }
func (t messageDesc) Extensions() pref.ExtensionDescriptors { return t.m.xs.lazyInit(t, t.m.Extensions) }
func (t messageDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t messageDesc) ProtoType(pref.MessageDescriptor) {}
func (t messageDesc) ProtoInternal(pragma.DoNotImplement) {}
func (t messageDesc) Parent() (pref.Descriptor, bool) { return t.m.parent, true }
func (t messageDesc) Index() int { return t.m.index }
func (t messageDesc) Syntax() pref.Syntax { return t.m.syntax }
func (t messageDesc) Name() pref.Name { return t.m.Name }
func (t messageDesc) FullName() pref.FullName { return t.m.fullName }
func (t messageDesc) IsPlaceholder() bool { return false }
func (t messageDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t messageDesc) Options() interface{} { return t.m.Options }
func (t messageDesc) IsMapEntry() bool { return t.m.Options.GetMapEntry() }
func (t messageDesc) Fields() pref.FieldDescriptors { return t.m.fs.lazyInit(t, t.m.Fields) }
func (t messageDesc) Oneofs() pref.OneofDescriptors { return t.m.os.lazyInit(t, t.m.Oneofs) }
func (t messageDesc) RequiredNumbers() pref.FieldNumbers { return t.m.ns.lazyInit(t.m.Fields) }
func (t messageDesc) ExtensionRanges() pref.FieldRanges { return (*ranges)(&t.m.ExtensionRanges) }
func (t messageDesc) Messages() pref.MessageDescriptors { return t.m.ms.lazyInit(t, t.m.Messages) }
func (t messageDesc) Enums() pref.EnumDescriptors { return t.m.es.lazyInit(t, t.m.Enums) }
func (t messageDesc) Extensions() pref.ExtensionDescriptors { return t.m.xs.lazyInit(t, t.m.Extensions) }
func (t messageDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t messageDesc) ProtoType(pref.MessageDescriptor) {}
func (t messageDesc) ProtoInternal(pragma.DoNotImplement) {}
type fieldMeta struct {
inheritedMeta
@ -197,35 +192,64 @@ type fieldMeta struct {
}
type fieldDesc struct{ f *Field }
func (t fieldDesc) Parent() (pref.Descriptor, bool) { return t.f.parent, true }
func (t fieldDesc) Index() int { return t.f.index }
func (t fieldDesc) Syntax() pref.Syntax { return t.f.syntax }
func (t fieldDesc) Name() pref.Name { return t.f.Name }
func (t fieldDesc) FullName() pref.FullName { return t.f.fullName }
func (t fieldDesc) IsPlaceholder() bool { return false }
func (t fieldDesc) DescriptorProto() (pref.Message, bool) { return t.f.desc.lazyInit(t) }
func (t fieldDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.f.opts.lazyInit(t) }
func (t fieldDesc) Number() pref.FieldNumber { return t.f.Number }
func (t fieldDesc) Cardinality() pref.Cardinality { return t.f.Cardinality }
func (t fieldDesc) Kind() pref.Kind { return t.f.Kind }
func (t fieldDesc) JSONName() string { return t.f.js.lazyInit(t.f) }
func (t fieldDesc) IsPacked() bool { return t.f.IsPacked }
func (t fieldDesc) IsMap() bool { return isMap(t) }
func (t fieldDesc) IsWeak() bool { return t.f.IsWeak }
func (t fieldDesc) Default() pref.Value { return t.f.dv.lazyInit(t, t.f.Default) }
func (t fieldDesc) HasDefault() bool { return t.f.Default.IsValid() }
func (t fieldDesc) OneofType() pref.OneofDescriptor { return t.f.ot.lazyInit(t, t.f.OneofName) }
func (t fieldDesc) ExtendedType() pref.MessageDescriptor { return nil }
func (t fieldDesc) MessageType() pref.MessageDescriptor { return t.f.mt.lazyInit(t, &t.f.MessageType) }
func (t fieldDesc) EnumType() pref.EnumDescriptor { return t.f.et.lazyInit(t, &t.f.EnumType) }
func (t fieldDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t fieldDesc) ProtoType(pref.FieldDescriptor) {}
func (t fieldDesc) ProtoInternal(pragma.DoNotImplement) {}
func (t fieldDesc) Parent() (pref.Descriptor, bool) { return t.f.parent, true }
func (t fieldDesc) Index() int { return t.f.index }
func (t fieldDesc) Syntax() pref.Syntax { return t.f.syntax }
func (t fieldDesc) Name() pref.Name { return t.f.Name }
func (t fieldDesc) FullName() pref.FullName { return t.f.fullName }
func (t fieldDesc) IsPlaceholder() bool { return false }
func (t fieldDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t fieldDesc) Options() interface{} { return t.f.Options }
func (t fieldDesc) Number() pref.FieldNumber { return t.f.Number }
func (t fieldDesc) Cardinality() pref.Cardinality { return t.f.Cardinality }
func (t fieldDesc) Kind() pref.Kind { return t.f.Kind }
func (t fieldDesc) JSONName() string { return t.f.js.lazyInit(t.f) }
func (t fieldDesc) IsPacked() bool { return fieldIsPacked(t) }
func (t fieldDesc) IsMap() bool { return isMap(t) }
func (t fieldDesc) IsWeak() bool { return t.f.Options.GetWeak() }
func (t fieldDesc) Default() pref.Value { return t.f.dv.lazyInit(t, t.f.Default) }
func (t fieldDesc) HasDefault() bool { return t.f.Default.IsValid() }
func (t fieldDesc) OneofType() pref.OneofDescriptor { return t.f.ot.lazyInit(t, t.f.OneofName) }
func (t fieldDesc) ExtendedType() pref.MessageDescriptor { return nil }
func (t fieldDesc) MessageType() pref.MessageDescriptor { return t.f.mt.lazyInit(t, &t.f.MessageType) }
func (t fieldDesc) EnumType() pref.EnumDescriptor { return t.f.et.lazyInit(t, &t.f.EnumType) }
func (t fieldDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t fieldDesc) ProtoType(pref.FieldDescriptor) {}
func (t fieldDesc) ProtoInternal(pragma.DoNotImplement) {}
func fieldIsPacked(t fieldDesc) bool {
if t.f.Options != nil && t.f.Options.Packed != nil {
return *t.f.Options.Packed
}
// https://developers.google.com/protocol-buffers/docs/proto3:
// "In proto3, repeated fields of scalar numeric types use packed
// encoding by default."
return (t.f.syntax == pref.Proto3 &&
t.f.Cardinality == pref.Repeated &&
isScalarNumeric[t.f.Kind])
}
var isScalarNumeric = map[pref.Kind]bool{
pref.BoolKind: true,
pref.EnumKind: true,
pref.Int32Kind: true,
pref.Sint32Kind: true,
pref.Uint32Kind: true,
pref.Int64Kind: true,
pref.Sint64Kind: true,
pref.Uint64Kind: true,
pref.Sfixed32Kind: true,
pref.Fixed32Kind: true,
pref.FloatKind: true,
pref.Sfixed64Kind: true,
pref.Fixed64Kind: true,
pref.DoubleKind: true,
}
func isMap(t pref.FieldDescriptor) bool {
if t.Cardinality() == pref.Repeated && t.Kind() == pref.MessageKind {
if mt := t.MessageType(); mt != nil {
return mt.IsMapEntry()
return mt.Options().(*descriptorV1.MessageOptions).GetMapEntry()
}
}
return false
@ -283,18 +307,18 @@ type oneofMeta struct {
}
type oneofDesc struct{ o *Oneof }
func (t oneofDesc) Parent() (pref.Descriptor, bool) { return t.o.parent, true }
func (t oneofDesc) Index() int { return t.o.index }
func (t oneofDesc) Syntax() pref.Syntax { return t.o.syntax }
func (t oneofDesc) Name() pref.Name { return t.o.Name }
func (t oneofDesc) FullName() pref.FullName { return t.o.fullName }
func (t oneofDesc) IsPlaceholder() bool { return false }
func (t oneofDesc) DescriptorProto() (pref.Message, bool) { return t.o.desc.lazyInit(t) }
func (t oneofDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.o.opts.lazyInit(t) }
func (t oneofDesc) Fields() pref.FieldDescriptors { return t.o.fs.lazyInit(t) }
func (t oneofDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t oneofDesc) ProtoType(pref.OneofDescriptor) {}
func (t oneofDesc) ProtoInternal(pragma.DoNotImplement) {}
func (t oneofDesc) Parent() (pref.Descriptor, bool) { return t.o.parent, true }
func (t oneofDesc) Index() int { return t.o.index }
func (t oneofDesc) Syntax() pref.Syntax { return t.o.syntax }
func (t oneofDesc) Name() pref.Name { return t.o.Name }
func (t oneofDesc) FullName() pref.FullName { return t.o.fullName }
func (t oneofDesc) IsPlaceholder() bool { return false }
func (t oneofDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t oneofDesc) Options() interface{} { return t.o.Options }
func (t oneofDesc) Fields() pref.FieldDescriptors { return t.o.fs.lazyInit(t) }
func (t oneofDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t oneofDesc) ProtoType(pref.OneofDescriptor) {}
func (t oneofDesc) ProtoInternal(pragma.DoNotImplement) {}
type extensionMeta struct {
inheritedMeta
@ -306,24 +330,24 @@ type extensionMeta struct {
}
type extensionDesc struct{ x *Extension }
func (t extensionDesc) Parent() (pref.Descriptor, bool) { return t.x.parent, true }
func (t extensionDesc) Syntax() pref.Syntax { return t.x.syntax }
func (t extensionDesc) Index() int { return t.x.index }
func (t extensionDesc) Name() pref.Name { return t.x.Name }
func (t extensionDesc) FullName() pref.FullName { return t.x.fullName }
func (t extensionDesc) IsPlaceholder() bool { return false }
func (t extensionDesc) DescriptorProto() (pref.Message, bool) { return t.x.desc.lazyInit(t) }
func (t extensionDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.x.opts.lazyInit(t) }
func (t extensionDesc) Number() pref.FieldNumber { return t.x.Number }
func (t extensionDesc) Cardinality() pref.Cardinality { return t.x.Cardinality }
func (t extensionDesc) Kind() pref.Kind { return t.x.Kind }
func (t extensionDesc) JSONName() string { return "" }
func (t extensionDesc) IsPacked() bool { return t.x.IsPacked }
func (t extensionDesc) IsMap() bool { return false }
func (t extensionDesc) IsWeak() bool { return false }
func (t extensionDesc) Default() pref.Value { return t.x.dv.lazyInit(t, t.x.Default) }
func (t extensionDesc) HasDefault() bool { return t.x.Default.IsValid() }
func (t extensionDesc) OneofType() pref.OneofDescriptor { return nil }
func (t extensionDesc) Parent() (pref.Descriptor, bool) { return t.x.parent, true }
func (t extensionDesc) Syntax() pref.Syntax { return t.x.syntax }
func (t extensionDesc) Index() int { return t.x.index }
func (t extensionDesc) Name() pref.Name { return t.x.Name }
func (t extensionDesc) FullName() pref.FullName { return t.x.fullName }
func (t extensionDesc) IsPlaceholder() bool { return false }
func (t extensionDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t extensionDesc) Options() interface{} { return t.x.Options }
func (t extensionDesc) Number() pref.FieldNumber { return t.x.Number }
func (t extensionDesc) Cardinality() pref.Cardinality { return t.x.Cardinality }
func (t extensionDesc) Kind() pref.Kind { return t.x.Kind }
func (t extensionDesc) JSONName() string { return "" }
func (t extensionDesc) IsPacked() bool { return extIsPacked(t) }
func (t extensionDesc) IsMap() bool { return false }
func (t extensionDesc) IsWeak() bool { return false }
func (t extensionDesc) Default() pref.Value { return t.x.dv.lazyInit(t, t.x.Default) }
func (t extensionDesc) HasDefault() bool { return t.x.Default.IsValid() }
func (t extensionDesc) OneofType() pref.OneofDescriptor { return nil }
func (t extensionDesc) ExtendedType() pref.MessageDescriptor {
return t.x.xt.lazyInit(t, &t.x.ExtendedType)
}
@ -335,6 +359,15 @@ func (t extensionDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t
func (t extensionDesc) ProtoType(pref.FieldDescriptor) {}
func (t extensionDesc) ProtoInternal(pragma.DoNotImplement) {}
func extIsPacked(t extensionDesc) bool {
// TODO: When a proto3 file extends a proto2 message (permitted only for
// extending descriptor options), does the extension have proto2 or proto3
// semantics? If the latter, repeated, scalar, numeric, proto3 extension
// fields should default to packed. If the former, perhaps the extension syntax
// should be protoreflect.Proto2.
return t.x.Options.GetPacked()
}
type enumMeta struct {
inheritedMeta
@ -342,36 +375,36 @@ type enumMeta struct {
}
type enumDesc struct{ e *Enum }
func (t enumDesc) Parent() (pref.Descriptor, bool) { return t.e.parent, true }
func (t enumDesc) Index() int { return t.e.index }
func (t enumDesc) Syntax() pref.Syntax { return t.e.syntax }
func (t enumDesc) Name() pref.Name { return t.e.Name }
func (t enumDesc) FullName() pref.FullName { return t.e.fullName }
func (t enumDesc) IsPlaceholder() bool { return false }
func (t enumDesc) DescriptorProto() (pref.Message, bool) { return t.e.desc.lazyInit(t) }
func (t enumDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.e.opts.lazyInit(t) }
func (t enumDesc) Values() pref.EnumValueDescriptors { return t.e.vs.lazyInit(t, t.e.Values) }
func (t enumDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t enumDesc) ProtoType(pref.EnumDescriptor) {}
func (t enumDesc) ProtoInternal(pragma.DoNotImplement) {}
func (t enumDesc) Parent() (pref.Descriptor, bool) { return t.e.parent, true }
func (t enumDesc) Index() int { return t.e.index }
func (t enumDesc) Syntax() pref.Syntax { return t.e.syntax }
func (t enumDesc) Name() pref.Name { return t.e.Name }
func (t enumDesc) FullName() pref.FullName { return t.e.fullName }
func (t enumDesc) IsPlaceholder() bool { return false }
func (t enumDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t enumDesc) Options() interface{} { return t.e.Options }
func (t enumDesc) Values() pref.EnumValueDescriptors { return t.e.vs.lazyInit(t, t.e.Values) }
func (t enumDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t enumDesc) ProtoType(pref.EnumDescriptor) {}
func (t enumDesc) ProtoInternal(pragma.DoNotImplement) {}
type enumValueMeta struct {
inheritedMeta
}
type enumValueDesc struct{ v *EnumValue }
func (t enumValueDesc) Parent() (pref.Descriptor, bool) { return t.v.parent, true }
func (t enumValueDesc) Index() int { return t.v.index }
func (t enumValueDesc) Syntax() pref.Syntax { return t.v.syntax }
func (t enumValueDesc) Name() pref.Name { return t.v.Name }
func (t enumValueDesc) FullName() pref.FullName { return t.v.fullName }
func (t enumValueDesc) IsPlaceholder() bool { return false }
func (t enumValueDesc) DescriptorProto() (pref.Message, bool) { return t.v.desc.lazyInit(t) }
func (t enumValueDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.v.opts.lazyInit(t) }
func (t enumValueDesc) Number() pref.EnumNumber { return t.v.Number }
func (t enumValueDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t enumValueDesc) ProtoType(pref.EnumValueDescriptor) {}
func (t enumValueDesc) ProtoInternal(pragma.DoNotImplement) {}
func (t enumValueDesc) Parent() (pref.Descriptor, bool) { return t.v.parent, true }
func (t enumValueDesc) Index() int { return t.v.index }
func (t enumValueDesc) Syntax() pref.Syntax { return t.v.syntax }
func (t enumValueDesc) Name() pref.Name { return t.v.Name }
func (t enumValueDesc) FullName() pref.FullName { return t.v.fullName }
func (t enumValueDesc) IsPlaceholder() bool { return false }
func (t enumValueDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t enumValueDesc) Options() interface{} { return t.v.Options }
func (t enumValueDesc) Number() pref.EnumNumber { return t.v.Number }
func (t enumValueDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t enumValueDesc) ProtoType(pref.EnumValueDescriptor) {}
func (t enumValueDesc) ProtoInternal(pragma.DoNotImplement) {}
type serviceMeta struct {
inheritedMeta
@ -380,18 +413,18 @@ type serviceMeta struct {
}
type serviceDesc struct{ s *Service }
func (t serviceDesc) Parent() (pref.Descriptor, bool) { return t.s.parent, true }
func (t serviceDesc) Index() int { return t.s.index }
func (t serviceDesc) Syntax() pref.Syntax { return t.s.syntax }
func (t serviceDesc) Name() pref.Name { return t.s.Name }
func (t serviceDesc) FullName() pref.FullName { return t.s.fullName }
func (t serviceDesc) IsPlaceholder() bool { return false }
func (t serviceDesc) DescriptorProto() (pref.Message, bool) { return t.s.desc.lazyInit(t) }
func (t serviceDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.s.opts.lazyInit(t) }
func (t serviceDesc) Methods() pref.MethodDescriptors { return t.s.ms.lazyInit(t, t.s.Methods) }
func (t serviceDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t serviceDesc) ProtoType(pref.ServiceDescriptor) {}
func (t serviceDesc) ProtoInternal(pragma.DoNotImplement) {}
func (t serviceDesc) Parent() (pref.Descriptor, bool) { return t.s.parent, true }
func (t serviceDesc) Index() int { return t.s.index }
func (t serviceDesc) Syntax() pref.Syntax { return t.s.syntax }
func (t serviceDesc) Name() pref.Name { return t.s.Name }
func (t serviceDesc) FullName() pref.FullName { return t.s.fullName }
func (t serviceDesc) IsPlaceholder() bool { return false }
func (t serviceDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t serviceDesc) Options() interface{} { return t.s.Options }
func (t serviceDesc) Methods() pref.MethodDescriptors { return t.s.ms.lazyInit(t, t.s.Methods) }
func (t serviceDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t serviceDesc) ProtoType(pref.ServiceDescriptor) {}
func (t serviceDesc) ProtoInternal(pragma.DoNotImplement) {}
type methodMeta struct {
inheritedMeta
@ -401,21 +434,21 @@ type methodMeta struct {
}
type methodDesc struct{ m *Method }
func (t methodDesc) Parent() (pref.Descriptor, bool) { return t.m.parent, true }
func (t methodDesc) Index() int { return t.m.index }
func (t methodDesc) Syntax() pref.Syntax { return t.m.syntax }
func (t methodDesc) Name() pref.Name { return t.m.Name }
func (t methodDesc) FullName() pref.FullName { return t.m.fullName }
func (t methodDesc) IsPlaceholder() bool { return false }
func (t methodDesc) DescriptorProto() (pref.Message, bool) { return t.m.desc.lazyInit(t) }
func (t methodDesc) DescriptorOptions() (pref.DescriptorOptions, bool) { return t.m.opts.lazyInit(t) }
func (t methodDesc) InputType() pref.MessageDescriptor { return t.m.mit.lazyInit(t, &t.m.InputType) }
func (t methodDesc) OutputType() pref.MessageDescriptor { return t.m.mot.lazyInit(t, &t.m.OutputType) }
func (t methodDesc) IsStreamingClient() bool { return t.m.IsStreamingClient }
func (t methodDesc) IsStreamingServer() bool { return t.m.IsStreamingServer }
func (t methodDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t methodDesc) ProtoType(pref.MethodDescriptor) {}
func (t methodDesc) ProtoInternal(pragma.DoNotImplement) {}
func (t methodDesc) Parent() (pref.Descriptor, bool) { return t.m.parent, true }
func (t methodDesc) Index() int { return t.m.index }
func (t methodDesc) Syntax() pref.Syntax { return t.m.syntax }
func (t methodDesc) Name() pref.Name { return t.m.Name }
func (t methodDesc) FullName() pref.FullName { return t.m.fullName }
func (t methodDesc) IsPlaceholder() bool { return false }
func (t methodDesc) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t methodDesc) Options() interface{} { return t.m.Options }
func (t methodDesc) InputType() pref.MessageDescriptor { return t.m.mit.lazyInit(t, &t.m.InputType) }
func (t methodDesc) OutputType() pref.MessageDescriptor { return t.m.mot.lazyInit(t, &t.m.OutputType) }
func (t methodDesc) IsStreamingClient() bool { return t.m.IsStreamingClient }
func (t methodDesc) IsStreamingServer() bool { return t.m.IsStreamingServer }
func (t methodDesc) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t methodDesc) ProtoType(pref.MethodDescriptor) {}
func (t methodDesc) ProtoInternal(pragma.DoNotImplement) {}
type defaultValue struct {
once sync.Once

View File

@ -5,6 +5,7 @@
package prototype
import (
descriptorV1 "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/v2/internal/errors"
"github.com/golang/protobuf/v2/reflect/protoreflect"
)
@ -17,10 +18,10 @@ import (
type StandaloneMessage struct {
Syntax protoreflect.Syntax
FullName protoreflect.FullName
IsMapEntry bool
Fields []Field
Oneofs []Oneof
ExtensionRanges [][2]protoreflect.FieldNumber
Options *descriptorV1.MessageOptions
fields fieldsMeta
oneofs oneofsMeta
@ -63,7 +64,7 @@ func NewMessages(ts []*StandaloneMessage) ([]protoreflect.MessageDescriptor, err
for i, f := range t.Fields {
// Resolve placeholder messages with a concrete standalone message.
// If this fails, validateMessage will complain about it later.
if !f.IsWeak && f.MessageType != nil && f.MessageType.IsPlaceholder() {
if !f.Options.GetWeak() && f.MessageType != nil && f.MessageType.IsPlaceholder() {
if m, ok := ms[f.MessageType.FullName()]; ok {
t.Fields[i].MessageType = m
}
@ -84,6 +85,7 @@ type StandaloneEnum struct {
Syntax protoreflect.Syntax
FullName protoreflect.FullName
Values []EnumValue
Options *descriptorV1.EnumOptions
vals enumValuesMeta
}
@ -107,11 +109,11 @@ type StandaloneExtension struct {
Number protoreflect.FieldNumber
Cardinality protoreflect.Cardinality
Kind protoreflect.Kind
IsPacked bool
Default protoreflect.Value
MessageType protoreflect.MessageDescriptor
EnumType protoreflect.EnumDescriptor
ExtendedType protoreflect.MessageDescriptor
Options *descriptorV1.FieldOptions
dv defaultValue
}

View File

@ -13,64 +13,64 @@ import (
type standaloneMessage struct{ m *StandaloneMessage }
func (t standaloneMessage) Parent() (pref.Descriptor, bool) { return nil, false }
func (t standaloneMessage) Index() int { return 0 }
func (t standaloneMessage) Syntax() pref.Syntax { return t.m.Syntax }
func (t standaloneMessage) Name() pref.Name { return t.m.FullName.Name() }
func (t standaloneMessage) FullName() pref.FullName { return t.m.FullName }
func (t standaloneMessage) IsPlaceholder() bool { return false }
func (t standaloneMessage) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t standaloneMessage) DescriptorOptions() (pref.DescriptorOptions, bool) { return nil, false }
func (t standaloneMessage) IsMapEntry() bool { return t.m.IsMapEntry }
func (t standaloneMessage) Fields() pref.FieldDescriptors { return t.m.fields.lazyInit(t, t.m.Fields) }
func (t standaloneMessage) Oneofs() pref.OneofDescriptors { return t.m.oneofs.lazyInit(t, t.m.Oneofs) }
func (t standaloneMessage) RequiredNumbers() pref.FieldNumbers { return t.m.nums.lazyInit(t.m.Fields) }
func (t standaloneMessage) ExtensionRanges() pref.FieldRanges { return (*ranges)(&t.m.ExtensionRanges) }
func (t standaloneMessage) Messages() pref.MessageDescriptors { return &emptyMessages }
func (t standaloneMessage) Enums() pref.EnumDescriptors { return &emptyEnums }
func (t standaloneMessage) Extensions() pref.ExtensionDescriptors { return &emptyExtensions }
func (t standaloneMessage) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t standaloneMessage) ProtoType(pref.MessageDescriptor) {}
func (t standaloneMessage) ProtoInternal(pragma.DoNotImplement) {}
func (t standaloneMessage) Parent() (pref.Descriptor, bool) { return nil, false }
func (t standaloneMessage) Index() int { return 0 }
func (t standaloneMessage) Syntax() pref.Syntax { return t.m.Syntax }
func (t standaloneMessage) Name() pref.Name { return t.m.FullName.Name() }
func (t standaloneMessage) FullName() pref.FullName { return t.m.FullName }
func (t standaloneMessage) IsPlaceholder() bool { return false }
func (t standaloneMessage) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t standaloneMessage) Options() interface{} { return t.m.Options }
func (t standaloneMessage) IsMapEntry() bool { return t.m.Options.GetMapEntry() }
func (t standaloneMessage) Fields() pref.FieldDescriptors { return t.m.fields.lazyInit(t, t.m.Fields) }
func (t standaloneMessage) Oneofs() pref.OneofDescriptors { return t.m.oneofs.lazyInit(t, t.m.Oneofs) }
func (t standaloneMessage) RequiredNumbers() pref.FieldNumbers { return t.m.nums.lazyInit(t.m.Fields) }
func (t standaloneMessage) ExtensionRanges() pref.FieldRanges { return (*ranges)(&t.m.ExtensionRanges) }
func (t standaloneMessage) Messages() pref.MessageDescriptors { return &emptyMessages }
func (t standaloneMessage) Enums() pref.EnumDescriptors { return &emptyEnums }
func (t standaloneMessage) Extensions() pref.ExtensionDescriptors { return &emptyExtensions }
func (t standaloneMessage) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t standaloneMessage) ProtoType(pref.MessageDescriptor) {}
func (t standaloneMessage) ProtoInternal(pragma.DoNotImplement) {}
type standaloneEnum struct{ e *StandaloneEnum }
func (t standaloneEnum) Parent() (pref.Descriptor, bool) { return nil, false }
func (t standaloneEnum) Index() int { return 0 }
func (t standaloneEnum) Syntax() pref.Syntax { return t.e.Syntax }
func (t standaloneEnum) Name() pref.Name { return t.e.FullName.Name() }
func (t standaloneEnum) FullName() pref.FullName { return t.e.FullName }
func (t standaloneEnum) IsPlaceholder() bool { return false }
func (t standaloneEnum) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t standaloneEnum) DescriptorOptions() (pref.DescriptorOptions, bool) { return nil, false }
func (t standaloneEnum) Values() pref.EnumValueDescriptors { return t.e.vals.lazyInit(t, t.e.Values) }
func (t standaloneEnum) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t standaloneEnum) ProtoType(pref.EnumDescriptor) {}
func (t standaloneEnum) ProtoInternal(pragma.DoNotImplement) {}
func (t standaloneEnum) Parent() (pref.Descriptor, bool) { return nil, false }
func (t standaloneEnum) Index() int { return 0 }
func (t standaloneEnum) Syntax() pref.Syntax { return t.e.Syntax }
func (t standaloneEnum) Name() pref.Name { return t.e.FullName.Name() }
func (t standaloneEnum) FullName() pref.FullName { return t.e.FullName }
func (t standaloneEnum) IsPlaceholder() bool { return false }
func (t standaloneEnum) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t standaloneEnum) Options() interface{} { return t.e.Options }
func (t standaloneEnum) Values() pref.EnumValueDescriptors { return t.e.vals.lazyInit(t, t.e.Values) }
func (t standaloneEnum) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t standaloneEnum) ProtoType(pref.EnumDescriptor) {}
func (t standaloneEnum) ProtoInternal(pragma.DoNotImplement) {}
type standaloneExtension struct{ x *StandaloneExtension }
func (t standaloneExtension) Parent() (pref.Descriptor, bool) { return nil, false }
func (t standaloneExtension) Index() int { return 0 }
func (t standaloneExtension) Syntax() pref.Syntax { return t.x.Syntax }
func (t standaloneExtension) Name() pref.Name { return t.x.FullName.Name() }
func (t standaloneExtension) FullName() pref.FullName { return t.x.FullName }
func (t standaloneExtension) IsPlaceholder() bool { return false }
func (t standaloneExtension) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t standaloneExtension) DescriptorOptions() (pref.DescriptorOptions, bool) { return nil, false }
func (t standaloneExtension) Number() pref.FieldNumber { return t.x.Number }
func (t standaloneExtension) Cardinality() pref.Cardinality { return t.x.Cardinality }
func (t standaloneExtension) Kind() pref.Kind { return t.x.Kind }
func (t standaloneExtension) JSONName() string { return "" }
func (t standaloneExtension) IsPacked() bool { return t.x.IsPacked }
func (t standaloneExtension) IsMap() bool { return false }
func (t standaloneExtension) IsWeak() bool { return false }
func (t standaloneExtension) Default() pref.Value { return t.x.dv.lazyInit(t, t.x.Default) }
func (t standaloneExtension) HasDefault() bool { return t.x.Default.IsValid() }
func (t standaloneExtension) OneofType() pref.OneofDescriptor { return nil }
func (t standaloneExtension) MessageType() pref.MessageDescriptor { return t.x.MessageType }
func (t standaloneExtension) EnumType() pref.EnumDescriptor { return t.x.EnumType }
func (t standaloneExtension) ExtendedType() pref.MessageDescriptor { return t.x.ExtendedType }
func (t standaloneExtension) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t standaloneExtension) ProtoType(pref.FieldDescriptor) {}
func (t standaloneExtension) ProtoInternal(pragma.DoNotImplement) {}
func (t standaloneExtension) Parent() (pref.Descriptor, bool) { return nil, false }
func (t standaloneExtension) Index() int { return 0 }
func (t standaloneExtension) Syntax() pref.Syntax { return t.x.Syntax }
func (t standaloneExtension) Name() pref.Name { return t.x.FullName.Name() }
func (t standaloneExtension) FullName() pref.FullName { return t.x.FullName }
func (t standaloneExtension) IsPlaceholder() bool { return false }
func (t standaloneExtension) DescriptorProto() (pref.Message, bool) { return nil, false }
func (t standaloneExtension) Options() interface{} { return t.x.Options }
func (t standaloneExtension) Number() pref.FieldNumber { return t.x.Number }
func (t standaloneExtension) Cardinality() pref.Cardinality { return t.x.Cardinality }
func (t standaloneExtension) Kind() pref.Kind { return t.x.Kind }
func (t standaloneExtension) JSONName() string { return "" }
func (t standaloneExtension) IsPacked() bool { return t.x.Options.GetPacked() }
func (t standaloneExtension) IsMap() bool { return false }
func (t standaloneExtension) IsWeak() bool { return false }
func (t standaloneExtension) Default() pref.Value { return t.x.dv.lazyInit(t, t.x.Default) }
func (t standaloneExtension) HasDefault() bool { return t.x.Default.IsValid() }
func (t standaloneExtension) OneofType() pref.OneofDescriptor { return nil }
func (t standaloneExtension) MessageType() pref.MessageDescriptor { return t.x.MessageType }
func (t standaloneExtension) EnumType() pref.EnumDescriptor { return t.x.EnumType }
func (t standaloneExtension) ExtendedType() pref.MessageDescriptor { return t.x.ExtendedType }
func (t standaloneExtension) Format(s fmt.State, r rune) { formatDesc(s, r, t) }
func (t standaloneExtension) ProtoType(pref.FieldDescriptor) {}
func (t standaloneExtension) ProtoInternal(pragma.DoNotImplement) {}

View File

@ -109,12 +109,17 @@ func TestFile(t *testing.T) {
Syntax: pref.Proto2,
Path: "path/to/file.proto",
Package: "test",
Options: &descriptorV1.FileOptions{Deprecated: protoV1.Bool(true)},
Messages: []Message{{
Name: "A", // "test.A"
IsMapEntry: true,
Name: "A", // "test.A"
Options: &descriptorV1.MessageOptions{
MapEntry: protoV1.Bool(true),
Deprecated: protoV1.Bool(true),
},
Fields: []Field{{
Name: "key", // "test.A.key"
Number: 1,
Options: &descriptorV1.FieldOptions{Deprecated: protoV1.Bool(true)},
Cardinality: pref.Optional,
Kind: pref.StringKind,
}, {
@ -161,7 +166,7 @@ func TestFile(t *testing.T) {
Number: 5,
Cardinality: pref.Repeated,
Kind: pref.Int32Kind,
IsPacked: true,
Options: &descriptorV1.FieldOptions{Packed: protoV1.Bool(true)},
}, {
Name: "field_six", // "test.B.field_six"
Number: 6,
@ -169,7 +174,14 @@ func TestFile(t *testing.T) {
Kind: pref.BytesKind,
}},
Oneofs: []Oneof{
{Name: "O1"}, // "test.B.O1"
{
Name: "O1", // "test.B.O1"
Options: &descriptorV1.OneofOptions{
UninterpretedOption: []*descriptorV1.UninterpretedOption{
{StringValue: []byte("option")},
},
},
},
{Name: "O2"}, // "test.B.O2"
},
ExtensionRanges: [][2]pref.FieldNumber{{1000, 2000}, {3000, 3001}},
@ -188,32 +200,42 @@ func TestFile(t *testing.T) {
Number: 1000,
Cardinality: pref.Repeated,
Kind: pref.MessageKind,
IsPacked: false,
Options: &descriptorV1.FieldOptions{Packed: protoV1.Bool(false)},
MessageType: PlaceholderMessage("test.C"),
ExtendedType: PlaceholderMessage("test.B"),
}},
}},
Enums: []Enum{{
Name: "E1", // "test.E1"
Values: []EnumValue{{Name: "FOO", Number: 0}, {Name: "BAR", Number: 1}},
Name: "E1", // "test.E1"
Options: &descriptorV1.EnumOptions{Deprecated: protoV1.Bool(true)},
Values: []EnumValue{
{
Name: "FOO",
Number: 0,
Options: &descriptorV1.EnumValueOptions{Deprecated: protoV1.Bool(true)},
},
{Name: "BAR", Number: 1},
},
}},
Extensions: []Extension{{
Name: "X", // "test.X"
Number: 1000,
Cardinality: pref.Repeated,
Kind: pref.MessageKind,
IsPacked: true,
Options: &descriptorV1.FieldOptions{Packed: protoV1.Bool(true)},
MessageType: PlaceholderMessage("test.C"),
ExtendedType: PlaceholderMessage("test.B"),
}},
Services: []Service{{
Name: "S", // "test.S"
Name: "S", // "test.S"
Options: &descriptorV1.ServiceOptions{Deprecated: protoV1.Bool(true)},
Methods: []Method{{
Name: "M", // "test.S.M"
InputType: PlaceholderMessage("test.A"),
OutputType: PlaceholderMessage("test.C.A"),
IsStreamingClient: true,
IsStreamingServer: true,
Options: &descriptorV1.MethodOptions{Deprecated: protoV1.Bool(true)},
}},
}},
}
@ -226,14 +248,19 @@ func TestFile(t *testing.T) {
Syntax: protoV1.String("proto2"),
Name: protoV1.String("path/to/file.proto"),
Package: protoV1.String("test"),
Options: &descriptorV1.FileOptions{Deprecated: protoV1.Bool(true)},
MessageType: []*descriptorV1.DescriptorProto{{
Name: protoV1.String("A"),
Options: &descriptorV1.MessageOptions{MapEntry: protoV1.Bool(true)},
Name: protoV1.String("A"),
Options: &descriptorV1.MessageOptions{
MapEntry: protoV1.Bool(true),
Deprecated: protoV1.Bool(true),
},
Field: []*descriptorV1.FieldDescriptorProto{{
Name: protoV1.String("key"),
Number: protoV1.Int32(1),
Label: descriptorV1.FieldDescriptorProto_Label(pref.Optional).Enum(),
Type: descriptorV1.FieldDescriptorProto_Type(pref.StringKind).Enum(),
Name: protoV1.String("key"),
Number: protoV1.Int32(1),
Options: &descriptorV1.FieldOptions{Deprecated: protoV1.Bool(true)},
Label: descriptorV1.FieldDescriptorProto_Label(pref.Optional).Enum(),
Type: descriptorV1.FieldDescriptorProto_Type(pref.StringKind).Enum(),
}, {
Name: protoV1.String("value"),
Number: protoV1.Int32(2),
@ -286,7 +313,14 @@ func TestFile(t *testing.T) {
Type: descriptorV1.FieldDescriptorProto_Type(pref.BytesKind).Enum(),
}},
OneofDecl: []*descriptorV1.OneofDescriptorProto{
{Name: protoV1.String("O1")},
{
Name: protoV1.String("O1"),
Options: &descriptorV1.OneofOptions{
UninterpretedOption: []*descriptorV1.UninterpretedOption{
{StringValue: []byte("option")},
},
},
},
{Name: protoV1.String("O2")},
},
ExtensionRange: []*descriptorV1.DescriptorProto_ExtensionRange{
@ -322,9 +356,14 @@ func TestFile(t *testing.T) {
}},
}},
EnumType: []*descriptorV1.EnumDescriptorProto{{
Name: protoV1.String("E1"),
Name: protoV1.String("E1"),
Options: &descriptorV1.EnumOptions{Deprecated: protoV1.Bool(true)},
Value: []*descriptorV1.EnumValueDescriptorProto{
{Name: protoV1.String("FOO"), Number: protoV1.Int32(0)},
{
Name: protoV1.String("FOO"),
Number: protoV1.Int32(0),
Options: &descriptorV1.EnumValueOptions{Deprecated: protoV1.Bool(true)},
},
{Name: protoV1.String("BAR"), Number: protoV1.Int32(1)},
},
}},
@ -338,13 +377,15 @@ func TestFile(t *testing.T) {
Extendee: protoV1.String(".test.B"),
}},
Service: []*descriptorV1.ServiceDescriptorProto{{
Name: protoV1.String("S"),
Name: protoV1.String("S"),
Options: &descriptorV1.ServiceOptions{Deprecated: protoV1.Bool(true)},
Method: []*descriptorV1.MethodDescriptorProto{{
Name: protoV1.String("M"),
InputType: protoV1.String(".test.A"),
OutputType: protoV1.String(".test.C.A"),
ClientStreaming: protoV1.Bool(true),
ServerStreaming: protoV1.Bool(true),
Options: &descriptorV1.MethodOptions{Deprecated: protoV1.Bool(true)},
}},
}},
}
@ -385,6 +426,7 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"Path": "path/to/file.proto",
"Package": pref.FullName("test"),
"IsPlaceholder": false,
"Options": &descriptorV1.FileOptions{Deprecated: protoV1.Bool(true)},
"Messages": M{
"Len": 3,
"Get:0": M{
@ -395,6 +437,10 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"FullName": pref.FullName("test.A"),
"IsPlaceholder": false,
"IsMapEntry": true,
"Options": &descriptorV1.MessageOptions{
MapEntry: protoV1.Bool(true),
Deprecated: protoV1.Bool(true),
},
"Fields": M{
"Len": 2,
"ByNumber:1": M{
@ -405,6 +451,7 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"Number": pref.FieldNumber(1),
"Cardinality": pref.Optional,
"Kind": pref.StringKind,
"Options": &descriptorV1.FieldOptions{Deprecated: protoV1.Bool(true)},
"JSONName": "key",
"IsPacked": false,
"IsMap": false,
@ -494,6 +541,11 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"ByName:O1": M{
"FullName": pref.FullName("test.B.O1"),
"Index": 0,
"Options": &descriptorV1.OneofOptions{
UninterpretedOption: []*descriptorV1.UninterpretedOption{
{StringValue: []byte("option")},
},
},
"Fields": M{
"Len": 1,
"Get:0": M{"FullName": pref.FullName("test.B.field_one")},
@ -546,11 +598,15 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"Enums": M{
"Len": 1,
"Get:0": M{
"Name": pref.Name("E1"),
"Name": pref.Name("E1"),
"Options": &descriptorV1.EnumOptions{Deprecated: protoV1.Bool(true)},
"Values": M{
"Len": 2,
"ByName:Foo": nil,
"ByName:FOO": M{"FullName": pref.FullName("test.FOO")},
"ByName:FOO": M{
"FullName": pref.FullName("test.FOO"),
"Options": &descriptorV1.EnumValueOptions{Deprecated: protoV1.Bool(true)},
},
"ByNumber:2": nil,
"ByNumber:1": M{"FullName": pref.FullName("test.BAR")},
},
@ -566,6 +622,7 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"IsPacked": true,
"MessageType": M{"FullName": pref.FullName("test.C"), "IsPlaceholder": false},
"ExtendedType": M{"FullName": pref.FullName("test.B"), "IsPlaceholder": false},
"Options": &descriptorV1.FieldOptions{Packed: protoV1.Bool(true)},
},
},
"Services": M{
@ -575,6 +632,7 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"Parent": M{"FullName": pref.FullName("test")},
"Name": pref.Name("S"),
"FullName": pref.FullName("test.S"),
"Options": &descriptorV1.ServiceOptions{Deprecated: protoV1.Bool(true)},
"Methods": M{
"Len": 1,
"Get:0": M{
@ -585,6 +643,7 @@ func testFileAccessors(t *testing.T, fd pref.FileDescriptor) {
"OutputType": M{"FullName": pref.FullName("test.C.A"), "IsPlaceholder": false},
"IsStreamingClient": true,
"IsStreamingServer": true,
"Options": &descriptorV1.MethodOptions{Deprecated: protoV1.Bool(true)},
},
},
},
@ -659,14 +718,26 @@ func checkAccessors(t *testing.T, p string, rv reflect.Value, want map[string]in
// Check that the accessor output matches.
if want, ok := v.(map[string]interface{}); ok {
checkAccessors(t, p, rets[0], want)
} else {
got := rets[0].Interface()
if pv, ok := got.(pref.Value); ok {
got = pv.Interface()
}
if want := v; !reflect.DeepEqual(got, want) {
continue
}
got := rets[0].Interface()
if pv, ok := got.(pref.Value); ok {
got = pv.Interface()
}
// Compare with proto.Equal if possible.
gotMsg, gotMsgOK := got.(protoV1.Message)
wantMsg, wantMsgOK := v.(protoV1.Message)
if gotMsgOK && wantMsgOK {
if !protoV1.Equal(gotMsg, wantMsg) {
t.Errorf("%v = %v, want %v", p, got, want)
}
continue
}
if want := v; !reflect.DeepEqual(got, want) {
t.Errorf("%v = %v, want %v", p, got, want)
}
}
}

View File

@ -26,6 +26,9 @@ import (
// * Placeholder messages and types may only be for weak fields.
// * Placeholder full names must be valid.
// * The name of each descriptor must be valid.
// * Options are consistent with constructor fields:
// Message.IsMapEntry and Message.Options.MapEntry
// Field.IsPacked and Field.Options.Packed
func validateFile(t pref.FileDescriptor) error {
return nil