...

Source file src/google.golang.org/protobuf/internal/filedesc/build.go

Documentation: google.golang.org/protobuf/internal/filedesc

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

View as plain text