vendor/google.golang.org/protobuf/internal/filedesc/build.go
changeset 256 6d9efbef00a9
child 260 445e01aede7e
equal deleted inserted replaced
255:4f153a23adab 256:6d9efbef00a9
       
     1 // Copyright 2019 The Go Authors. All rights reserved.
       
     2 // Use of this source code is governed by a BSD-style
       
     3 // license that can be found in the LICENSE file.
       
     4 
       
     5 // Package filedesc provides functionality for constructing descriptors.
       
     6 //
       
     7 // The types in this package implement interfaces in the protoreflect package
       
     8 // related to protobuf descripriptors.
       
     9 package filedesc
       
    10 
       
    11 import (
       
    12 	"google.golang.org/protobuf/encoding/protowire"
       
    13 	"google.golang.org/protobuf/internal/genid"
       
    14 	"google.golang.org/protobuf/reflect/protoreflect"
       
    15 	pref "google.golang.org/protobuf/reflect/protoreflect"
       
    16 	preg "google.golang.org/protobuf/reflect/protoregistry"
       
    17 )
       
    18 
       
    19 // Builder construct a protoreflect.FileDescriptor from the raw descriptor.
       
    20 type Builder struct {
       
    21 	// GoPackagePath is the Go package path that is invoking this builder.
       
    22 	GoPackagePath string
       
    23 
       
    24 	// RawDescriptor is the wire-encoded bytes of FileDescriptorProto
       
    25 	// and must be populated.
       
    26 	RawDescriptor []byte
       
    27 
       
    28 	// NumEnums is the total number of enums declared in the file.
       
    29 	NumEnums int32
       
    30 	// NumMessages is the total number of messages declared in the file.
       
    31 	// It includes the implicit message declarations for map entries.
       
    32 	NumMessages int32
       
    33 	// NumExtensions is the total number of extensions declared in the file.
       
    34 	NumExtensions int32
       
    35 	// NumServices is the total number of services declared in the file.
       
    36 	NumServices int32
       
    37 
       
    38 	// TypeResolver resolves extension field types for descriptor options.
       
    39 	// If nil, it uses protoregistry.GlobalTypes.
       
    40 	TypeResolver interface {
       
    41 		preg.ExtensionTypeResolver
       
    42 	}
       
    43 
       
    44 	// FileRegistry is use to lookup file, enum, and message dependencies.
       
    45 	// Once constructed, the file descriptor is registered here.
       
    46 	// If nil, it uses protoregistry.GlobalFiles.
       
    47 	FileRegistry interface {
       
    48 		FindFileByPath(string) (protoreflect.FileDescriptor, error)
       
    49 		FindDescriptorByName(pref.FullName) (pref.Descriptor, error)
       
    50 		RegisterFile(pref.FileDescriptor) error
       
    51 	}
       
    52 }
       
    53 
       
    54 // resolverByIndex is an interface Builder.FileRegistry may implement.
       
    55 // If so, it permits looking up an enum or message dependency based on the
       
    56 // sub-list and element index into filetype.Builder.DependencyIndexes.
       
    57 type resolverByIndex interface {
       
    58 	FindEnumByIndex(int32, int32, []Enum, []Message) pref.EnumDescriptor
       
    59 	FindMessageByIndex(int32, int32, []Enum, []Message) pref.MessageDescriptor
       
    60 }
       
    61 
       
    62 // Indexes of each sub-list in filetype.Builder.DependencyIndexes.
       
    63 const (
       
    64 	listFieldDeps int32 = iota
       
    65 	listExtTargets
       
    66 	listExtDeps
       
    67 	listMethInDeps
       
    68 	listMethOutDeps
       
    69 )
       
    70 
       
    71 // Out is the output of the Builder.
       
    72 type Out struct {
       
    73 	File pref.FileDescriptor
       
    74 
       
    75 	// Enums is all enum descriptors in "flattened ordering".
       
    76 	Enums []Enum
       
    77 	// Messages is all message descriptors in "flattened ordering".
       
    78 	// It includes the implicit message declarations for map entries.
       
    79 	Messages []Message
       
    80 	// Extensions is all extension descriptors in "flattened ordering".
       
    81 	Extensions []Extension
       
    82 	// Service is all service descriptors in "flattened ordering".
       
    83 	Services []Service
       
    84 }
       
    85 
       
    86 // Build constructs a FileDescriptor given the parameters set in Builder.
       
    87 // It assumes that the inputs are well-formed and panics if any inconsistencies
       
    88 // are encountered.
       
    89 //
       
    90 // If NumEnums+NumMessages+NumExtensions+NumServices is zero,
       
    91 // then Build automatically derives them from the raw descriptor.
       
    92 func (db Builder) Build() (out Out) {
       
    93 	// Populate the counts if uninitialized.
       
    94 	if db.NumEnums+db.NumMessages+db.NumExtensions+db.NumServices == 0 {
       
    95 		db.unmarshalCounts(db.RawDescriptor, true)
       
    96 	}
       
    97 
       
    98 	// Initialize resolvers and registries if unpopulated.
       
    99 	if db.TypeResolver == nil {
       
   100 		db.TypeResolver = preg.GlobalTypes
       
   101 	}
       
   102 	if db.FileRegistry == nil {
       
   103 		db.FileRegistry = preg.GlobalFiles
       
   104 	}
       
   105 
       
   106 	fd := newRawFile(db)
       
   107 	out.File = fd
       
   108 	out.Enums = fd.allEnums
       
   109 	out.Messages = fd.allMessages
       
   110 	out.Extensions = fd.allExtensions
       
   111 	out.Services = fd.allServices
       
   112 
       
   113 	if err := db.FileRegistry.RegisterFile(fd); err != nil {
       
   114 		panic(err)
       
   115 	}
       
   116 	return out
       
   117 }
       
   118 
       
   119 // unmarshalCounts counts the number of enum, message, extension, and service
       
   120 // declarations in the raw message, which is either a FileDescriptorProto
       
   121 // or a MessageDescriptorProto depending on whether isFile is set.
       
   122 func (db *Builder) unmarshalCounts(b []byte, isFile bool) {
       
   123 	for len(b) > 0 {
       
   124 		num, typ, n := protowire.ConsumeTag(b)
       
   125 		b = b[n:]
       
   126 		switch typ {
       
   127 		case protowire.BytesType:
       
   128 			v, m := protowire.ConsumeBytes(b)
       
   129 			b = b[m:]
       
   130 			if isFile {
       
   131 				switch num {
       
   132 				case genid.FileDescriptorProto_EnumType_field_number:
       
   133 					db.NumEnums++
       
   134 				case genid.FileDescriptorProto_MessageType_field_number:
       
   135 					db.unmarshalCounts(v, false)
       
   136 					db.NumMessages++
       
   137 				case genid.FileDescriptorProto_Extension_field_number:
       
   138 					db.NumExtensions++
       
   139 				case genid.FileDescriptorProto_Service_field_number:
       
   140 					db.NumServices++
       
   141 				}
       
   142 			} else {
       
   143 				switch num {
       
   144 				case genid.DescriptorProto_EnumType_field_number:
       
   145 					db.NumEnums++
       
   146 				case genid.DescriptorProto_NestedType_field_number:
       
   147 					db.unmarshalCounts(v, false)
       
   148 					db.NumMessages++
       
   149 				case genid.DescriptorProto_Extension_field_number:
       
   150 					db.NumExtensions++
       
   151 				}
       
   152 			}
       
   153 		default:
       
   154 			m := protowire.ConsumeFieldValue(num, typ, b)
       
   155 			b = b[m:]
       
   156 		}
       
   157 	}
       
   158 }