blob: 7cac1c19016f9c4cd6c51ece7939a081aa2eda18 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301// 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.
9package filedesc
10
11import (
12 "google.golang.org/protobuf/encoding/protowire"
13 "google.golang.org/protobuf/internal/genid"
14 "google.golang.org/protobuf/reflect/protoreflect"
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053015 "google.golang.org/protobuf/reflect/protoregistry"
Naveen Sampath04696f72022-06-13 15:19:14 +053016)
17
18// Builder construct a protoreflect.FileDescriptor from the raw descriptor.
19type 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 {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053040 protoregistry.ExtensionTypeResolver
Naveen Sampath04696f72022-06-13 15:19:14 +053041 }
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)
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053048 FindDescriptorByName(protoreflect.FullName) (protoreflect.Descriptor, error)
49 RegisterFile(protoreflect.FileDescriptor) error
Naveen Sampath04696f72022-06-13 15:19:14 +053050 }
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.
56type resolverByIndex interface {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053057 FindEnumByIndex(int32, int32, []Enum, []Message) protoreflect.EnumDescriptor
58 FindMessageByIndex(int32, int32, []Enum, []Message) protoreflect.MessageDescriptor
Naveen Sampath04696f72022-06-13 15:19:14 +053059}
60
61// Indexes of each sub-list in filetype.Builder.DependencyIndexes.
62const (
63 listFieldDeps int32 = iota
64 listExtTargets
65 listExtDeps
66 listMethInDeps
67 listMethOutDeps
68)
69
70// Out is the output of the Builder.
71type Out struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053072 File protoreflect.FileDescriptor
Naveen Sampath04696f72022-06-13 15:19:14 +053073
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.
91func (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 {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053099 db.TypeResolver = protoregistry.GlobalTypes
Naveen Sampath04696f72022-06-13 15:19:14 +0530100 }
101 if db.FileRegistry == nil {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530102 db.FileRegistry = protoregistry.GlobalFiles
Naveen Sampath04696f72022-06-13 15:19:14 +0530103 }
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.
121func (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}