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