[VOL-4442] grpc streaming connection monitoring
Change-Id: I8a361473a252f6d2b64578a97980b2b7b3618f55
diff --git a/vendor/github.com/jhump/protoreflect/desc/convert.go b/vendor/github.com/jhump/protoreflect/desc/convert.go
new file mode 100644
index 0000000..538820c
--- /dev/null
+++ b/vendor/github.com/jhump/protoreflect/desc/convert.go
@@ -0,0 +1,231 @@
+package desc
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+
+ dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
+
+ "github.com/jhump/protoreflect/desc/internal"
+ intn "github.com/jhump/protoreflect/internal"
+)
+
+// CreateFileDescriptor instantiates a new file descriptor for the given descriptor proto.
+// The file's direct dependencies must be provided. If the given dependencies do not include
+// all of the file's dependencies or if the contents of the descriptors are internally
+// inconsistent (e.g. contain unresolvable symbols) then an error is returned.
+func CreateFileDescriptor(fd *dpb.FileDescriptorProto, deps ...*FileDescriptor) (*FileDescriptor, error) {
+ return createFileDescriptor(fd, deps, nil)
+}
+
+func createFileDescriptor(fd *dpb.FileDescriptorProto, deps []*FileDescriptor, r *ImportResolver) (*FileDescriptor, error) {
+ ret := &FileDescriptor{
+ proto: fd,
+ symbols: map[string]Descriptor{},
+ fieldIndex: map[string]map[int32]*FieldDescriptor{},
+ }
+ pkg := fd.GetPackage()
+
+ // populate references to file descriptor dependencies
+ files := map[string]*FileDescriptor{}
+ for _, f := range deps {
+ files[f.proto.GetName()] = f
+ }
+ ret.deps = make([]*FileDescriptor, len(fd.GetDependency()))
+ for i, d := range fd.GetDependency() {
+ resolved := r.ResolveImport(fd.GetName(), d)
+ ret.deps[i] = files[resolved]
+ if ret.deps[i] == nil {
+ if resolved != d {
+ ret.deps[i] = files[d]
+ }
+ if ret.deps[i] == nil {
+ return nil, intn.ErrNoSuchFile(d)
+ }
+ }
+ }
+ ret.publicDeps = make([]*FileDescriptor, len(fd.GetPublicDependency()))
+ for i, pd := range fd.GetPublicDependency() {
+ ret.publicDeps[i] = ret.deps[pd]
+ }
+ ret.weakDeps = make([]*FileDescriptor, len(fd.GetWeakDependency()))
+ for i, wd := range fd.GetWeakDependency() {
+ ret.weakDeps[i] = ret.deps[wd]
+ }
+ ret.isProto3 = fd.GetSyntax() == "proto3"
+
+ // populate all tables of child descriptors
+ for _, m := range fd.GetMessageType() {
+ md, n := createMessageDescriptor(ret, ret, pkg, m, ret.symbols)
+ ret.symbols[n] = md
+ ret.messages = append(ret.messages, md)
+ }
+ for _, e := range fd.GetEnumType() {
+ ed, n := createEnumDescriptor(ret, ret, pkg, e, ret.symbols)
+ ret.symbols[n] = ed
+ ret.enums = append(ret.enums, ed)
+ }
+ for _, ex := range fd.GetExtension() {
+ exd, n := createFieldDescriptor(ret, ret, pkg, ex)
+ ret.symbols[n] = exd
+ ret.extensions = append(ret.extensions, exd)
+ }
+ for _, s := range fd.GetService() {
+ sd, n := createServiceDescriptor(ret, pkg, s, ret.symbols)
+ ret.symbols[n] = sd
+ ret.services = append(ret.services, sd)
+ }
+
+ ret.sourceInfo = internal.CreateSourceInfoMap(fd)
+ ret.sourceInfoRecomputeFunc = ret.recomputeSourceInfo
+
+ // now we can resolve all type references and source code info
+ scopes := []scope{fileScope(ret)}
+ path := make([]int32, 1, 8)
+ path[0] = internal.File_messagesTag
+ for i, md := range ret.messages {
+ if err := md.resolve(append(path, int32(i)), scopes); err != nil {
+ return nil, err
+ }
+ }
+ path[0] = internal.File_enumsTag
+ for i, ed := range ret.enums {
+ ed.resolve(append(path, int32(i)))
+ }
+ path[0] = internal.File_extensionsTag
+ for i, exd := range ret.extensions {
+ if err := exd.resolve(append(path, int32(i)), scopes); err != nil {
+ return nil, err
+ }
+ }
+ path[0] = internal.File_servicesTag
+ for i, sd := range ret.services {
+ if err := sd.resolve(append(path, int32(i)), scopes); err != nil {
+ return nil, err
+ }
+ }
+
+ return ret, nil
+}
+
+// CreateFileDescriptors constructs a set of descriptors, one for each of the
+// given descriptor protos. The given set of descriptor protos must include all
+// transitive dependencies for every file.
+func CreateFileDescriptors(fds []*dpb.FileDescriptorProto) (map[string]*FileDescriptor, error) {
+ return createFileDescriptors(fds, nil)
+}
+
+func createFileDescriptors(fds []*dpb.FileDescriptorProto, r *ImportResolver) (map[string]*FileDescriptor, error) {
+ if len(fds) == 0 {
+ return nil, nil
+ }
+ files := map[string]*dpb.FileDescriptorProto{}
+ resolved := map[string]*FileDescriptor{}
+ var name string
+ for _, fd := range fds {
+ name = fd.GetName()
+ files[name] = fd
+ }
+ for _, fd := range fds {
+ _, err := createFromSet(fd.GetName(), r, nil, files, resolved)
+ if err != nil {
+ return nil, err
+ }
+ }
+ return resolved, nil
+}
+
+// ToFileDescriptorSet creates a FileDescriptorSet proto that contains all of the given
+// file descriptors and their transitive dependencies. The files are topologically sorted
+// so that a file will always appear after its dependencies.
+func ToFileDescriptorSet(fds ...*FileDescriptor) *dpb.FileDescriptorSet {
+ var fdps []*dpb.FileDescriptorProto
+ addAllFiles(fds, &fdps, map[string]struct{}{})
+ return &dpb.FileDescriptorSet{File: fdps}
+}
+
+func addAllFiles(src []*FileDescriptor, results *[]*dpb.FileDescriptorProto, seen map[string]struct{}) {
+ for _, fd := range src {
+ if _, ok := seen[fd.GetName()]; ok {
+ continue
+ }
+ seen[fd.GetName()] = struct{}{}
+ addAllFiles(fd.GetDependencies(), results, seen)
+ *results = append(*results, fd.AsFileDescriptorProto())
+ }
+}
+
+// CreateFileDescriptorFromSet creates a descriptor from the given file descriptor set. The
+// set's *last* file will be the returned descriptor. The set's remaining files must comprise
+// the full set of transitive dependencies of that last file. This is the same format and
+// order used by protoc when emitting a FileDescriptorSet file with an invocation like so:
+// protoc --descriptor_set_out=./test.protoset --include_imports -I. test.proto
+func CreateFileDescriptorFromSet(fds *dpb.FileDescriptorSet) (*FileDescriptor, error) {
+ return createFileDescriptorFromSet(fds, nil)
+}
+
+func createFileDescriptorFromSet(fds *dpb.FileDescriptorSet, r *ImportResolver) (*FileDescriptor, error) {
+ result, err := createFileDescriptorsFromSet(fds, r)
+ if err != nil {
+ return nil, err
+ }
+ files := fds.GetFile()
+ lastFilename := files[len(files)-1].GetName()
+ return result[lastFilename], nil
+}
+
+// CreateFileDescriptorsFromSet creates file descriptors from the given file descriptor set.
+// The returned map includes all files in the set, keyed b name. The set must include the
+// full set of transitive dependencies for all files therein or else a link error will occur
+// and be returned instead of the slice of descriptors. This is the same format used by
+// protoc when a FileDescriptorSet file with an invocation like so:
+// protoc --descriptor_set_out=./test.protoset --include_imports -I. test.proto
+func CreateFileDescriptorsFromSet(fds *dpb.FileDescriptorSet) (map[string]*FileDescriptor, error) {
+ return createFileDescriptorsFromSet(fds, nil)
+}
+
+func createFileDescriptorsFromSet(fds *dpb.FileDescriptorSet, r *ImportResolver) (map[string]*FileDescriptor, error) {
+ files := fds.GetFile()
+ if len(files) == 0 {
+ return nil, errors.New("file descriptor set is empty")
+ }
+ return createFileDescriptors(files, r)
+}
+
+// createFromSet creates a descriptor for the given filename. It recursively
+// creates descriptors for the given file's dependencies.
+func createFromSet(filename string, r *ImportResolver, seen []string, files map[string]*dpb.FileDescriptorProto, resolved map[string]*FileDescriptor) (*FileDescriptor, error) {
+ for _, s := range seen {
+ if filename == s {
+ return nil, fmt.Errorf("cycle in imports: %s", strings.Join(append(seen, filename), " -> "))
+ }
+ }
+ seen = append(seen, filename)
+
+ if d, ok := resolved[filename]; ok {
+ return d, nil
+ }
+ fdp := files[filename]
+ if fdp == nil {
+ return nil, intn.ErrNoSuchFile(filename)
+ }
+ deps := make([]*FileDescriptor, len(fdp.GetDependency()))
+ for i, depName := range fdp.GetDependency() {
+ resolvedDep := r.ResolveImport(filename, depName)
+ dep, err := createFromSet(resolvedDep, r, seen, files, resolved)
+ if _, ok := err.(intn.ErrNoSuchFile); ok && resolvedDep != depName {
+ dep, err = createFromSet(depName, r, seen, files, resolved)
+ }
+ if err != nil {
+ return nil, err
+ }
+ deps[i] = dep
+ }
+ d, err := createFileDescriptor(fdp, deps, r)
+ if err != nil {
+ return nil, err
+ }
+ resolved[filename] = d
+ return d, nil
+}
diff --git a/vendor/github.com/jhump/protoreflect/desc/descriptor.go b/vendor/github.com/jhump/protoreflect/desc/descriptor.go
new file mode 100644
index 0000000..42f0f8e
--- /dev/null
+++ b/vendor/github.com/jhump/protoreflect/desc/descriptor.go
@@ -0,0 +1,1723 @@
+package desc
+
+import (
+ "bytes"
+ "fmt"
+ "sort"
+ "strconv"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "github.com/golang/protobuf/proto"
+ dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
+
+ "github.com/jhump/protoreflect/desc/internal"
+)
+
+// Descriptor is the common interface implemented by all descriptor objects.
+type Descriptor interface {
+ // GetName returns the name of the object described by the descriptor. This will
+ // be a base name that does not include enclosing message names or the package name.
+ // For file descriptors, this indicates the path and name to the described file.
+ GetName() string
+ // GetFullyQualifiedName returns the fully-qualified name of the object described by
+ // the descriptor. This will include the package name and any enclosing message names.
+ // For file descriptors, this returns the path and name to the described file (same as
+ // GetName).
+ GetFullyQualifiedName() string
+ // GetParent returns the enclosing element in a proto source file. If the described
+ // object is a top-level object, this returns the file descriptor. Otherwise, it returns
+ // the element in which the described object was declared. File descriptors have no
+ // parent and return nil.
+ GetParent() Descriptor
+ // GetFile returns the file descriptor in which this element was declared. File
+ // descriptors return themselves.
+ GetFile() *FileDescriptor
+ // GetOptions returns the options proto containing options for the described element.
+ GetOptions() proto.Message
+ // GetSourceInfo returns any source code information that was present in the file
+ // descriptor. Source code info is optional. If no source code info is available for
+ // the element (including if there is none at all in the file descriptor) then this
+ // returns nil
+ GetSourceInfo() *dpb.SourceCodeInfo_Location
+ // AsProto returns the underlying descriptor proto for this descriptor.
+ AsProto() proto.Message
+}
+
+type sourceInfoRecomputeFunc = internal.SourceInfoComputeFunc
+
+// FileDescriptor describes a proto source file.
+type FileDescriptor struct {
+ proto *dpb.FileDescriptorProto
+ symbols map[string]Descriptor
+ deps []*FileDescriptor
+ publicDeps []*FileDescriptor
+ weakDeps []*FileDescriptor
+ messages []*MessageDescriptor
+ enums []*EnumDescriptor
+ extensions []*FieldDescriptor
+ services []*ServiceDescriptor
+ fieldIndex map[string]map[int32]*FieldDescriptor
+ isProto3 bool
+ sourceInfo internal.SourceInfoMap
+ sourceInfoRecomputeFunc
+}
+
+func (fd *FileDescriptor) recomputeSourceInfo() {
+ internal.PopulateSourceInfoMap(fd.proto, fd.sourceInfo)
+}
+
+func (fd *FileDescriptor) registerField(field *FieldDescriptor) {
+ fields := fd.fieldIndex[field.owner.GetFullyQualifiedName()]
+ if fields == nil {
+ fields = map[int32]*FieldDescriptor{}
+ fd.fieldIndex[field.owner.GetFullyQualifiedName()] = fields
+ }
+ fields[field.GetNumber()] = field
+}
+
+// GetName returns the name of the file, as it was given to the protoc invocation
+// to compile it, possibly including path (relative to a directory in the proto
+// import path).
+func (fd *FileDescriptor) GetName() string {
+ return fd.proto.GetName()
+}
+
+// GetFullyQualifiedName returns the name of the file, same as GetName. It is
+// present to satisfy the Descriptor interface.
+func (fd *FileDescriptor) GetFullyQualifiedName() string {
+ return fd.proto.GetName()
+}
+
+// GetPackage returns the name of the package declared in the file.
+func (fd *FileDescriptor) GetPackage() string {
+ return fd.proto.GetPackage()
+}
+
+// GetParent always returns nil: files are the root of descriptor hierarchies.
+// Is it present to satisfy the Descriptor interface.
+func (fd *FileDescriptor) GetParent() Descriptor {
+ return nil
+}
+
+// GetFile returns the receiver, which is a file descriptor. This is present
+// to satisfy the Descriptor interface.
+func (fd *FileDescriptor) GetFile() *FileDescriptor {
+ return fd
+}
+
+// GetOptions returns the file's options. Most usages will be more interested
+// in GetFileOptions, which has a concrete return type. This generic version
+// is present to satisfy the Descriptor interface.
+func (fd *FileDescriptor) GetOptions() proto.Message {
+ return fd.proto.GetOptions()
+}
+
+// GetFileOptions returns the file's options.
+func (fd *FileDescriptor) GetFileOptions() *dpb.FileOptions {
+ return fd.proto.GetOptions()
+}
+
+// GetSourceInfo returns nil for files. It is present to satisfy the Descriptor
+// interface.
+func (fd *FileDescriptor) GetSourceInfo() *dpb.SourceCodeInfo_Location {
+ return nil
+}
+
+// AsProto returns the underlying descriptor proto. Most usages will be more
+// interested in AsFileDescriptorProto, which has a concrete return type. This
+// generic version is present to satisfy the Descriptor interface.
+func (fd *FileDescriptor) AsProto() proto.Message {
+ return fd.proto
+}
+
+// AsFileDescriptorProto returns the underlying descriptor proto.
+func (fd *FileDescriptor) AsFileDescriptorProto() *dpb.FileDescriptorProto {
+ return fd.proto
+}
+
+// String returns the underlying descriptor proto, in compact text format.
+func (fd *FileDescriptor) String() string {
+ return fd.proto.String()
+}
+
+// IsProto3 returns true if the file declares a syntax of "proto3".
+func (fd *FileDescriptor) IsProto3() bool {
+ return fd.isProto3
+}
+
+// GetDependencies returns all of this file's dependencies. These correspond to
+// import statements in the file.
+func (fd *FileDescriptor) GetDependencies() []*FileDescriptor {
+ return fd.deps
+}
+
+// GetPublicDependencies returns all of this file's public dependencies. These
+// correspond to public import statements in the file.
+func (fd *FileDescriptor) GetPublicDependencies() []*FileDescriptor {
+ return fd.publicDeps
+}
+
+// GetWeakDependencies returns all of this file's weak dependencies. These
+// correspond to weak import statements in the file.
+func (fd *FileDescriptor) GetWeakDependencies() []*FileDescriptor {
+ return fd.weakDeps
+}
+
+// GetMessageTypes returns all top-level messages declared in this file.
+func (fd *FileDescriptor) GetMessageTypes() []*MessageDescriptor {
+ return fd.messages
+}
+
+// GetEnumTypes returns all top-level enums declared in this file.
+func (fd *FileDescriptor) GetEnumTypes() []*EnumDescriptor {
+ return fd.enums
+}
+
+// GetExtensions returns all top-level extensions declared in this file.
+func (fd *FileDescriptor) GetExtensions() []*FieldDescriptor {
+ return fd.extensions
+}
+
+// GetServices returns all services declared in this file.
+func (fd *FileDescriptor) GetServices() []*ServiceDescriptor {
+ return fd.services
+}
+
+// FindSymbol returns the descriptor contained within this file for the
+// element with the given fully-qualified symbol name. If no such element
+// exists then this method returns nil.
+func (fd *FileDescriptor) FindSymbol(symbol string) Descriptor {
+ if symbol[0] == '.' {
+ symbol = symbol[1:]
+ }
+ if ret := fd.symbols[symbol]; ret != nil {
+ return ret
+ }
+
+ // allow accessing symbols through public imports, too
+ for _, dep := range fd.GetPublicDependencies() {
+ if ret := dep.FindSymbol(symbol); ret != nil {
+ return ret
+ }
+ }
+
+ // not found
+ return nil
+}
+
+// FindMessage finds the message with the given fully-qualified name. If no
+// such element exists in this file then nil is returned.
+func (fd *FileDescriptor) FindMessage(msgName string) *MessageDescriptor {
+ if md, ok := fd.symbols[msgName].(*MessageDescriptor); ok {
+ return md
+ } else {
+ return nil
+ }
+}
+
+// FindEnum finds the enum with the given fully-qualified name. If no such
+// element exists in this file then nil is returned.
+func (fd *FileDescriptor) FindEnum(enumName string) *EnumDescriptor {
+ if ed, ok := fd.symbols[enumName].(*EnumDescriptor); ok {
+ return ed
+ } else {
+ return nil
+ }
+}
+
+// FindService finds the service with the given fully-qualified name. If no
+// such element exists in this file then nil is returned.
+func (fd *FileDescriptor) FindService(serviceName string) *ServiceDescriptor {
+ if sd, ok := fd.symbols[serviceName].(*ServiceDescriptor); ok {
+ return sd
+ } else {
+ return nil
+ }
+}
+
+// FindExtension finds the extension field for the given extended type name and
+// tag number. If no such element exists in this file then nil is returned.
+func (fd *FileDescriptor) FindExtension(extendeeName string, tagNumber int32) *FieldDescriptor {
+ if exd, ok := fd.fieldIndex[extendeeName][tagNumber]; ok && exd.IsExtension() {
+ return exd
+ } else {
+ return nil
+ }
+}
+
+// FindExtensionByName finds the extension field with the given fully-qualified
+// name. If no such element exists in this file then nil is returned.
+func (fd *FileDescriptor) FindExtensionByName(extName string) *FieldDescriptor {
+ if exd, ok := fd.symbols[extName].(*FieldDescriptor); ok && exd.IsExtension() {
+ return exd
+ } else {
+ return nil
+ }
+}
+
+// MessageDescriptor describes a protocol buffer message.
+type MessageDescriptor struct {
+ proto *dpb.DescriptorProto
+ parent Descriptor
+ file *FileDescriptor
+ fields []*FieldDescriptor
+ nested []*MessageDescriptor
+ enums []*EnumDescriptor
+ extensions []*FieldDescriptor
+ oneOfs []*OneOfDescriptor
+ extRanges extRanges
+ fqn string
+ sourceInfoPath []int32
+ jsonNames jsonNameMap
+ isProto3 bool
+ isMapEntry bool
+}
+
+func createMessageDescriptor(fd *FileDescriptor, parent Descriptor, enclosing string, md *dpb.DescriptorProto, symbols map[string]Descriptor) (*MessageDescriptor, string) {
+ msgName := merge(enclosing, md.GetName())
+ ret := &MessageDescriptor{proto: md, parent: parent, file: fd, fqn: msgName}
+ for _, f := range md.GetField() {
+ fld, n := createFieldDescriptor(fd, ret, msgName, f)
+ symbols[n] = fld
+ ret.fields = append(ret.fields, fld)
+ }
+ for _, nm := range md.NestedType {
+ nmd, n := createMessageDescriptor(fd, ret, msgName, nm, symbols)
+ symbols[n] = nmd
+ ret.nested = append(ret.nested, nmd)
+ }
+ for _, e := range md.EnumType {
+ ed, n := createEnumDescriptor(fd, ret, msgName, e, symbols)
+ symbols[n] = ed
+ ret.enums = append(ret.enums, ed)
+ }
+ for _, ex := range md.GetExtension() {
+ exd, n := createFieldDescriptor(fd, ret, msgName, ex)
+ symbols[n] = exd
+ ret.extensions = append(ret.extensions, exd)
+ }
+ for i, o := range md.GetOneofDecl() {
+ od, n := createOneOfDescriptor(fd, ret, i, msgName, o)
+ symbols[n] = od
+ ret.oneOfs = append(ret.oneOfs, od)
+ }
+ for _, r := range md.GetExtensionRange() {
+ // proto.ExtensionRange is inclusive (and that's how extension ranges are defined in code).
+ // but protoc converts range to exclusive end in descriptor, so we must convert back
+ end := r.GetEnd() - 1
+ ret.extRanges = append(ret.extRanges, proto.ExtensionRange{
+ Start: r.GetStart(),
+ End: end})
+ }
+ sort.Sort(ret.extRanges)
+ ret.isProto3 = fd.isProto3
+ ret.isMapEntry = md.GetOptions().GetMapEntry() &&
+ len(ret.fields) == 2 &&
+ ret.fields[0].GetNumber() == 1 &&
+ ret.fields[1].GetNumber() == 2
+
+ return ret, msgName
+}
+
+func (md *MessageDescriptor) resolve(path []int32, scopes []scope) error {
+ md.sourceInfoPath = append([]int32(nil), path...) // defensive copy
+ path = append(path, internal.Message_nestedMessagesTag)
+ scopes = append(scopes, messageScope(md))
+ for i, nmd := range md.nested {
+ if err := nmd.resolve(append(path, int32(i)), scopes); err != nil {
+ return err
+ }
+ }
+ path[len(path)-1] = internal.Message_enumsTag
+ for i, ed := range md.enums {
+ ed.resolve(append(path, int32(i)))
+ }
+ path[len(path)-1] = internal.Message_fieldsTag
+ for i, fld := range md.fields {
+ if err := fld.resolve(append(path, int32(i)), scopes); err != nil {
+ return err
+ }
+ }
+ path[len(path)-1] = internal.Message_extensionsTag
+ for i, exd := range md.extensions {
+ if err := exd.resolve(append(path, int32(i)), scopes); err != nil {
+ return err
+ }
+ }
+ path[len(path)-1] = internal.Message_oneOfsTag
+ for i, od := range md.oneOfs {
+ od.resolve(append(path, int32(i)))
+ }
+ return nil
+}
+
+// GetName returns the simple (unqualified) name of the message.
+func (md *MessageDescriptor) GetName() string {
+ return md.proto.GetName()
+}
+
+// GetFullyQualifiedName returns the fully qualified name of the message. This
+// includes the package name (if there is one) as well as the names of any
+// enclosing messages.
+func (md *MessageDescriptor) GetFullyQualifiedName() string {
+ return md.fqn
+}
+
+// GetParent returns the message's enclosing descriptor. For top-level messages,
+// this will be a file descriptor. Otherwise it will be the descriptor for the
+// enclosing message.
+func (md *MessageDescriptor) GetParent() Descriptor {
+ return md.parent
+}
+
+// GetFile returns the descriptor for the file in which this message is defined.
+func (md *MessageDescriptor) GetFile() *FileDescriptor {
+ return md.file
+}
+
+// GetOptions returns the message's options. Most usages will be more interested
+// in GetMessageOptions, which has a concrete return type. This generic version
+// is present to satisfy the Descriptor interface.
+func (md *MessageDescriptor) GetOptions() proto.Message {
+ return md.proto.GetOptions()
+}
+
+// GetMessageOptions returns the message's options.
+func (md *MessageDescriptor) GetMessageOptions() *dpb.MessageOptions {
+ return md.proto.GetOptions()
+}
+
+// GetSourceInfo returns source info for the message, if present in the
+// descriptor. Not all descriptors will contain source info. If non-nil, the
+// returned info contains information about the location in the file where the
+// message was defined and also contains comments associated with the message
+// definition.
+func (md *MessageDescriptor) GetSourceInfo() *dpb.SourceCodeInfo_Location {
+ return md.file.sourceInfo.Get(md.sourceInfoPath)
+}
+
+// AsProto returns the underlying descriptor proto. Most usages will be more
+// interested in AsDescriptorProto, which has a concrete return type. This
+// generic version is present to satisfy the Descriptor interface.
+func (md *MessageDescriptor) AsProto() proto.Message {
+ return md.proto
+}
+
+// AsDescriptorProto returns the underlying descriptor proto.
+func (md *MessageDescriptor) AsDescriptorProto() *dpb.DescriptorProto {
+ return md.proto
+}
+
+// String returns the underlying descriptor proto, in compact text format.
+func (md *MessageDescriptor) String() string {
+ return md.proto.String()
+}
+
+// IsMapEntry returns true if this is a synthetic message type that represents an entry
+// in a map field.
+func (md *MessageDescriptor) IsMapEntry() bool {
+ return md.isMapEntry
+}
+
+// GetFields returns all of the fields for this message.
+func (md *MessageDescriptor) GetFields() []*FieldDescriptor {
+ return md.fields
+}
+
+// GetNestedMessageTypes returns all of the message types declared inside this message.
+func (md *MessageDescriptor) GetNestedMessageTypes() []*MessageDescriptor {
+ return md.nested
+}
+
+// GetNestedEnumTypes returns all of the enums declared inside this message.
+func (md *MessageDescriptor) GetNestedEnumTypes() []*EnumDescriptor {
+ return md.enums
+}
+
+// GetNestedExtensions returns all of the extensions declared inside this message.
+func (md *MessageDescriptor) GetNestedExtensions() []*FieldDescriptor {
+ return md.extensions
+}
+
+// GetOneOfs returns all of the one-of field sets declared inside this message.
+func (md *MessageDescriptor) GetOneOfs() []*OneOfDescriptor {
+ return md.oneOfs
+}
+
+// IsProto3 returns true if the file in which this message is defined declares a syntax of "proto3".
+func (md *MessageDescriptor) IsProto3() bool {
+ return md.isProto3
+}
+
+// GetExtensionRanges returns the ranges of extension field numbers for this message.
+func (md *MessageDescriptor) GetExtensionRanges() []proto.ExtensionRange {
+ return md.extRanges
+}
+
+// IsExtendable returns true if this message has any extension ranges.
+func (md *MessageDescriptor) IsExtendable() bool {
+ return len(md.extRanges) > 0
+}
+
+// IsExtension returns true if the given tag number is within any of this message's
+// extension ranges.
+func (md *MessageDescriptor) IsExtension(tagNumber int32) bool {
+ return md.extRanges.IsExtension(tagNumber)
+}
+
+type extRanges []proto.ExtensionRange
+
+func (er extRanges) String() string {
+ var buf bytes.Buffer
+ first := true
+ for _, r := range er {
+ if first {
+ first = false
+ } else {
+ buf.WriteString(",")
+ }
+ fmt.Fprintf(&buf, "%d..%d", r.Start, r.End)
+ }
+ return buf.String()
+}
+
+func (er extRanges) IsExtension(tagNumber int32) bool {
+ i := sort.Search(len(er), func(i int) bool { return er[i].End >= tagNumber })
+ return i < len(er) && tagNumber >= er[i].Start
+}
+
+func (er extRanges) Len() int {
+ return len(er)
+}
+
+func (er extRanges) Less(i, j int) bool {
+ return er[i].Start < er[j].Start
+}
+
+func (er extRanges) Swap(i, j int) {
+ er[i], er[j] = er[j], er[i]
+}
+
+// FindFieldByName finds the field with the given name. If no such field exists
+// then nil is returned. Only regular fields are returned, not extensions.
+func (md *MessageDescriptor) FindFieldByName(fieldName string) *FieldDescriptor {
+ fqn := fmt.Sprintf("%s.%s", md.fqn, fieldName)
+ if fd, ok := md.file.symbols[fqn].(*FieldDescriptor); ok && !fd.IsExtension() {
+ return fd
+ } else {
+ return nil
+ }
+}
+
+// FindFieldByNumber finds the field with the given tag number. If no such field
+// exists then nil is returned. Only regular fields are returned, not extensions.
+func (md *MessageDescriptor) FindFieldByNumber(tagNumber int32) *FieldDescriptor {
+ if fd, ok := md.file.fieldIndex[md.fqn][tagNumber]; ok && !fd.IsExtension() {
+ return fd
+ } else {
+ return nil
+ }
+}
+
+// FieldDescriptor describes a field of a protocol buffer message.
+type FieldDescriptor struct {
+ proto *dpb.FieldDescriptorProto
+ parent Descriptor
+ owner *MessageDescriptor
+ file *FileDescriptor
+ oneOf *OneOfDescriptor
+ msgType *MessageDescriptor
+ enumType *EnumDescriptor
+ fqn string
+ sourceInfoPath []int32
+ def memoizedDefault
+ isMap bool
+}
+
+func createFieldDescriptor(fd *FileDescriptor, parent Descriptor, enclosing string, fld *dpb.FieldDescriptorProto) (*FieldDescriptor, string) {
+ fldName := merge(enclosing, fld.GetName())
+ ret := &FieldDescriptor{proto: fld, parent: parent, file: fd, fqn: fldName}
+ if fld.GetExtendee() == "" {
+ ret.owner = parent.(*MessageDescriptor)
+ }
+ // owner for extensions, field type (be it message or enum), and one-ofs get resolved later
+ return ret, fldName
+}
+
+func (fd *FieldDescriptor) resolve(path []int32, scopes []scope) error {
+ if fd.proto.OneofIndex != nil && fd.oneOf == nil {
+ return fmt.Errorf("could not link field %s to one-of index %d", fd.fqn, *fd.proto.OneofIndex)
+ }
+ fd.sourceInfoPath = append([]int32(nil), path...) // defensive copy
+ if fd.proto.GetType() == dpb.FieldDescriptorProto_TYPE_ENUM {
+ if desc, err := resolve(fd.file, fd.proto.GetTypeName(), scopes); err != nil {
+ return err
+ } else {
+ fd.enumType = desc.(*EnumDescriptor)
+ }
+ }
+ if fd.proto.GetType() == dpb.FieldDescriptorProto_TYPE_MESSAGE || fd.proto.GetType() == dpb.FieldDescriptorProto_TYPE_GROUP {
+ if desc, err := resolve(fd.file, fd.proto.GetTypeName(), scopes); err != nil {
+ return err
+ } else {
+ fd.msgType = desc.(*MessageDescriptor)
+ }
+ }
+ if fd.proto.GetExtendee() != "" {
+ if desc, err := resolve(fd.file, fd.proto.GetExtendee(), scopes); err != nil {
+ return err
+ } else {
+ fd.owner = desc.(*MessageDescriptor)
+ }
+ }
+ fd.file.registerField(fd)
+ fd.isMap = fd.proto.GetLabel() == dpb.FieldDescriptorProto_LABEL_REPEATED &&
+ fd.proto.GetType() == dpb.FieldDescriptorProto_TYPE_MESSAGE &&
+ fd.GetMessageType().IsMapEntry()
+ return nil
+}
+
+func (fd *FieldDescriptor) determineDefault() interface{} {
+ if fd.IsMap() {
+ return map[interface{}]interface{}(nil)
+ } else if fd.IsRepeated() {
+ return []interface{}(nil)
+ } else if fd.msgType != nil {
+ return nil
+ }
+
+ proto3 := fd.file.isProto3
+ if !proto3 {
+ def := fd.AsFieldDescriptorProto().GetDefaultValue()
+ if def != "" {
+ ret := parseDefaultValue(fd, def)
+ if ret != nil {
+ return ret
+ }
+ // if we can't parse default value, fall-through to return normal default...
+ }
+ }
+
+ switch fd.GetType() {
+ case dpb.FieldDescriptorProto_TYPE_FIXED32,
+ dpb.FieldDescriptorProto_TYPE_UINT32:
+ return uint32(0)
+ case dpb.FieldDescriptorProto_TYPE_SFIXED32,
+ dpb.FieldDescriptorProto_TYPE_INT32,
+ dpb.FieldDescriptorProto_TYPE_SINT32:
+ return int32(0)
+ case dpb.FieldDescriptorProto_TYPE_FIXED64,
+ dpb.FieldDescriptorProto_TYPE_UINT64:
+ return uint64(0)
+ case dpb.FieldDescriptorProto_TYPE_SFIXED64,
+ dpb.FieldDescriptorProto_TYPE_INT64,
+ dpb.FieldDescriptorProto_TYPE_SINT64:
+ return int64(0)
+ case dpb.FieldDescriptorProto_TYPE_FLOAT:
+ return float32(0.0)
+ case dpb.FieldDescriptorProto_TYPE_DOUBLE:
+ return float64(0.0)
+ case dpb.FieldDescriptorProto_TYPE_BOOL:
+ return false
+ case dpb.FieldDescriptorProto_TYPE_BYTES:
+ return []byte(nil)
+ case dpb.FieldDescriptorProto_TYPE_STRING:
+ return ""
+ case dpb.FieldDescriptorProto_TYPE_ENUM:
+ if proto3 {
+ return int32(0)
+ }
+ enumVals := fd.GetEnumType().GetValues()
+ if len(enumVals) > 0 {
+ return enumVals[0].GetNumber()
+ } else {
+ return int32(0) // WTF?
+ }
+ default:
+ panic(fmt.Sprintf("Unknown field type: %v", fd.GetType()))
+ }
+}
+
+func parseDefaultValue(fd *FieldDescriptor, val string) interface{} {
+ switch fd.GetType() {
+ case dpb.FieldDescriptorProto_TYPE_ENUM:
+ vd := fd.GetEnumType().FindValueByName(val)
+ if vd != nil {
+ return vd.GetNumber()
+ }
+ return nil
+ case dpb.FieldDescriptorProto_TYPE_BOOL:
+ if val == "true" {
+ return true
+ } else if val == "false" {
+ return false
+ }
+ return nil
+ case dpb.FieldDescriptorProto_TYPE_BYTES:
+ return []byte(unescape(val))
+ case dpb.FieldDescriptorProto_TYPE_STRING:
+ return val
+ case dpb.FieldDescriptorProto_TYPE_FLOAT:
+ if f, err := strconv.ParseFloat(val, 32); err == nil {
+ return float32(f)
+ } else {
+ return float32(0)
+ }
+ case dpb.FieldDescriptorProto_TYPE_DOUBLE:
+ if f, err := strconv.ParseFloat(val, 64); err == nil {
+ return f
+ } else {
+ return float64(0)
+ }
+ case dpb.FieldDescriptorProto_TYPE_INT32,
+ dpb.FieldDescriptorProto_TYPE_SINT32,
+ dpb.FieldDescriptorProto_TYPE_SFIXED32:
+ if i, err := strconv.ParseInt(val, 10, 32); err == nil {
+ return int32(i)
+ } else {
+ return int32(0)
+ }
+ case dpb.FieldDescriptorProto_TYPE_UINT32,
+ dpb.FieldDescriptorProto_TYPE_FIXED32:
+ if i, err := strconv.ParseUint(val, 10, 32); err == nil {
+ return uint32(i)
+ } else {
+ return uint32(0)
+ }
+ case dpb.FieldDescriptorProto_TYPE_INT64,
+ dpb.FieldDescriptorProto_TYPE_SINT64,
+ dpb.FieldDescriptorProto_TYPE_SFIXED64:
+ if i, err := strconv.ParseInt(val, 10, 64); err == nil {
+ return i
+ } else {
+ return int64(0)
+ }
+ case dpb.FieldDescriptorProto_TYPE_UINT64,
+ dpb.FieldDescriptorProto_TYPE_FIXED64:
+ if i, err := strconv.ParseUint(val, 10, 64); err == nil {
+ return i
+ } else {
+ return uint64(0)
+ }
+ default:
+ return nil
+ }
+}
+
+func unescape(s string) string {
+ // protoc encodes default values for 'bytes' fields using C escaping,
+ // so this function reverses that escaping
+ out := make([]byte, 0, len(s))
+ var buf [4]byte
+ for len(s) > 0 {
+ if s[0] != '\\' || len(s) < 2 {
+ // not escape sequence, or too short to be well-formed escape
+ out = append(out, s[0])
+ s = s[1:]
+ } else if s[1] == 'x' || s[1] == 'X' {
+ n := matchPrefix(s[2:], 2, isHex)
+ if n == 0 {
+ // bad escape
+ out = append(out, s[:2]...)
+ s = s[2:]
+ } else {
+ c, err := strconv.ParseUint(s[2:2+n], 16, 8)
+ if err != nil {
+ // shouldn't really happen...
+ out = append(out, s[:2+n]...)
+ } else {
+ out = append(out, byte(c))
+ }
+ s = s[2+n:]
+ }
+ } else if s[1] >= '0' && s[1] <= '7' {
+ n := 1 + matchPrefix(s[2:], 2, isOctal)
+ c, err := strconv.ParseUint(s[1:1+n], 8, 8)
+ if err != nil || c > 0xff {
+ out = append(out, s[:1+n]...)
+ } else {
+ out = append(out, byte(c))
+ }
+ s = s[1+n:]
+ } else if s[1] == 'u' {
+ if len(s) < 6 {
+ // bad escape
+ out = append(out, s...)
+ s = s[len(s):]
+ } else {
+ c, err := strconv.ParseUint(s[2:6], 16, 16)
+ if err != nil {
+ // bad escape
+ out = append(out, s[:6]...)
+ } else {
+ w := utf8.EncodeRune(buf[:], rune(c))
+ out = append(out, buf[:w]...)
+ }
+ s = s[6:]
+ }
+ } else if s[1] == 'U' {
+ if len(s) < 10 {
+ // bad escape
+ out = append(out, s...)
+ s = s[len(s):]
+ } else {
+ c, err := strconv.ParseUint(s[2:10], 16, 32)
+ if err != nil || c > 0x10ffff {
+ // bad escape
+ out = append(out, s[:10]...)
+ } else {
+ w := utf8.EncodeRune(buf[:], rune(c))
+ out = append(out, buf[:w]...)
+ }
+ s = s[10:]
+ }
+ } else {
+ switch s[1] {
+ case 'a':
+ out = append(out, '\a')
+ case 'b':
+ out = append(out, '\b')
+ case 'f':
+ out = append(out, '\f')
+ case 'n':
+ out = append(out, '\n')
+ case 'r':
+ out = append(out, '\r')
+ case 't':
+ out = append(out, '\t')
+ case 'v':
+ out = append(out, '\v')
+ case '\\':
+ out = append(out, '\\')
+ case '\'':
+ out = append(out, '\'')
+ case '"':
+ out = append(out, '"')
+ case '?':
+ out = append(out, '?')
+ default:
+ // invalid escape, just copy it as-is
+ out = append(out, s[:2]...)
+ }
+ s = s[2:]
+ }
+ }
+ return string(out)
+}
+
+func isOctal(b byte) bool { return b >= '0' && b <= '7' }
+func isHex(b byte) bool {
+ return (b >= '0' && b <= '9') || (b >= 'a' && b <= 'f') || (b >= 'A' && b <= 'F')
+}
+func matchPrefix(s string, limit int, fn func(byte) bool) int {
+ l := len(s)
+ if l > limit {
+ l = limit
+ }
+ i := 0
+ for ; i < l; i++ {
+ if !fn(s[i]) {
+ return i
+ }
+ }
+ return i
+}
+
+// GetName returns the name of the field.
+func (fd *FieldDescriptor) GetName() string {
+ return fd.proto.GetName()
+}
+
+// GetNumber returns the tag number of this field.
+func (fd *FieldDescriptor) GetNumber() int32 {
+ return fd.proto.GetNumber()
+}
+
+// GetFullyQualifiedName returns the fully qualified name of the field. Unlike
+// GetName, this includes fully qualified name of the enclosing message for
+// regular fields.
+//
+// For extension fields, this includes the package (if there is one) as well as
+// any enclosing messages. The package and/or enclosing messages are for where
+// the extension is defined, not the message it extends.
+//
+// If this field is part of a one-of, the fully qualified name does *not*
+// include the name of the one-of, only of the enclosing message.
+func (fd *FieldDescriptor) GetFullyQualifiedName() string {
+ return fd.fqn
+}
+
+// GetParent returns the fields's enclosing descriptor. For normal
+// (non-extension) fields, this is the enclosing message. For extensions, this
+// is the descriptor in which the extension is defined, not the message that is
+// extended. The parent for an extension may be a file descriptor or a message,
+// depending on where the extension is defined.
+func (fd *FieldDescriptor) GetParent() Descriptor {
+ return fd.parent
+}
+
+// GetFile returns the descriptor for the file in which this field is defined.
+func (fd *FieldDescriptor) GetFile() *FileDescriptor {
+ return fd.file
+}
+
+// GetOptions returns the field's options. Most usages will be more interested
+// in GetFieldOptions, which has a concrete return type. This generic version
+// is present to satisfy the Descriptor interface.
+func (fd *FieldDescriptor) GetOptions() proto.Message {
+ return fd.proto.GetOptions()
+}
+
+// GetFieldOptions returns the field's options.
+func (fd *FieldDescriptor) GetFieldOptions() *dpb.FieldOptions {
+ return fd.proto.GetOptions()
+}
+
+// GetSourceInfo returns source info for the field, if present in the
+// descriptor. Not all descriptors will contain source info. If non-nil, the
+// returned info contains information about the location in the file where the
+// field was defined and also contains comments associated with the field
+// definition.
+func (fd *FieldDescriptor) GetSourceInfo() *dpb.SourceCodeInfo_Location {
+ return fd.file.sourceInfo.Get(fd.sourceInfoPath)
+}
+
+// AsProto returns the underlying descriptor proto. Most usages will be more
+// interested in AsFieldDescriptorProto, which has a concrete return type. This
+// generic version is present to satisfy the Descriptor interface.
+func (fd *FieldDescriptor) AsProto() proto.Message {
+ return fd.proto
+}
+
+// AsFieldDescriptorProto returns the underlying descriptor proto.
+func (fd *FieldDescriptor) AsFieldDescriptorProto() *dpb.FieldDescriptorProto {
+ return fd.proto
+}
+
+// String returns the underlying descriptor proto, in compact text format.
+func (fd *FieldDescriptor) String() string {
+ return fd.proto.String()
+}
+
+// GetJSONName returns the name of the field as referenced in the message's JSON
+// format.
+func (fd *FieldDescriptor) GetJSONName() string {
+ if jsonName := fd.proto.JsonName; jsonName != nil {
+ // if json name is present, use its value
+ return *jsonName
+ }
+ // otherwise, compute the proper JSON name from the field name
+ return jsonCamelCase(fd.proto.GetName())
+}
+
+func jsonCamelCase(s string) string {
+ // This mirrors the implementation in protoc/C++ runtime and in the Java runtime:
+ // https://github.com/protocolbuffers/protobuf/blob/a104dffcb6b1958a424f5fa6f9e6bdc0ab9b6f9e/src/google/protobuf/descriptor.cc#L276
+ // https://github.com/protocolbuffers/protobuf/blob/a1c886834425abb64a966231dd2c9dd84fb289b3/java/core/src/main/java/com/google/protobuf/Descriptors.java#L1286
+ var buf bytes.Buffer
+ prevWasUnderscore := false
+ for _, r := range s {
+ if r == '_' {
+ prevWasUnderscore = true
+ continue
+ }
+ if prevWasUnderscore {
+ r = unicode.ToUpper(r)
+ prevWasUnderscore = false
+ }
+ buf.WriteRune(r)
+ }
+ return buf.String()
+}
+
+// GetFullyQualifiedJSONName returns the JSON format name (same as GetJSONName),
+// but includes the fully qualified name of the enclosing message.
+//
+// If the field is an extension, it will return the package name (if there is
+// one) as well as the names of any enclosing messages. The package and/or
+// enclosing messages are for where the extension is defined, not the message it
+// extends.
+func (fd *FieldDescriptor) GetFullyQualifiedJSONName() string {
+ parent := fd.GetParent()
+ switch parent := parent.(type) {
+ case *FileDescriptor:
+ pkg := parent.GetPackage()
+ if pkg == "" {
+ return fd.GetJSONName()
+ }
+ return fmt.Sprintf("%s.%s", pkg, fd.GetJSONName())
+ default:
+ return fmt.Sprintf("%s.%s", parent.GetFullyQualifiedName(), fd.GetJSONName())
+ }
+}
+
+// GetOwner returns the message type that this field belongs to. If this is a normal
+// field then this is the same as GetParent. But for extensions, this will be the
+// extendee message whereas GetParent refers to where the extension was declared.
+func (fd *FieldDescriptor) GetOwner() *MessageDescriptor {
+ return fd.owner
+}
+
+// IsExtension returns true if this is an extension field.
+func (fd *FieldDescriptor) IsExtension() bool {
+ return fd.proto.GetExtendee() != ""
+}
+
+// GetOneOf returns the one-of field set to which this field belongs. If this field
+// is not part of a one-of then this method returns nil.
+func (fd *FieldDescriptor) GetOneOf() *OneOfDescriptor {
+ return fd.oneOf
+}
+
+// GetType returns the type of this field. If the type indicates an enum, the
+// enum type can be queried via GetEnumType. If the type indicates a message, the
+// message type can be queried via GetMessageType.
+func (fd *FieldDescriptor) GetType() dpb.FieldDescriptorProto_Type {
+ return fd.proto.GetType()
+}
+
+// GetLabel returns the label for this field. The label can be required (proto2-only),
+// optional (default for proto3), or required.
+func (fd *FieldDescriptor) GetLabel() dpb.FieldDescriptorProto_Label {
+ return fd.proto.GetLabel()
+}
+
+// IsRequired returns true if this field has the "required" label.
+func (fd *FieldDescriptor) IsRequired() bool {
+ return fd.proto.GetLabel() == dpb.FieldDescriptorProto_LABEL_REQUIRED
+}
+
+// IsRepeated returns true if this field has the "repeated" label.
+func (fd *FieldDescriptor) IsRepeated() bool {
+ return fd.proto.GetLabel() == dpb.FieldDescriptorProto_LABEL_REPEATED
+}
+
+// IsProto3Optional returns true if this field has an explicit "optional" label
+// and is in a "proto3" syntax file. Such fields, if they are normal fields (not
+// extensions), will be nested in synthetic oneofs that contain only the single
+// field.
+func (fd *FieldDescriptor) IsProto3Optional() bool {
+ return internal.GetProto3Optional(fd.proto)
+}
+
+// HasPresence returns true if this field can distinguish when a value is
+// present or not. Scalar fields in "proto3" syntax files, for example, return
+// false since absent values are indistinguishable from zero values.
+func (fd *FieldDescriptor) HasPresence() bool {
+ if !fd.file.isProto3 {
+ return true
+ }
+ return fd.msgType != nil || fd.oneOf != nil
+}
+
+// IsMap returns true if this is a map field. If so, it will have the "repeated"
+// label its type will be a message that represents a map entry. The map entry
+// message will have exactly two fields: tag #1 is the key and tag #2 is the value.
+func (fd *FieldDescriptor) IsMap() bool {
+ return fd.isMap
+}
+
+// GetMapKeyType returns the type of the key field if this is a map field. If it is
+// not a map field, nil is returned.
+func (fd *FieldDescriptor) GetMapKeyType() *FieldDescriptor {
+ if fd.isMap {
+ return fd.msgType.FindFieldByNumber(int32(1))
+ }
+ return nil
+}
+
+// GetMapValueType returns the type of the value field if this is a map field. If it
+// is not a map field, nil is returned.
+func (fd *FieldDescriptor) GetMapValueType() *FieldDescriptor {
+ if fd.isMap {
+ return fd.msgType.FindFieldByNumber(int32(2))
+ }
+ return nil
+}
+
+// GetMessageType returns the type of this field if it is a message type. If
+// this field is not a message type, it returns nil.
+func (fd *FieldDescriptor) GetMessageType() *MessageDescriptor {
+ return fd.msgType
+}
+
+// GetEnumType returns the type of this field if it is an enum type. If this
+// field is not an enum type, it returns nil.
+func (fd *FieldDescriptor) GetEnumType() *EnumDescriptor {
+ return fd.enumType
+}
+
+// GetDefaultValue returns the default value for this field.
+//
+// If this field represents a message type, this method always returns nil (even though
+// for proto2 files, the default value should be a default instance of the message type).
+// If the field represents an enum type, this method returns an int32 corresponding to the
+// enum value. If this field is a map, it returns a nil map[interface{}]interface{}. If
+// this field is repeated (and not a map), it returns a nil []interface{}.
+//
+// Otherwise, it returns the declared default value for the field or a zero value, if no
+// default is declared or if the file is proto3. The type of said return value corresponds
+// to the type of the field:
+// +-------------------------+-----------+
+// | Declared Type | Go Type |
+// +-------------------------+-----------+
+// | int32, sint32, sfixed32 | int32 |
+// | int64, sint64, sfixed64 | int64 |
+// | uint32, fixed32 | uint32 |
+// | uint64, fixed64 | uint64 |
+// | float | float32 |
+// | double | double32 |
+// | bool | bool |
+// | string | string |
+// | bytes | []byte |
+// +-------------------------+-----------+
+func (fd *FieldDescriptor) GetDefaultValue() interface{} {
+ return fd.getDefaultValue()
+}
+
+// EnumDescriptor describes an enum declared in a proto file.
+type EnumDescriptor struct {
+ proto *dpb.EnumDescriptorProto
+ parent Descriptor
+ file *FileDescriptor
+ values []*EnumValueDescriptor
+ valuesByNum sortedValues
+ fqn string
+ sourceInfoPath []int32
+}
+
+func createEnumDescriptor(fd *FileDescriptor, parent Descriptor, enclosing string, ed *dpb.EnumDescriptorProto, symbols map[string]Descriptor) (*EnumDescriptor, string) {
+ enumName := merge(enclosing, ed.GetName())
+ ret := &EnumDescriptor{proto: ed, parent: parent, file: fd, fqn: enumName}
+ for _, ev := range ed.GetValue() {
+ evd, n := createEnumValueDescriptor(fd, ret, enumName, ev)
+ symbols[n] = evd
+ ret.values = append(ret.values, evd)
+ }
+ if len(ret.values) > 0 {
+ ret.valuesByNum = make(sortedValues, len(ret.values))
+ copy(ret.valuesByNum, ret.values)
+ sort.Stable(ret.valuesByNum)
+ }
+ return ret, enumName
+}
+
+type sortedValues []*EnumValueDescriptor
+
+func (sv sortedValues) Len() int {
+ return len(sv)
+}
+
+func (sv sortedValues) Less(i, j int) bool {
+ return sv[i].GetNumber() < sv[j].GetNumber()
+}
+
+func (sv sortedValues) Swap(i, j int) {
+ sv[i], sv[j] = sv[j], sv[i]
+}
+
+func (ed *EnumDescriptor) resolve(path []int32) {
+ ed.sourceInfoPath = append([]int32(nil), path...) // defensive copy
+ path = append(path, internal.Enum_valuesTag)
+ for i, evd := range ed.values {
+ evd.resolve(append(path, int32(i)))
+ }
+}
+
+// GetName returns the simple (unqualified) name of the enum type.
+func (ed *EnumDescriptor) GetName() string {
+ return ed.proto.GetName()
+}
+
+// GetFullyQualifiedName returns the fully qualified name of the enum type.
+// This includes the package name (if there is one) as well as the names of any
+// enclosing messages.
+func (ed *EnumDescriptor) GetFullyQualifiedName() string {
+ return ed.fqn
+}
+
+// GetParent returns the enum type's enclosing descriptor. For top-level enums,
+// this will be a file descriptor. Otherwise it will be the descriptor for the
+// enclosing message.
+func (ed *EnumDescriptor) GetParent() Descriptor {
+ return ed.parent
+}
+
+// GetFile returns the descriptor for the file in which this enum is defined.
+func (ed *EnumDescriptor) GetFile() *FileDescriptor {
+ return ed.file
+}
+
+// GetOptions returns the enum type's options. Most usages will be more
+// interested in GetEnumOptions, which has a concrete return type. This generic
+// version is present to satisfy the Descriptor interface.
+func (ed *EnumDescriptor) GetOptions() proto.Message {
+ return ed.proto.GetOptions()
+}
+
+// GetEnumOptions returns the enum type's options.
+func (ed *EnumDescriptor) GetEnumOptions() *dpb.EnumOptions {
+ return ed.proto.GetOptions()
+}
+
+// GetSourceInfo returns source info for the enum type, if present in the
+// descriptor. Not all descriptors will contain source info. If non-nil, the
+// returned info contains information about the location in the file where the
+// enum type was defined and also contains comments associated with the enum
+// definition.
+func (ed *EnumDescriptor) GetSourceInfo() *dpb.SourceCodeInfo_Location {
+ return ed.file.sourceInfo.Get(ed.sourceInfoPath)
+}
+
+// AsProto returns the underlying descriptor proto. Most usages will be more
+// interested in AsEnumDescriptorProto, which has a concrete return type. This
+// generic version is present to satisfy the Descriptor interface.
+func (ed *EnumDescriptor) AsProto() proto.Message {
+ return ed.proto
+}
+
+// AsEnumDescriptorProto returns the underlying descriptor proto.
+func (ed *EnumDescriptor) AsEnumDescriptorProto() *dpb.EnumDescriptorProto {
+ return ed.proto
+}
+
+// String returns the underlying descriptor proto, in compact text format.
+func (ed *EnumDescriptor) String() string {
+ return ed.proto.String()
+}
+
+// GetValues returns all of the allowed values defined for this enum.
+func (ed *EnumDescriptor) GetValues() []*EnumValueDescriptor {
+ return ed.values
+}
+
+// FindValueByName finds the enum value with the given name. If no such value exists
+// then nil is returned.
+func (ed *EnumDescriptor) FindValueByName(name string) *EnumValueDescriptor {
+ fqn := fmt.Sprintf("%s.%s", ed.fqn, name)
+ if vd, ok := ed.file.symbols[fqn].(*EnumValueDescriptor); ok {
+ return vd
+ } else {
+ return nil
+ }
+}
+
+// FindValueByNumber finds the value with the given numeric value. If no such value
+// exists then nil is returned. If aliases are allowed and multiple values have the
+// given number, the first declared value is returned.
+func (ed *EnumDescriptor) FindValueByNumber(num int32) *EnumValueDescriptor {
+ index := sort.Search(len(ed.valuesByNum), func(i int) bool { return ed.valuesByNum[i].GetNumber() >= num })
+ if index < len(ed.valuesByNum) {
+ vd := ed.valuesByNum[index]
+ if vd.GetNumber() == num {
+ return vd
+ }
+ }
+ return nil
+}
+
+// EnumValueDescriptor describes an allowed value of an enum declared in a proto file.
+type EnumValueDescriptor struct {
+ proto *dpb.EnumValueDescriptorProto
+ parent *EnumDescriptor
+ file *FileDescriptor
+ fqn string
+ sourceInfoPath []int32
+}
+
+func createEnumValueDescriptor(fd *FileDescriptor, parent *EnumDescriptor, enclosing string, evd *dpb.EnumValueDescriptorProto) (*EnumValueDescriptor, string) {
+ valName := merge(enclosing, evd.GetName())
+ return &EnumValueDescriptor{proto: evd, parent: parent, file: fd, fqn: valName}, valName
+}
+
+func (vd *EnumValueDescriptor) resolve(path []int32) {
+ vd.sourceInfoPath = append([]int32(nil), path...) // defensive copy
+}
+
+// GetName returns the name of the enum value.
+func (vd *EnumValueDescriptor) GetName() string {
+ return vd.proto.GetName()
+}
+
+// GetNumber returns the numeric value associated with this enum value.
+func (vd *EnumValueDescriptor) GetNumber() int32 {
+ return vd.proto.GetNumber()
+}
+
+// GetFullyQualifiedName returns the fully qualified name of the enum value.
+// Unlike GetName, this includes fully qualified name of the enclosing enum.
+func (vd *EnumValueDescriptor) GetFullyQualifiedName() string {
+ return vd.fqn
+}
+
+// GetParent returns the descriptor for the enum in which this enum value is
+// defined. Most usages will prefer to use GetEnum, which has a concrete return
+// type. This more generic method is present to satisfy the Descriptor interface.
+func (vd *EnumValueDescriptor) GetParent() Descriptor {
+ return vd.parent
+}
+
+// GetEnum returns the enum in which this enum value is defined.
+func (vd *EnumValueDescriptor) GetEnum() *EnumDescriptor {
+ return vd.parent
+}
+
+// GetFile returns the descriptor for the file in which this enum value is
+// defined.
+func (vd *EnumValueDescriptor) GetFile() *FileDescriptor {
+ return vd.file
+}
+
+// GetOptions returns the enum value's options. Most usages will be more
+// interested in GetEnumValueOptions, which has a concrete return type. This
+// generic version is present to satisfy the Descriptor interface.
+func (vd *EnumValueDescriptor) GetOptions() proto.Message {
+ return vd.proto.GetOptions()
+}
+
+// GetEnumValueOptions returns the enum value's options.
+func (vd *EnumValueDescriptor) GetEnumValueOptions() *dpb.EnumValueOptions {
+ return vd.proto.GetOptions()
+}
+
+// GetSourceInfo returns source info for the enum value, if present in the
+// descriptor. Not all descriptors will contain source info. If non-nil, the
+// returned info contains information about the location in the file where the
+// enum value was defined and also contains comments associated with the enum
+// value definition.
+func (vd *EnumValueDescriptor) GetSourceInfo() *dpb.SourceCodeInfo_Location {
+ return vd.file.sourceInfo.Get(vd.sourceInfoPath)
+}
+
+// AsProto returns the underlying descriptor proto. Most usages will be more
+// interested in AsEnumValueDescriptorProto, which has a concrete return type.
+// This generic version is present to satisfy the Descriptor interface.
+func (vd *EnumValueDescriptor) AsProto() proto.Message {
+ return vd.proto
+}
+
+// AsEnumValueDescriptorProto returns the underlying descriptor proto.
+func (vd *EnumValueDescriptor) AsEnumValueDescriptorProto() *dpb.EnumValueDescriptorProto {
+ return vd.proto
+}
+
+// String returns the underlying descriptor proto, in compact text format.
+func (vd *EnumValueDescriptor) String() string {
+ return vd.proto.String()
+}
+
+// ServiceDescriptor describes an RPC service declared in a proto file.
+type ServiceDescriptor struct {
+ proto *dpb.ServiceDescriptorProto
+ file *FileDescriptor
+ methods []*MethodDescriptor
+ fqn string
+ sourceInfoPath []int32
+}
+
+func createServiceDescriptor(fd *FileDescriptor, enclosing string, sd *dpb.ServiceDescriptorProto, symbols map[string]Descriptor) (*ServiceDescriptor, string) {
+ serviceName := merge(enclosing, sd.GetName())
+ ret := &ServiceDescriptor{proto: sd, file: fd, fqn: serviceName}
+ for _, m := range sd.GetMethod() {
+ md, n := createMethodDescriptor(fd, ret, serviceName, m)
+ symbols[n] = md
+ ret.methods = append(ret.methods, md)
+ }
+ return ret, serviceName
+}
+
+func (sd *ServiceDescriptor) resolve(path []int32, scopes []scope) error {
+ sd.sourceInfoPath = append([]int32(nil), path...) // defensive copy
+ path = append(path, internal.Service_methodsTag)
+ for i, md := range sd.methods {
+ if err := md.resolve(append(path, int32(i)), scopes); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// GetName returns the simple (unqualified) name of the service.
+func (sd *ServiceDescriptor) GetName() string {
+ return sd.proto.GetName()
+}
+
+// GetFullyQualifiedName returns the fully qualified name of the service. This
+// includes the package name (if there is one).
+func (sd *ServiceDescriptor) GetFullyQualifiedName() string {
+ return sd.fqn
+}
+
+// GetParent returns the descriptor for the file in which this service is
+// defined. Most usages will prefer to use GetFile, which has a concrete return
+// type. This more generic method is present to satisfy the Descriptor interface.
+func (sd *ServiceDescriptor) GetParent() Descriptor {
+ return sd.file
+}
+
+// GetFile returns the descriptor for the file in which this service is defined.
+func (sd *ServiceDescriptor) GetFile() *FileDescriptor {
+ return sd.file
+}
+
+// GetOptions returns the service's options. Most usages will be more interested
+// in GetServiceOptions, which has a concrete return type. This generic version
+// is present to satisfy the Descriptor interface.
+func (sd *ServiceDescriptor) GetOptions() proto.Message {
+ return sd.proto.GetOptions()
+}
+
+// GetServiceOptions returns the service's options.
+func (sd *ServiceDescriptor) GetServiceOptions() *dpb.ServiceOptions {
+ return sd.proto.GetOptions()
+}
+
+// GetSourceInfo returns source info for the service, if present in the
+// descriptor. Not all descriptors will contain source info. If non-nil, the
+// returned info contains information about the location in the file where the
+// service was defined and also contains comments associated with the service
+// definition.
+func (sd *ServiceDescriptor) GetSourceInfo() *dpb.SourceCodeInfo_Location {
+ return sd.file.sourceInfo.Get(sd.sourceInfoPath)
+}
+
+// AsProto returns the underlying descriptor proto. Most usages will be more
+// interested in AsServiceDescriptorProto, which has a concrete return type.
+// This generic version is present to satisfy the Descriptor interface.
+func (sd *ServiceDescriptor) AsProto() proto.Message {
+ return sd.proto
+}
+
+// AsServiceDescriptorProto returns the underlying descriptor proto.
+func (sd *ServiceDescriptor) AsServiceDescriptorProto() *dpb.ServiceDescriptorProto {
+ return sd.proto
+}
+
+// String returns the underlying descriptor proto, in compact text format.
+func (sd *ServiceDescriptor) String() string {
+ return sd.proto.String()
+}
+
+// GetMethods returns all of the RPC methods for this service.
+func (sd *ServiceDescriptor) GetMethods() []*MethodDescriptor {
+ return sd.methods
+}
+
+// FindMethodByName finds the method with the given name. If no such method exists
+// then nil is returned.
+func (sd *ServiceDescriptor) FindMethodByName(name string) *MethodDescriptor {
+ fqn := fmt.Sprintf("%s.%s", sd.fqn, name)
+ if md, ok := sd.file.symbols[fqn].(*MethodDescriptor); ok {
+ return md
+ } else {
+ return nil
+ }
+}
+
+// MethodDescriptor describes an RPC method declared in a proto file.
+type MethodDescriptor struct {
+ proto *dpb.MethodDescriptorProto
+ parent *ServiceDescriptor
+ file *FileDescriptor
+ inType *MessageDescriptor
+ outType *MessageDescriptor
+ fqn string
+ sourceInfoPath []int32
+}
+
+func createMethodDescriptor(fd *FileDescriptor, parent *ServiceDescriptor, enclosing string, md *dpb.MethodDescriptorProto) (*MethodDescriptor, string) {
+ // request and response types get resolved later
+ methodName := merge(enclosing, md.GetName())
+ return &MethodDescriptor{proto: md, parent: parent, file: fd, fqn: methodName}, methodName
+}
+
+func (md *MethodDescriptor) resolve(path []int32, scopes []scope) error {
+ md.sourceInfoPath = append([]int32(nil), path...) // defensive copy
+ if desc, err := resolve(md.file, md.proto.GetInputType(), scopes); err != nil {
+ return err
+ } else {
+ md.inType = desc.(*MessageDescriptor)
+ }
+ if desc, err := resolve(md.file, md.proto.GetOutputType(), scopes); err != nil {
+ return err
+ } else {
+ md.outType = desc.(*MessageDescriptor)
+ }
+ return nil
+}
+
+// GetName returns the name of the method.
+func (md *MethodDescriptor) GetName() string {
+ return md.proto.GetName()
+}
+
+// GetFullyQualifiedName returns the fully qualified name of the method. Unlike
+// GetName, this includes fully qualified name of the enclosing service.
+func (md *MethodDescriptor) GetFullyQualifiedName() string {
+ return md.fqn
+}
+
+// GetParent returns the descriptor for the service in which this method is
+// defined. Most usages will prefer to use GetService, which has a concrete
+// return type. This more generic method is present to satisfy the Descriptor
+// interface.
+func (md *MethodDescriptor) GetParent() Descriptor {
+ return md.parent
+}
+
+// GetService returns the RPC service in which this method is declared.
+func (md *MethodDescriptor) GetService() *ServiceDescriptor {
+ return md.parent
+}
+
+// GetFile returns the descriptor for the file in which this method is defined.
+func (md *MethodDescriptor) GetFile() *FileDescriptor {
+ return md.file
+}
+
+// GetOptions returns the method's options. Most usages will be more interested
+// in GetMethodOptions, which has a concrete return type. This generic version
+// is present to satisfy the Descriptor interface.
+func (md *MethodDescriptor) GetOptions() proto.Message {
+ return md.proto.GetOptions()
+}
+
+// GetMethodOptions returns the method's options.
+func (md *MethodDescriptor) GetMethodOptions() *dpb.MethodOptions {
+ return md.proto.GetOptions()
+}
+
+// GetSourceInfo returns source info for the method, if present in the
+// descriptor. Not all descriptors will contain source info. If non-nil, the
+// returned info contains information about the location in the file where the
+// method was defined and also contains comments associated with the method
+// definition.
+func (md *MethodDescriptor) GetSourceInfo() *dpb.SourceCodeInfo_Location {
+ return md.file.sourceInfo.Get(md.sourceInfoPath)
+}
+
+// AsProto returns the underlying descriptor proto. Most usages will be more
+// interested in AsMethodDescriptorProto, which has a concrete return type. This
+// generic version is present to satisfy the Descriptor interface.
+func (md *MethodDescriptor) AsProto() proto.Message {
+ return md.proto
+}
+
+// AsMethodDescriptorProto returns the underlying descriptor proto.
+func (md *MethodDescriptor) AsMethodDescriptorProto() *dpb.MethodDescriptorProto {
+ return md.proto
+}
+
+// String returns the underlying descriptor proto, in compact text format.
+func (md *MethodDescriptor) String() string {
+ return md.proto.String()
+}
+
+// IsServerStreaming returns true if this is a server-streaming method.
+func (md *MethodDescriptor) IsServerStreaming() bool {
+ return md.proto.GetServerStreaming()
+}
+
+// IsClientStreaming returns true if this is a client-streaming method.
+func (md *MethodDescriptor) IsClientStreaming() bool {
+ return md.proto.GetClientStreaming()
+}
+
+// GetInputType returns the input type, or request type, of the RPC method.
+func (md *MethodDescriptor) GetInputType() *MessageDescriptor {
+ return md.inType
+}
+
+// GetOutputType returns the output type, or response type, of the RPC method.
+func (md *MethodDescriptor) GetOutputType() *MessageDescriptor {
+ return md.outType
+}
+
+// OneOfDescriptor describes a one-of field set declared in a protocol buffer message.
+type OneOfDescriptor struct {
+ proto *dpb.OneofDescriptorProto
+ parent *MessageDescriptor
+ file *FileDescriptor
+ choices []*FieldDescriptor
+ fqn string
+ sourceInfoPath []int32
+}
+
+func createOneOfDescriptor(fd *FileDescriptor, parent *MessageDescriptor, index int, enclosing string, od *dpb.OneofDescriptorProto) (*OneOfDescriptor, string) {
+ oneOfName := merge(enclosing, od.GetName())
+ ret := &OneOfDescriptor{proto: od, parent: parent, file: fd, fqn: oneOfName}
+ for _, f := range parent.fields {
+ oi := f.proto.OneofIndex
+ if oi != nil && *oi == int32(index) {
+ f.oneOf = ret
+ ret.choices = append(ret.choices, f)
+ }
+ }
+ return ret, oneOfName
+}
+
+func (od *OneOfDescriptor) resolve(path []int32) {
+ od.sourceInfoPath = append([]int32(nil), path...) // defensive copy
+}
+
+// GetName returns the name of the one-of.
+func (od *OneOfDescriptor) GetName() string {
+ return od.proto.GetName()
+}
+
+// GetFullyQualifiedName returns the fully qualified name of the one-of. Unlike
+// GetName, this includes fully qualified name of the enclosing message.
+func (od *OneOfDescriptor) GetFullyQualifiedName() string {
+ return od.fqn
+}
+
+// GetParent returns the descriptor for the message in which this one-of is
+// defined. Most usages will prefer to use GetOwner, which has a concrete
+// return type. This more generic method is present to satisfy the Descriptor
+// interface.
+func (od *OneOfDescriptor) GetParent() Descriptor {
+ return od.parent
+}
+
+// GetOwner returns the message to which this one-of field set belongs.
+func (od *OneOfDescriptor) GetOwner() *MessageDescriptor {
+ return od.parent
+}
+
+// GetFile returns the descriptor for the file in which this one-fof is defined.
+func (od *OneOfDescriptor) GetFile() *FileDescriptor {
+ return od.file
+}
+
+// GetOptions returns the one-of's options. Most usages will be more interested
+// in GetOneOfOptions, which has a concrete return type. This generic version
+// is present to satisfy the Descriptor interface.
+func (od *OneOfDescriptor) GetOptions() proto.Message {
+ return od.proto.GetOptions()
+}
+
+// GetOneOfOptions returns the one-of's options.
+func (od *OneOfDescriptor) GetOneOfOptions() *dpb.OneofOptions {
+ return od.proto.GetOptions()
+}
+
+// GetSourceInfo returns source info for the one-of, if present in the
+// descriptor. Not all descriptors will contain source info. If non-nil, the
+// returned info contains information about the location in the file where the
+// one-of was defined and also contains comments associated with the one-of
+// definition.
+func (od *OneOfDescriptor) GetSourceInfo() *dpb.SourceCodeInfo_Location {
+ return od.file.sourceInfo.Get(od.sourceInfoPath)
+}
+
+// AsProto returns the underlying descriptor proto. Most usages will be more
+// interested in AsOneofDescriptorProto, which has a concrete return type. This
+// generic version is present to satisfy the Descriptor interface.
+func (od *OneOfDescriptor) AsProto() proto.Message {
+ return od.proto
+}
+
+// AsOneofDescriptorProto returns the underlying descriptor proto.
+func (od *OneOfDescriptor) AsOneofDescriptorProto() *dpb.OneofDescriptorProto {
+ return od.proto
+}
+
+// String returns the underlying descriptor proto, in compact text format.
+func (od *OneOfDescriptor) String() string {
+ return od.proto.String()
+}
+
+// GetChoices returns the fields that are part of the one-of field set. At most one of
+// these fields may be set for a given message.
+func (od *OneOfDescriptor) GetChoices() []*FieldDescriptor {
+ return od.choices
+}
+
+func (od *OneOfDescriptor) IsSynthetic() bool {
+ return len(od.choices) == 1 && od.choices[0].IsProto3Optional()
+}
+
+// scope represents a lexical scope in a proto file in which messages and enums
+// can be declared.
+type scope func(string) Descriptor
+
+func fileScope(fd *FileDescriptor) scope {
+ // we search symbols in this file, but also symbols in other files that have
+ // the same package as this file or a "parent" package (in protobuf,
+ // packages are a hierarchy like C++ namespaces)
+ prefixes := internal.CreatePrefixList(fd.proto.GetPackage())
+ return func(name string) Descriptor {
+ for _, prefix := range prefixes {
+ n := merge(prefix, name)
+ d := findSymbol(fd, n, false)
+ if d != nil {
+ return d
+ }
+ }
+ return nil
+ }
+}
+
+func messageScope(md *MessageDescriptor) scope {
+ return func(name string) Descriptor {
+ n := merge(md.fqn, name)
+ if d, ok := md.file.symbols[n]; ok {
+ return d
+ }
+ return nil
+ }
+}
+
+func resolve(fd *FileDescriptor, name string, scopes []scope) (Descriptor, error) {
+ if strings.HasPrefix(name, ".") {
+ // already fully-qualified
+ d := findSymbol(fd, name[1:], false)
+ if d != nil {
+ return d, nil
+ }
+ } else {
+ // unqualified, so we look in the enclosing (last) scope first and move
+ // towards outermost (first) scope, trying to resolve the symbol
+ for i := len(scopes) - 1; i >= 0; i-- {
+ d := scopes[i](name)
+ if d != nil {
+ return d, nil
+ }
+ }
+ }
+ return nil, fmt.Errorf("file %q included an unresolvable reference to %q", fd.proto.GetName(), name)
+}
+
+func findSymbol(fd *FileDescriptor, name string, public bool) Descriptor {
+ d := fd.symbols[name]
+ if d != nil {
+ return d
+ }
+
+ // When public = false, we are searching only directly imported symbols. But we
+ // also need to search transitive public imports due to semantics of public imports.
+ var deps []*FileDescriptor
+ if public {
+ deps = fd.publicDeps
+ } else {
+ deps = fd.deps
+ }
+ for _, dep := range deps {
+ d = findSymbol(dep, name, true)
+ if d != nil {
+ return d
+ }
+ }
+
+ return nil
+}
+
+func merge(a, b string) string {
+ if a == "" {
+ return b
+ } else {
+ return a + "." + b
+ }
+}
diff --git a/vendor/github.com/jhump/protoreflect/desc/descriptor_no_unsafe.go b/vendor/github.com/jhump/protoreflect/desc/descriptor_no_unsafe.go
new file mode 100644
index 0000000..25d619a
--- /dev/null
+++ b/vendor/github.com/jhump/protoreflect/desc/descriptor_no_unsafe.go
@@ -0,0 +1,30 @@
+//go:build appengine || gopherjs || purego
+// +build appengine gopherjs purego
+
+// NB: other environments where unsafe is unappropriate should use "purego" build tag
+// https://github.com/golang/go/issues/23172
+
+package desc
+
+type jsonNameMap struct{}
+type memoizedDefault struct{}
+
+// FindFieldByJSONName finds the field with the given JSON field name. If no such
+// field exists then nil is returned. Only regular fields are returned, not
+// extensions.
+func (md *MessageDescriptor) FindFieldByJSONName(jsonName string) *FieldDescriptor {
+ // NB: With allowed use of unsafe, we use it to atomically define an index
+ // via atomic.LoadPointer/atomic.StorePointer. Without it, we skip the index
+ // and must do a linear scan of fields each time.
+ for _, f := range md.fields {
+ jn := f.GetJSONName()
+ if jn == jsonName {
+ return f
+ }
+ }
+ return nil
+}
+
+func (fd *FieldDescriptor) getDefaultValue() interface{} {
+ return fd.determineDefault()
+}
diff --git a/vendor/github.com/jhump/protoreflect/desc/descriptor_unsafe.go b/vendor/github.com/jhump/protoreflect/desc/descriptor_unsafe.go
new file mode 100644
index 0000000..691f0d8
--- /dev/null
+++ b/vendor/github.com/jhump/protoreflect/desc/descriptor_unsafe.go
@@ -0,0 +1,59 @@
+//go:build !appengine && !gopherjs && !purego
+// +build !appengine,!gopherjs,!purego
+
+// NB: other environments where unsafe is unappropriate should use "purego" build tag
+// https://github.com/golang/go/issues/23172
+
+package desc
+
+import (
+ "sync/atomic"
+ "unsafe"
+)
+
+type jsonNameMap map[string]*FieldDescriptor // loaded/stored atomically via atomic+unsafe
+type memoizedDefault *interface{} // loaded/stored atomically via atomic+unsafe
+
+// FindFieldByJSONName finds the field with the given JSON field name. If no such
+// field exists then nil is returned. Only regular fields are returned, not
+// extensions.
+func (md *MessageDescriptor) FindFieldByJSONName(jsonName string) *FieldDescriptor {
+ // NB: We don't want to eagerly index JSON names because many programs won't use it.
+ // So we want to do it lazily, but also make sure the result is thread-safe. So we
+ // atomically load/store the map as if it were a normal pointer. We don't use other
+ // mechanisms -- like sync.Mutex, sync.RWMutex, sync.Once, or atomic.Value -- to
+ // do this lazily because those types cannot be copied, and we'd rather not induce
+ // 'go vet' errors in programs that use descriptors and try to copy them.
+ // If multiple goroutines try to access the index at the same time, before it is
+ // built, they will all end up computing the index redundantly. Future reads of
+ // the index will use whatever was the "last one stored" by those racing goroutines.
+ // Since building the index is deterministic, this is fine: all indices computed
+ // will be the same.
+ addrOfJsonNames := (*unsafe.Pointer)(unsafe.Pointer(&md.jsonNames))
+ jsonNames := atomic.LoadPointer(addrOfJsonNames)
+ var index map[string]*FieldDescriptor
+ if jsonNames == nil {
+ // slow path: compute the index
+ index = map[string]*FieldDescriptor{}
+ for _, f := range md.fields {
+ jn := f.GetJSONName()
+ index[jn] = f
+ }
+ atomic.StorePointer(addrOfJsonNames, *(*unsafe.Pointer)(unsafe.Pointer(&index)))
+ } else {
+ *(*unsafe.Pointer)(unsafe.Pointer(&index)) = jsonNames
+ }
+ return index[jsonName]
+}
+
+func (fd *FieldDescriptor) getDefaultValue() interface{} {
+ addrOfDef := (*unsafe.Pointer)(unsafe.Pointer(&fd.def))
+ def := atomic.LoadPointer(addrOfDef)
+ if def != nil {
+ return *(*interface{})(def)
+ }
+ // slow path: compute the default, potentially involves decoding value
+ d := fd.determineDefault()
+ atomic.StorePointer(addrOfDef, (unsafe.Pointer(&d)))
+ return d
+}
diff --git a/vendor/github.com/jhump/protoreflect/desc/doc.go b/vendor/github.com/jhump/protoreflect/desc/doc.go
new file mode 100644
index 0000000..1740dce
--- /dev/null
+++ b/vendor/github.com/jhump/protoreflect/desc/doc.go
@@ -0,0 +1,41 @@
+// Package desc contains "rich descriptors" for protocol buffers. The built-in
+// descriptor types are simple protobuf messages, each one representing a
+// different kind of element in the AST of a .proto source file.
+//
+// Because of this inherent "tree" quality, these build-in descriptors cannot
+// refer to their enclosing file descriptor. Nor can a field descriptor refer to
+// a message or enum descriptor that represents the field's type (for enum and
+// nested message fields). All such links must instead be stringly typed. This
+// limitation makes them much harder to use for doing interesting things with
+// reflection.
+//
+// Without this package, resolving references to types is particularly complex.
+// For example, resolving a field's type, the message type an extension extends,
+// or the request and response types of an RPC method all require searching
+// through symbols defined not only in the file in which these elements are
+// declared but also in its transitive closure of dependencies.
+//
+// "Rich descriptors" avoid the need to deal with the complexities described
+// above. A rich descriptor has all type references resolved and provides
+// methods to access other rich descriptors for all referenced elements. Each
+// rich descriptor has a usefully broad API, but does not try to mimic the full
+// interface of the underlying descriptor proto. Instead, every rich descriptor
+// provides access to that underlying proto, for extracting descriptor
+// properties that are not immediately accessible through rich descriptor's
+// methods.
+//
+// Rich descriptors can be accessed in similar ways as their "poor" cousins
+// (descriptor protos). Instead of using proto.FileDescriptor, use
+// desc.LoadFileDescriptor. Message descriptors and extension field descriptors
+// can also be easily accessed using desc.LoadMessageDescriptor and
+// desc.LoadFieldDescriptorForExtension, respectively.
+//
+// It is also possible create rich descriptors for proto messages that a given
+// Go program doesn't even know about. For example, they could be loaded from a
+// FileDescriptorSet file (which can be generated by protoc) or loaded from a
+// server. This enables interesting things like dynamic clients: where a Go
+// program can be an RPC client of a service it wasn't compiled to know about.
+//
+// Also see the grpcreflect, dynamic, and grpcdynamic packages in this same
+// repo to see just how useful rich descriptors really are.
+package desc
diff --git a/vendor/github.com/jhump/protoreflect/desc/imports.go b/vendor/github.com/jhump/protoreflect/desc/imports.go
new file mode 100644
index 0000000..ab93032
--- /dev/null
+++ b/vendor/github.com/jhump/protoreflect/desc/imports.go
@@ -0,0 +1,313 @@
+package desc
+
+import (
+ "fmt"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "sync"
+
+ "github.com/golang/protobuf/proto"
+ dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
+)
+
+var (
+ globalImportPathConf map[string]string
+ globalImportPathMu sync.RWMutex
+)
+
+// RegisterImportPath registers an alternate import path for a given registered
+// proto file path. For more details on why alternate import paths may need to
+// be configured, see ImportResolver.
+//
+// This method panics if provided invalid input. An empty importPath is invalid.
+// An un-registered registerPath is also invalid. For example, if an attempt is
+// made to register the import path "foo/bar.proto" as "bar.proto", but there is
+// no "bar.proto" registered in the Go protobuf runtime, this method will panic.
+// This method also panics if an attempt is made to register the same import
+// path more than once.
+//
+// This function works globally, applying to all descriptors loaded by this
+// package. If you instead want more granular support for handling alternate
+// import paths -- such as for a single invocation of a function in this
+// package or when the alternate path is only used from one file (so you don't
+// want the alternate path used when loading every other file), use an
+// ImportResolver instead.
+func RegisterImportPath(registerPath, importPath string) {
+ if len(importPath) == 0 {
+ panic("import path cannot be empty")
+ }
+ desc := proto.FileDescriptor(registerPath)
+ if len(desc) == 0 {
+ panic(fmt.Sprintf("path %q is not a registered proto file", registerPath))
+ }
+ globalImportPathMu.Lock()
+ defer globalImportPathMu.Unlock()
+ if reg := globalImportPathConf[importPath]; reg != "" {
+ panic(fmt.Sprintf("import path %q already registered for %s", importPath, reg))
+ }
+ if globalImportPathConf == nil {
+ globalImportPathConf = map[string]string{}
+ }
+ globalImportPathConf[importPath] = registerPath
+}
+
+// ResolveImport resolves the given import path. If it has been registered as an
+// alternate via RegisterImportPath, the registered path is returned. Otherwise,
+// the given import path is returned unchanged.
+func ResolveImport(importPath string) string {
+ importPath = clean(importPath)
+ globalImportPathMu.RLock()
+ defer globalImportPathMu.RUnlock()
+ reg := globalImportPathConf[importPath]
+ if reg == "" {
+ return importPath
+ }
+ return reg
+}
+
+// ImportResolver lets you work-around linking issues that are caused by
+// mismatches between how a particular proto source file is registered in the Go
+// protobuf runtime and how that same file is imported by other files. The file
+// is registered using the same relative path given to protoc when the file is
+// compiled (i.e. when Go code is generated). So if any file tries to import
+// that source file, but using a different relative path, then a link error will
+// occur when this package tries to load a descriptor for the importing file.
+//
+// For example, let's say we have two proto source files: "foo/bar.proto" and
+// "fubar/baz.proto". The latter imports the former using a line like so:
+// import "foo/bar.proto";
+// However, when protoc is invoked, the command-line args looks like so:
+// protoc -Ifoo/ --go_out=foo/ bar.proto
+// protoc -I./ -Ifubar/ --go_out=fubar/ baz.proto
+// Because the path given to protoc is just "bar.proto" and "baz.proto", this is
+// how they are registered in the Go protobuf runtime. So, when loading the
+// descriptor for "fubar/baz.proto", we'll see an import path of "foo/bar.proto"
+// but will find no file registered with that path:
+// fd, err := desc.LoadFileDescriptor("baz.proto")
+// // err will be non-nil, complaining that there is no such file
+// // found named "foo/bar.proto"
+//
+// This can be remedied by registering alternate import paths using an
+// ImportResolver. Continuing with the example above, the code below would fix
+// any link issue:
+// var r desc.ImportResolver
+// r.RegisterImportPath("bar.proto", "foo/bar.proto")
+// fd, err := r.LoadFileDescriptor("baz.proto")
+// // err will be nil; descriptor successfully loaded!
+//
+// If there are files that are *always* imported using a different relative
+// path then how they are registered, consider using the global
+// RegisterImportPath function, so you don't have to use an ImportResolver for
+// every file that imports it.
+type ImportResolver struct {
+ children map[string]*ImportResolver
+ importPaths map[string]string
+
+ // By default, an ImportResolver will fallback to consulting any paths
+ // registered via the top-level RegisterImportPath function. Setting this
+ // field to true will cause the ImportResolver to skip that fallback and
+ // only examine its own locally registered paths.
+ SkipFallbackRules bool
+}
+
+// ResolveImport resolves the given import path in the context of the given
+// source file. If a matching alternate has been registered with this resolver
+// via a call to RegisterImportPath or RegisterImportPathFrom, then the
+// registered path is returned. Otherwise, the given import path is returned
+// unchanged.
+func (r *ImportResolver) ResolveImport(source, importPath string) string {
+ if r != nil {
+ res := r.resolveImport(clean(source), clean(importPath))
+ if res != "" {
+ return res
+ }
+ if r.SkipFallbackRules {
+ return importPath
+ }
+ }
+ return ResolveImport(importPath)
+}
+
+func (r *ImportResolver) resolveImport(source, importPath string) string {
+ if source == "" {
+ return r.importPaths[importPath]
+ }
+ var car, cdr string
+ idx := strings.IndexRune(source, filepath.Separator)
+ if idx < 0 {
+ car, cdr = source, ""
+ } else {
+ car, cdr = source[:idx], source[idx+1:]
+ }
+ ch := r.children[car]
+ if ch != nil {
+ if reg := ch.resolveImport(cdr, importPath); reg != "" {
+ return reg
+ }
+ }
+ return r.importPaths[importPath]
+}
+
+// RegisterImportPath registers an alternate import path for a given registered
+// proto file path with this resolver. Any appearance of the given import path
+// when linking files will instead try to link the given registered path. If the
+// registered path cannot be located, then linking will fallback to the actual
+// imported path.
+//
+// This method will panic if given an empty path or if the same import path is
+// registered more than once.
+//
+// To constrain the contexts where the given import path is to be re-written,
+// use RegisterImportPathFrom instead.
+func (r *ImportResolver) RegisterImportPath(registerPath, importPath string) {
+ r.RegisterImportPathFrom(registerPath, importPath, "")
+}
+
+// RegisterImportPathFrom registers an alternate import path for a given
+// registered proto file path with this resolver, but only for imports in the
+// specified source context.
+//
+// The source context can be the name of a folder or a proto source file. Any
+// appearance of the given import path in that context will instead try to link
+// the given registered path. To be in context, the file that is being linked
+// (i.e. the one whose import statement is being resolved) must be the same
+// relative path of the source context or be a sub-path (i.e. a descendant of
+// the source folder).
+//
+// If the registered path cannot be located, then linking will fallback to the
+// actual imported path.
+//
+// This method will panic if given an empty path. The source context, on the
+// other hand, is allowed to be blank. A blank source matches all files. This
+// method also panics if the same import path is registered in the same source
+// context more than once.
+func (r *ImportResolver) RegisterImportPathFrom(registerPath, importPath, source string) {
+ importPath = clean(importPath)
+ if len(importPath) == 0 {
+ panic("import path cannot be empty")
+ }
+ registerPath = clean(registerPath)
+ if len(registerPath) == 0 {
+ panic("registered path cannot be empty")
+ }
+ r.registerImportPathFrom(registerPath, importPath, clean(source))
+}
+
+func (r *ImportResolver) registerImportPathFrom(registerPath, importPath, source string) {
+ if source == "" {
+ if r.importPaths == nil {
+ r.importPaths = map[string]string{}
+ } else if reg := r.importPaths[importPath]; reg != "" {
+ panic(fmt.Sprintf("already registered import path %q as %q", importPath, registerPath))
+ }
+ r.importPaths[importPath] = registerPath
+ return
+ }
+ var car, cdr string
+ idx := strings.IndexRune(source, filepath.Separator)
+ if idx < 0 {
+ car, cdr = source, ""
+ } else {
+ car, cdr = source[:idx], source[idx+1:]
+ }
+ ch := r.children[car]
+ if ch == nil {
+ if r.children == nil {
+ r.children = map[string]*ImportResolver{}
+ }
+ ch = &ImportResolver{}
+ r.children[car] = ch
+ }
+ ch.registerImportPathFrom(registerPath, importPath, cdr)
+}
+
+// LoadFileDescriptor is the same as the package function of the same name, but
+// any alternate paths configured in this resolver are used when linking the
+// given descriptor proto.
+func (r *ImportResolver) LoadFileDescriptor(filePath string) (*FileDescriptor, error) {
+ return loadFileDescriptor(filePath, r)
+}
+
+// LoadMessageDescriptor is the same as the package function of the same name,
+// but any alternate paths configured in this resolver are used when linking
+// files for the returned descriptor.
+func (r *ImportResolver) LoadMessageDescriptor(msgName string) (*MessageDescriptor, error) {
+ return loadMessageDescriptor(msgName, r)
+}
+
+// LoadMessageDescriptorForMessage is the same as the package function of the
+// same name, but any alternate paths configured in this resolver are used when
+// linking files for the returned descriptor.
+func (r *ImportResolver) LoadMessageDescriptorForMessage(msg proto.Message) (*MessageDescriptor, error) {
+ return loadMessageDescriptorForMessage(msg, r)
+}
+
+// LoadMessageDescriptorForType is the same as the package function of the same
+// name, but any alternate paths configured in this resolver are used when
+// linking files for the returned descriptor.
+func (r *ImportResolver) LoadMessageDescriptorForType(msgType reflect.Type) (*MessageDescriptor, error) {
+ return loadMessageDescriptorForType(msgType, r)
+}
+
+// LoadEnumDescriptorForEnum is the same as the package function of the same
+// name, but any alternate paths configured in this resolver are used when
+// linking files for the returned descriptor.
+func (r *ImportResolver) LoadEnumDescriptorForEnum(enum protoEnum) (*EnumDescriptor, error) {
+ return loadEnumDescriptorForEnum(enum, r)
+}
+
+// LoadEnumDescriptorForType is the same as the package function of the same
+// name, but any alternate paths configured in this resolver are used when
+// linking files for the returned descriptor.
+func (r *ImportResolver) LoadEnumDescriptorForType(enumType reflect.Type) (*EnumDescriptor, error) {
+ return loadEnumDescriptorForType(enumType, r)
+}
+
+// LoadFieldDescriptorForExtension is the same as the package function of the
+// same name, but any alternate paths configured in this resolver are used when
+// linking files for the returned descriptor.
+func (r *ImportResolver) LoadFieldDescriptorForExtension(ext *proto.ExtensionDesc) (*FieldDescriptor, error) {
+ return loadFieldDescriptorForExtension(ext, r)
+}
+
+// CreateFileDescriptor is the same as the package function of the same name,
+// but any alternate paths configured in this resolver are used when linking the
+// given descriptor proto.
+func (r *ImportResolver) CreateFileDescriptor(fdp *dpb.FileDescriptorProto, deps ...*FileDescriptor) (*FileDescriptor, error) {
+ return createFileDescriptor(fdp, deps, r)
+}
+
+// CreateFileDescriptors is the same as the package function of the same name,
+// but any alternate paths configured in this resolver are used when linking the
+// given descriptor protos.
+func (r *ImportResolver) CreateFileDescriptors(fds []*dpb.FileDescriptorProto) (map[string]*FileDescriptor, error) {
+ return createFileDescriptors(fds, r)
+}
+
+// CreateFileDescriptorFromSet is the same as the package function of the same
+// name, but any alternate paths configured in this resolver are used when
+// linking the descriptor protos in the given set.
+func (r *ImportResolver) CreateFileDescriptorFromSet(fds *dpb.FileDescriptorSet) (*FileDescriptor, error) {
+ return createFileDescriptorFromSet(fds, r)
+}
+
+// CreateFileDescriptorsFromSet is the same as the package function of the same
+// name, but any alternate paths configured in this resolver are used when
+// linking the descriptor protos in the given set.
+func (r *ImportResolver) CreateFileDescriptorsFromSet(fds *dpb.FileDescriptorSet) (map[string]*FileDescriptor, error) {
+ return createFileDescriptorsFromSet(fds, r)
+}
+
+const dotPrefix = "." + string(filepath.Separator)
+
+func clean(path string) string {
+ if path == "" {
+ return ""
+ }
+ path = filepath.Clean(path)
+ if path == "." {
+ return ""
+ }
+ return strings.TrimPrefix(path, dotPrefix)
+}
diff --git a/vendor/github.com/jhump/protoreflect/desc/internal/proto3_optional.go b/vendor/github.com/jhump/protoreflect/desc/internal/proto3_optional.go
new file mode 100644
index 0000000..9aa4a3e
--- /dev/null
+++ b/vendor/github.com/jhump/protoreflect/desc/internal/proto3_optional.go
@@ -0,0 +1,120 @@
+package internal
+
+import (
+ "github.com/golang/protobuf/proto"
+ dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
+ "github.com/jhump/protoreflect/internal/codec"
+ "reflect"
+ "strings"
+
+ "github.com/jhump/protoreflect/internal"
+)
+
+// NB: We use reflection or unknown fields in case we are linked against an older
+// version of the proto runtime which does not know about the proto3_optional field.
+// We don't require linking with newer version (which would greatly simplify this)
+// because that means pulling in v1.4+ of the protobuf runtime, which has some
+// compatibility issues. (We'll be nice to users and not require they upgrade to
+// that latest runtime to upgrade to newer protoreflect.)
+
+func GetProto3Optional(fd *dpb.FieldDescriptorProto) bool {
+ type newerFieldDesc interface {
+ GetProto3Optional() bool
+ }
+ var pm proto.Message = fd
+ if fd, ok := pm.(newerFieldDesc); ok {
+ return fd.GetProto3Optional()
+ }
+
+ // Field does not exist, so we have to examine unknown fields
+ // (we just silently bail if we have problems parsing them)
+ unk := internal.GetUnrecognized(pm)
+ buf := codec.NewBuffer(unk)
+ for {
+ tag, wt, err := buf.DecodeTagAndWireType()
+ if err != nil {
+ return false
+ }
+ if tag == Field_proto3OptionalTag && wt == proto.WireVarint {
+ v, _ := buf.DecodeVarint()
+ return v != 0
+ }
+ if err := buf.SkipField(wt); err != nil {
+ return false
+ }
+ }
+}
+
+func SetProto3Optional(fd *dpb.FieldDescriptorProto) {
+ rv := reflect.ValueOf(fd).Elem()
+ fld := rv.FieldByName("Proto3Optional")
+ if fld.IsValid() {
+ fld.Set(reflect.ValueOf(proto.Bool(true)))
+ return
+ }
+
+ // Field does not exist, so we have to store as unknown field.
+ var buf codec.Buffer
+ if err := buf.EncodeTagAndWireType(Field_proto3OptionalTag, proto.WireVarint); err != nil {
+ // TODO: panic? log?
+ return
+ }
+ if err := buf.EncodeVarint(1); err != nil {
+ // TODO: panic? log?
+ return
+ }
+ internal.SetUnrecognized(fd, buf.Bytes())
+}
+
+// ProcessProto3OptionalFields adds synthetic oneofs to the given message descriptor
+// for each proto3 optional field. It also updates the fields to have the correct
+// oneof index reference.
+func ProcessProto3OptionalFields(msgd *dpb.DescriptorProto) {
+ var allNames map[string]struct{}
+ for _, fd := range msgd.Field {
+ if GetProto3Optional(fd) {
+ // lazy init the set of all names
+ if allNames == nil {
+ allNames = map[string]struct{}{}
+ for _, fd := range msgd.Field {
+ allNames[fd.GetName()] = struct{}{}
+ }
+ for _, fd := range msgd.Extension {
+ allNames[fd.GetName()] = struct{}{}
+ }
+ for _, ed := range msgd.EnumType {
+ allNames[ed.GetName()] = struct{}{}
+ for _, evd := range ed.Value {
+ allNames[evd.GetName()] = struct{}{}
+ }
+ }
+ for _, fd := range msgd.NestedType {
+ allNames[fd.GetName()] = struct{}{}
+ }
+ for _, n := range msgd.ReservedName {
+ allNames[n] = struct{}{}
+ }
+ }
+
+ // Compute a name for the synthetic oneof. This uses the same
+ // algorithm as used in protoc:
+ // https://github.com/protocolbuffers/protobuf/blob/74ad62759e0a9b5a21094f3fb9bb4ebfaa0d1ab8/src/google/protobuf/compiler/parser.cc#L785-L803
+ ooName := fd.GetName()
+ if !strings.HasPrefix(ooName, "_") {
+ ooName = "_" + ooName
+ }
+ for {
+ _, ok := allNames[ooName]
+ if !ok {
+ // found a unique name
+ allNames[ooName] = struct{}{}
+ break
+ }
+ ooName = "X" + ooName
+ }
+
+ fd.OneofIndex = proto.Int32(int32(len(msgd.OneofDecl)))
+ msgd.OneofDecl = append(msgd.OneofDecl, &dpb.OneofDescriptorProto{Name: proto.String(ooName)})
+ }
+ }
+}
diff --git a/vendor/github.com/jhump/protoreflect/desc/internal/source_info.go b/vendor/github.com/jhump/protoreflect/desc/internal/source_info.go
new file mode 100644
index 0000000..b4150b8
--- /dev/null
+++ b/vendor/github.com/jhump/protoreflect/desc/internal/source_info.go
@@ -0,0 +1,107 @@
+package internal
+
+import (
+ dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
+)
+
+// SourceInfoMap is a map of paths in a descriptor to the corresponding source
+// code info.
+type SourceInfoMap map[string][]*dpb.SourceCodeInfo_Location
+
+// Get returns the source code info for the given path. If there are
+// multiple locations for the same path, the first one is returned.
+func (m SourceInfoMap) Get(path []int32) *dpb.SourceCodeInfo_Location {
+ v := m[asMapKey(path)]
+ if len(v) > 0 {
+ return v[0]
+ }
+ return nil
+}
+
+// GetAll returns all source code info for the given path.
+func (m SourceInfoMap) GetAll(path []int32) []*dpb.SourceCodeInfo_Location {
+ return m[asMapKey(path)]
+}
+
+// Add stores the given source code info for the given path.
+func (m SourceInfoMap) Add(path []int32, loc *dpb.SourceCodeInfo_Location) {
+ m[asMapKey(path)] = append(m[asMapKey(path)], loc)
+}
+
+// PutIfAbsent stores the given source code info for the given path only if the
+// given path does not exist in the map. This method returns true when the value
+// is stored, false if the path already exists.
+func (m SourceInfoMap) PutIfAbsent(path []int32, loc *dpb.SourceCodeInfo_Location) bool {
+ k := asMapKey(path)
+ if _, ok := m[k]; ok {
+ return false
+ }
+ m[k] = []*dpb.SourceCodeInfo_Location{loc}
+ return true
+}
+
+func asMapKey(slice []int32) string {
+ // NB: arrays should be usable as map keys, but this does not
+ // work due to a bug: https://github.com/golang/go/issues/22605
+ //rv := reflect.ValueOf(slice)
+ //arrayType := reflect.ArrayOf(rv.Len(), rv.Type().Elem())
+ //array := reflect.New(arrayType).Elem()
+ //reflect.Copy(array, rv)
+ //return array.Interface()
+
+ b := make([]byte, len(slice)*4)
+ j := 0
+ for _, s := range slice {
+ b[j] = byte(s)
+ b[j+1] = byte(s >> 8)
+ b[j+2] = byte(s >> 16)
+ b[j+3] = byte(s >> 24)
+ j += 4
+ }
+ return string(b)
+}
+
+// CreateSourceInfoMap constructs a new SourceInfoMap and populates it with the
+// source code info in the given file descriptor proto.
+func CreateSourceInfoMap(fd *dpb.FileDescriptorProto) SourceInfoMap {
+ res := SourceInfoMap{}
+ PopulateSourceInfoMap(fd, res)
+ return res
+}
+
+// PopulateSourceInfoMap populates the given SourceInfoMap with information from
+// the given file descriptor.
+func PopulateSourceInfoMap(fd *dpb.FileDescriptorProto, m SourceInfoMap) {
+ for _, l := range fd.GetSourceCodeInfo().GetLocation() {
+ m.Add(l.Path, l)
+ }
+}
+
+// NB: This wonkiness allows desc.Descriptor impl to implement an interface that
+// is only usable from this package, by embedding a SourceInfoComputeFunc that
+// implements the actual logic (which must live in desc package to avoid a
+// dependency cycle).
+
+// SourceInfoComputer is a single method which will be invoked to recompute
+// source info. This is needed for the protoparse package, which needs to link
+// descriptors without source info in order to interpret options, but then needs
+// to re-compute source info after that interpretation so that final linked
+// descriptors expose the right info.
+type SourceInfoComputer interface {
+ recomputeSourceInfo()
+}
+
+// SourceInfoComputeFunc is the type that a desc.Descriptor will embed. It will
+// be aliased in the desc package to an unexported name so it is not marked as
+// an exported field in reflection and not present in Go docs.
+type SourceInfoComputeFunc func()
+
+func (f SourceInfoComputeFunc) recomputeSourceInfo() {
+ f()
+}
+
+// RecomputeSourceInfo is used to initiate recomputation of source info. This is
+// is used by the protoparse package, after it interprets options.
+func RecomputeSourceInfo(c SourceInfoComputer) {
+ c.recomputeSourceInfo()
+}
diff --git a/vendor/github.com/jhump/protoreflect/desc/internal/util.go b/vendor/github.com/jhump/protoreflect/desc/internal/util.go
new file mode 100644
index 0000000..71855bf
--- /dev/null
+++ b/vendor/github.com/jhump/protoreflect/desc/internal/util.go
@@ -0,0 +1,291 @@
+package internal
+
+import (
+ "math"
+ "unicode"
+ "unicode/utf8"
+)
+
+const (
+ // MaxNormalTag is the maximum allowed tag number for a field in a normal message.
+ MaxNormalTag = 536870911 // 2^29 - 1
+
+ // MaxMessageSetTag is the maximum allowed tag number of a field in a message that
+ // uses the message set wire format.
+ MaxMessageSetTag = math.MaxInt32 - 1
+
+ // MaxTag is the maximum allowed tag number. (It is the same as MaxMessageSetTag
+ // since that is the absolute highest allowed.)
+ MaxTag = MaxMessageSetTag
+
+ // SpecialReservedStart is the first tag in a range that is reserved and not
+ // allowed for use in message definitions.
+ SpecialReservedStart = 19000
+ // SpecialReservedEnd is the last tag in a range that is reserved and not
+ // allowed for use in message definitions.
+ SpecialReservedEnd = 19999
+
+ // NB: It would be nice to use constants from generated code instead of
+ // hard-coding these here. But code-gen does not emit these as constants
+ // anywhere. The only places they appear in generated code are struct tags
+ // on fields of the generated descriptor protos.
+
+ // File_packageTag is the tag number of the package element in a file
+ // descriptor proto.
+ File_packageTag = 2
+ // File_dependencyTag is the tag number of the dependencies element in a
+ // file descriptor proto.
+ File_dependencyTag = 3
+ // File_messagesTag is the tag number of the messages element in a file
+ // descriptor proto.
+ File_messagesTag = 4
+ // File_enumsTag is the tag number of the enums element in a file descriptor
+ // proto.
+ File_enumsTag = 5
+ // File_servicesTag is the tag number of the services element in a file
+ // descriptor proto.
+ File_servicesTag = 6
+ // File_extensionsTag is the tag number of the extensions element in a file
+ // descriptor proto.
+ File_extensionsTag = 7
+ // File_optionsTag is the tag number of the options element in a file
+ // descriptor proto.
+ File_optionsTag = 8
+ // File_syntaxTag is the tag number of the syntax element in a file
+ // descriptor proto.
+ File_syntaxTag = 12
+ // Message_nameTag is the tag number of the name element in a message
+ // descriptor proto.
+ Message_nameTag = 1
+ // Message_fieldsTag is the tag number of the fields element in a message
+ // descriptor proto.
+ Message_fieldsTag = 2
+ // Message_nestedMessagesTag is the tag number of the nested messages
+ // element in a message descriptor proto.
+ Message_nestedMessagesTag = 3
+ // Message_enumsTag is the tag number of the enums element in a message
+ // descriptor proto.
+ Message_enumsTag = 4
+ // Message_extensionRangeTag is the tag number of the extension ranges
+ // element in a message descriptor proto.
+ Message_extensionRangeTag = 5
+ // Message_extensionsTag is the tag number of the extensions element in a
+ // message descriptor proto.
+ Message_extensionsTag = 6
+ // Message_optionsTag is the tag number of the options element in a message
+ // descriptor proto.
+ Message_optionsTag = 7
+ // Message_oneOfsTag is the tag number of the one-ofs element in a message
+ // descriptor proto.
+ Message_oneOfsTag = 8
+ // Message_reservedRangeTag is the tag number of the reserved ranges element
+ // in a message descriptor proto.
+ Message_reservedRangeTag = 9
+ // Message_reservedNameTag is the tag number of the reserved names element
+ // in a message descriptor proto.
+ Message_reservedNameTag = 10
+ // ExtensionRange_startTag is the tag number of the start index in an
+ // extension range proto.
+ ExtensionRange_startTag = 1
+ // ExtensionRange_endTag is the tag number of the end index in an
+ // extension range proto.
+ ExtensionRange_endTag = 2
+ // ExtensionRange_optionsTag is the tag number of the options element in an
+ // extension range proto.
+ ExtensionRange_optionsTag = 3
+ // ReservedRange_startTag is the tag number of the start index in a reserved
+ // range proto.
+ ReservedRange_startTag = 1
+ // ReservedRange_endTag is the tag number of the end index in a reserved
+ // range proto.
+ ReservedRange_endTag = 2
+ // Field_nameTag is the tag number of the name element in a field descriptor
+ // proto.
+ Field_nameTag = 1
+ // Field_extendeeTag is the tag number of the extendee element in a field
+ // descriptor proto.
+ Field_extendeeTag = 2
+ // Field_numberTag is the tag number of the number element in a field
+ // descriptor proto.
+ Field_numberTag = 3
+ // Field_labelTag is the tag number of the label element in a field
+ // descriptor proto.
+ Field_labelTag = 4
+ // Field_typeTag is the tag number of the type element in a field descriptor
+ // proto.
+ Field_typeTag = 5
+ // Field_typeNameTag is the tag number of the type name element in a field
+ // descriptor proto.
+ Field_typeNameTag = 6
+ // Field_defaultTag is the tag number of the default value element in a
+ // field descriptor proto.
+ Field_defaultTag = 7
+ // Field_optionsTag is the tag number of the options element in a field
+ // descriptor proto.
+ Field_optionsTag = 8
+ // Field_jsonNameTag is the tag number of the JSON name element in a field
+ // descriptor proto.
+ Field_jsonNameTag = 10
+ // Field_proto3OptionalTag is the tag number of the proto3_optional element
+ // in a descriptor proto.
+ Field_proto3OptionalTag = 17
+ // OneOf_nameTag is the tag number of the name element in a one-of
+ // descriptor proto.
+ OneOf_nameTag = 1
+ // OneOf_optionsTag is the tag number of the options element in a one-of
+ // descriptor proto.
+ OneOf_optionsTag = 2
+ // Enum_nameTag is the tag number of the name element in an enum descriptor
+ // proto.
+ Enum_nameTag = 1
+ // Enum_valuesTag is the tag number of the values element in an enum
+ // descriptor proto.
+ Enum_valuesTag = 2
+ // Enum_optionsTag is the tag number of the options element in an enum
+ // descriptor proto.
+ Enum_optionsTag = 3
+ // Enum_reservedRangeTag is the tag number of the reserved ranges element in
+ // an enum descriptor proto.
+ Enum_reservedRangeTag = 4
+ // Enum_reservedNameTag is the tag number of the reserved names element in
+ // an enum descriptor proto.
+ Enum_reservedNameTag = 5
+ // EnumVal_nameTag is the tag number of the name element in an enum value
+ // descriptor proto.
+ EnumVal_nameTag = 1
+ // EnumVal_numberTag is the tag number of the number element in an enum
+ // value descriptor proto.
+ EnumVal_numberTag = 2
+ // EnumVal_optionsTag is the tag number of the options element in an enum
+ // value descriptor proto.
+ EnumVal_optionsTag = 3
+ // Service_nameTag is the tag number of the name element in a service
+ // descriptor proto.
+ Service_nameTag = 1
+ // Service_methodsTag is the tag number of the methods element in a service
+ // descriptor proto.
+ Service_methodsTag = 2
+ // Service_optionsTag is the tag number of the options element in a service
+ // descriptor proto.
+ Service_optionsTag = 3
+ // Method_nameTag is the tag number of the name element in a method
+ // descriptor proto.
+ Method_nameTag = 1
+ // Method_inputTag is the tag number of the input type element in a method
+ // descriptor proto.
+ Method_inputTag = 2
+ // Method_outputTag is the tag number of the output type element in a method
+ // descriptor proto.
+ Method_outputTag = 3
+ // Method_optionsTag is the tag number of the options element in a method
+ // descriptor proto.
+ Method_optionsTag = 4
+ // Method_inputStreamTag is the tag number of the input stream flag in a
+ // method descriptor proto.
+ Method_inputStreamTag = 5
+ // Method_outputStreamTag is the tag number of the output stream flag in a
+ // method descriptor proto.
+ Method_outputStreamTag = 6
+
+ // UninterpretedOptionsTag is the tag number of the uninterpreted options
+ // element. All *Options messages use the same tag for the field that stores
+ // uninterpreted options.
+ UninterpretedOptionsTag = 999
+
+ // Uninterpreted_nameTag is the tag number of the name element in an
+ // uninterpreted options proto.
+ Uninterpreted_nameTag = 2
+ // Uninterpreted_identTag is the tag number of the identifier value in an
+ // uninterpreted options proto.
+ Uninterpreted_identTag = 3
+ // Uninterpreted_posIntTag is the tag number of the positive int value in an
+ // uninterpreted options proto.
+ Uninterpreted_posIntTag = 4
+ // Uninterpreted_negIntTag is the tag number of the negative int value in an
+ // uninterpreted options proto.
+ Uninterpreted_negIntTag = 5
+ // Uninterpreted_doubleTag is the tag number of the double value in an
+ // uninterpreted options proto.
+ Uninterpreted_doubleTag = 6
+ // Uninterpreted_stringTag is the tag number of the string value in an
+ // uninterpreted options proto.
+ Uninterpreted_stringTag = 7
+ // Uninterpreted_aggregateTag is the tag number of the aggregate value in an
+ // uninterpreted options proto.
+ Uninterpreted_aggregateTag = 8
+ // UninterpretedName_nameTag is the tag number of the name element in an
+ // uninterpreted option name proto.
+ UninterpretedName_nameTag = 1
+)
+
+// JsonName returns the default JSON name for a field with the given name.
+func JsonName(name string) string {
+ var js []rune
+ nextUpper := false
+ for i, r := range name {
+ if r == '_' {
+ nextUpper = true
+ continue
+ }
+ if i == 0 {
+ js = append(js, r)
+ } else if nextUpper {
+ nextUpper = false
+ js = append(js, unicode.ToUpper(r))
+ } else {
+ js = append(js, r)
+ }
+ }
+ return string(js)
+}
+
+// InitCap returns the given field name, but with the first letter capitalized.
+func InitCap(name string) string {
+ r, sz := utf8.DecodeRuneInString(name)
+ return string(unicode.ToUpper(r)) + name[sz:]
+}
+
+// CreatePrefixList returns a list of package prefixes to search when resolving
+// a symbol name. If the given package is blank, it returns only the empty
+// string. If the given package contains only one token, e.g. "foo", it returns
+// that token and the empty string, e.g. ["foo", ""]. Otherwise, it returns
+// successively shorter prefixes of the package and then the empty string. For
+// example, for a package named "foo.bar.baz" it will return the following list:
+// ["foo.bar.baz", "foo.bar", "foo", ""]
+func CreatePrefixList(pkg string) []string {
+ if pkg == "" {
+ return []string{""}
+ }
+
+ numDots := 0
+ // one pass to pre-allocate the returned slice
+ for i := 0; i < len(pkg); i++ {
+ if pkg[i] == '.' {
+ numDots++
+ }
+ }
+ if numDots == 0 {
+ return []string{pkg, ""}
+ }
+
+ prefixes := make([]string, numDots+2)
+ // second pass to fill in returned slice
+ for i := 0; i < len(pkg); i++ {
+ if pkg[i] == '.' {
+ prefixes[numDots] = pkg[:i]
+ numDots--
+ }
+ }
+ prefixes[0] = pkg
+
+ return prefixes
+}
+
+// GetMaxTag returns the max tag number allowed, based on whether a message uses
+// message set wire format or not.
+func GetMaxTag(isMessageSet bool) int32 {
+ if isMessageSet {
+ return MaxMessageSetTag
+ }
+ return MaxNormalTag
+}
diff --git a/vendor/github.com/jhump/protoreflect/desc/load.go b/vendor/github.com/jhump/protoreflect/desc/load.go
new file mode 100644
index 0000000..4a05830
--- /dev/null
+++ b/vendor/github.com/jhump/protoreflect/desc/load.go
@@ -0,0 +1,341 @@
+package desc
+
+import (
+ "fmt"
+ "reflect"
+ "sync"
+
+ "github.com/golang/protobuf/proto"
+ dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
+
+ "github.com/jhump/protoreflect/internal"
+)
+
+var (
+ cacheMu sync.RWMutex
+ filesCache = map[string]*FileDescriptor{}
+ messagesCache = map[string]*MessageDescriptor{}
+ enumCache = map[reflect.Type]*EnumDescriptor{}
+)
+
+// LoadFileDescriptor creates a file descriptor using the bytes returned by
+// proto.FileDescriptor. Descriptors are cached so that they do not need to be
+// re-processed if the same file is fetched again later.
+func LoadFileDescriptor(file string) (*FileDescriptor, error) {
+ return loadFileDescriptor(file, nil)
+}
+
+func loadFileDescriptor(file string, r *ImportResolver) (*FileDescriptor, error) {
+ f := getFileFromCache(file)
+ if f != nil {
+ return f, nil
+ }
+ cacheMu.Lock()
+ defer cacheMu.Unlock()
+ return loadFileDescriptorLocked(file, r)
+}
+
+func loadFileDescriptorLocked(file string, r *ImportResolver) (*FileDescriptor, error) {
+ f := filesCache[file]
+ if f != nil {
+ return f, nil
+ }
+ fd, err := internal.LoadFileDescriptor(file)
+ if err != nil {
+ return nil, err
+ }
+
+ f, err = toFileDescriptorLocked(fd, r)
+ if err != nil {
+ return nil, err
+ }
+ putCacheLocked(file, f)
+ return f, nil
+}
+
+func toFileDescriptorLocked(fd *dpb.FileDescriptorProto, r *ImportResolver) (*FileDescriptor, error) {
+ deps := make([]*FileDescriptor, len(fd.GetDependency()))
+ for i, dep := range fd.GetDependency() {
+ resolvedDep := r.ResolveImport(fd.GetName(), dep)
+ var err error
+ deps[i], err = loadFileDescriptorLocked(resolvedDep, r)
+ if _, ok := err.(internal.ErrNoSuchFile); ok && resolvedDep != dep {
+ // try original path
+ deps[i], err = loadFileDescriptorLocked(dep, r)
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+ return CreateFileDescriptor(fd, deps...)
+}
+
+func getFileFromCache(file string) *FileDescriptor {
+ cacheMu.RLock()
+ defer cacheMu.RUnlock()
+ return filesCache[file]
+}
+
+func putCacheLocked(filename string, fd *FileDescriptor) {
+ filesCache[filename] = fd
+ putMessageCacheLocked(fd.messages)
+}
+
+func putMessageCacheLocked(mds []*MessageDescriptor) {
+ for _, md := range mds {
+ messagesCache[md.fqn] = md
+ putMessageCacheLocked(md.nested)
+ }
+}
+
+// interface implemented by generated messages, which all have a Descriptor() method in
+// addition to the methods of proto.Message
+type protoMessage interface {
+ proto.Message
+ Descriptor() ([]byte, []int)
+}
+
+// LoadMessageDescriptor loads descriptor using the encoded descriptor proto returned by
+// Message.Descriptor() for the given message type. If the given type is not recognized,
+// then a nil descriptor is returned.
+func LoadMessageDescriptor(message string) (*MessageDescriptor, error) {
+ return loadMessageDescriptor(message, nil)
+}
+
+func loadMessageDescriptor(message string, r *ImportResolver) (*MessageDescriptor, error) {
+ m := getMessageFromCache(message)
+ if m != nil {
+ return m, nil
+ }
+
+ pt := proto.MessageType(message)
+ if pt == nil {
+ return nil, nil
+ }
+ msg, err := messageFromType(pt)
+ if err != nil {
+ return nil, err
+ }
+
+ cacheMu.Lock()
+ defer cacheMu.Unlock()
+ return loadMessageDescriptorForTypeLocked(message, msg, r)
+}
+
+// LoadMessageDescriptorForType loads descriptor using the encoded descriptor proto returned
+// by message.Descriptor() for the given message type. If the given type is not recognized,
+// then a nil descriptor is returned.
+func LoadMessageDescriptorForType(messageType reflect.Type) (*MessageDescriptor, error) {
+ return loadMessageDescriptorForType(messageType, nil)
+}
+
+func loadMessageDescriptorForType(messageType reflect.Type, r *ImportResolver) (*MessageDescriptor, error) {
+ m, err := messageFromType(messageType)
+ if err != nil {
+ return nil, err
+ }
+ return loadMessageDescriptorForMessage(m, r)
+}
+
+// LoadMessageDescriptorForMessage loads descriptor using the encoded descriptor proto
+// returned by message.Descriptor(). If the given type is not recognized, then a nil
+// descriptor is returned.
+func LoadMessageDescriptorForMessage(message proto.Message) (*MessageDescriptor, error) {
+ return loadMessageDescriptorForMessage(message, nil)
+}
+
+func loadMessageDescriptorForMessage(message proto.Message, r *ImportResolver) (*MessageDescriptor, error) {
+ // efficiently handle dynamic messages
+ type descriptorable interface {
+ GetMessageDescriptor() *MessageDescriptor
+ }
+ if d, ok := message.(descriptorable); ok {
+ return d.GetMessageDescriptor(), nil
+ }
+
+ name := proto.MessageName(message)
+ if name == "" {
+ return nil, nil
+ }
+ m := getMessageFromCache(name)
+ if m != nil {
+ return m, nil
+ }
+
+ cacheMu.Lock()
+ defer cacheMu.Unlock()
+ return loadMessageDescriptorForTypeLocked(name, message.(protoMessage), nil)
+}
+
+func messageFromType(mt reflect.Type) (protoMessage, error) {
+ if mt.Kind() != reflect.Ptr {
+ mt = reflect.PtrTo(mt)
+ }
+ m, ok := reflect.Zero(mt).Interface().(protoMessage)
+ if !ok {
+ return nil, fmt.Errorf("failed to create message from type: %v", mt)
+ }
+ return m, nil
+}
+
+func loadMessageDescriptorForTypeLocked(name string, message protoMessage, r *ImportResolver) (*MessageDescriptor, error) {
+ m := messagesCache[name]
+ if m != nil {
+ return m, nil
+ }
+
+ fdb, _ := message.Descriptor()
+ fd, err := internal.DecodeFileDescriptor(name, fdb)
+ if err != nil {
+ return nil, err
+ }
+
+ f, err := toFileDescriptorLocked(fd, r)
+ if err != nil {
+ return nil, err
+ }
+ putCacheLocked(fd.GetName(), f)
+ return f.FindSymbol(name).(*MessageDescriptor), nil
+}
+
+func getMessageFromCache(message string) *MessageDescriptor {
+ cacheMu.RLock()
+ defer cacheMu.RUnlock()
+ return messagesCache[message]
+}
+
+// interface implemented by all generated enums
+type protoEnum interface {
+ EnumDescriptor() ([]byte, []int)
+}
+
+// NB: There is no LoadEnumDescriptor that takes a fully-qualified enum name because
+// it is not useful since protoc-gen-go does not expose the name anywhere in generated
+// code or register it in a way that is it accessible for reflection code. This also
+// means we have to cache enum descriptors differently -- we can only cache them as
+// they are requested, as opposed to caching all enum types whenever a file descriptor
+// is cached. This is because we need to know the generated type of the enums, and we
+// don't know that at the time of caching file descriptors.
+
+// LoadEnumDescriptorForType loads descriptor using the encoded descriptor proto returned
+// by enum.EnumDescriptor() for the given enum type.
+func LoadEnumDescriptorForType(enumType reflect.Type) (*EnumDescriptor, error) {
+ return loadEnumDescriptorForType(enumType, nil)
+}
+
+func loadEnumDescriptorForType(enumType reflect.Type, r *ImportResolver) (*EnumDescriptor, error) {
+ // we cache descriptors using non-pointer type
+ if enumType.Kind() == reflect.Ptr {
+ enumType = enumType.Elem()
+ }
+ e := getEnumFromCache(enumType)
+ if e != nil {
+ return e, nil
+ }
+ enum, err := enumFromType(enumType)
+ if err != nil {
+ return nil, err
+ }
+
+ cacheMu.Lock()
+ defer cacheMu.Unlock()
+ return loadEnumDescriptorForTypeLocked(enumType, enum, r)
+}
+
+// LoadEnumDescriptorForEnum loads descriptor using the encoded descriptor proto
+// returned by enum.EnumDescriptor().
+func LoadEnumDescriptorForEnum(enum protoEnum) (*EnumDescriptor, error) {
+ return loadEnumDescriptorForEnum(enum, nil)
+}
+
+func loadEnumDescriptorForEnum(enum protoEnum, r *ImportResolver) (*EnumDescriptor, error) {
+ et := reflect.TypeOf(enum)
+ // we cache descriptors using non-pointer type
+ if et.Kind() == reflect.Ptr {
+ et = et.Elem()
+ enum = reflect.Zero(et).Interface().(protoEnum)
+ }
+ e := getEnumFromCache(et)
+ if e != nil {
+ return e, nil
+ }
+
+ cacheMu.Lock()
+ defer cacheMu.Unlock()
+ return loadEnumDescriptorForTypeLocked(et, enum, r)
+}
+
+func enumFromType(et reflect.Type) (protoEnum, error) {
+ if et.Kind() != reflect.Int32 {
+ et = reflect.PtrTo(et)
+ }
+ e, ok := reflect.Zero(et).Interface().(protoEnum)
+ if !ok {
+ return nil, fmt.Errorf("failed to create enum from type: %v", et)
+ }
+ return e, nil
+}
+
+func loadEnumDescriptorForTypeLocked(et reflect.Type, enum protoEnum, r *ImportResolver) (*EnumDescriptor, error) {
+ e := enumCache[et]
+ if e != nil {
+ return e, nil
+ }
+
+ fdb, path := enum.EnumDescriptor()
+ name := fmt.Sprintf("%v", et)
+ fd, err := internal.DecodeFileDescriptor(name, fdb)
+ if err != nil {
+ return nil, err
+ }
+ // see if we already have cached "rich" descriptor
+ f, ok := filesCache[fd.GetName()]
+ if !ok {
+ f, err = toFileDescriptorLocked(fd, r)
+ if err != nil {
+ return nil, err
+ }
+ putCacheLocked(fd.GetName(), f)
+ }
+
+ ed := findEnum(f, path)
+ enumCache[et] = ed
+ return ed, nil
+}
+
+func getEnumFromCache(et reflect.Type) *EnumDescriptor {
+ cacheMu.RLock()
+ defer cacheMu.RUnlock()
+ return enumCache[et]
+}
+
+func findEnum(fd *FileDescriptor, path []int) *EnumDescriptor {
+ if len(path) == 1 {
+ return fd.GetEnumTypes()[path[0]]
+ }
+ md := fd.GetMessageTypes()[path[0]]
+ for _, i := range path[1 : len(path)-1] {
+ md = md.GetNestedMessageTypes()[i]
+ }
+ return md.GetNestedEnumTypes()[path[len(path)-1]]
+}
+
+// LoadFieldDescriptorForExtension loads the field descriptor that corresponds to the given
+// extension description.
+func LoadFieldDescriptorForExtension(ext *proto.ExtensionDesc) (*FieldDescriptor, error) {
+ return loadFieldDescriptorForExtension(ext, nil)
+}
+
+func loadFieldDescriptorForExtension(ext *proto.ExtensionDesc, r *ImportResolver) (*FieldDescriptor, error) {
+ file, err := loadFileDescriptor(ext.Filename, r)
+ if err != nil {
+ return nil, err
+ }
+ field, ok := file.FindSymbol(ext.Name).(*FieldDescriptor)
+ // make sure descriptor agrees with attributes of the ExtensionDesc
+ if !ok || !field.IsExtension() || field.GetOwner().GetFullyQualifiedName() != proto.MessageName(ext.ExtendedType) ||
+ field.GetNumber() != ext.Field {
+ return nil, fmt.Errorf("file descriptor contained unexpected object with name %s", ext.Name)
+ }
+ return field, nil
+}