|
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 } |