8 |
8 |
9 import ( |
9 import ( |
10 "reflect" |
10 "reflect" |
11 |
11 |
12 "google.golang.org/protobuf/internal/descopts" |
12 "google.golang.org/protobuf/internal/descopts" |
13 fdesc "google.golang.org/protobuf/internal/filedesc" |
13 "google.golang.org/protobuf/internal/filedesc" |
14 pimpl "google.golang.org/protobuf/internal/impl" |
14 pimpl "google.golang.org/protobuf/internal/impl" |
15 pref "google.golang.org/protobuf/reflect/protoreflect" |
15 "google.golang.org/protobuf/reflect/protoreflect" |
16 preg "google.golang.org/protobuf/reflect/protoregistry" |
16 "google.golang.org/protobuf/reflect/protoregistry" |
17 ) |
17 ) |
18 |
18 |
19 // Builder constructs type descriptors from a raw file descriptor |
19 // Builder constructs type descriptors from a raw file descriptor |
20 // and associated Go types for each enum and message declaration. |
20 // and associated Go types for each enum and message declaration. |
21 // |
21 // |
22 // |
22 // # Flattened Ordering |
23 // Flattened Ordering |
|
24 // |
23 // |
25 // The protobuf type system represents declarations as a tree. Certain nodes in |
24 // The protobuf type system represents declarations as a tree. Certain nodes in |
26 // the tree require us to either associate it with a concrete Go type or to |
25 // the tree require us to either associate it with a concrete Go type or to |
27 // resolve a dependency, which is information that must be provided separately |
26 // resolve a dependency, which is information that must be provided separately |
28 // since it cannot be derived from the file descriptor alone. |
27 // since it cannot be derived from the file descriptor alone. |
50 // The traversal starts at the root file descriptor and yields each direct |
49 // The traversal starts at the root file descriptor and yields each direct |
51 // declaration within each node before traversing into sub-declarations |
50 // declaration within each node before traversing into sub-declarations |
52 // that children themselves may have. |
51 // that children themselves may have. |
53 type Builder struct { |
52 type Builder struct { |
54 // File is the underlying file descriptor builder. |
53 // File is the underlying file descriptor builder. |
55 File fdesc.Builder |
54 File filedesc.Builder |
56 |
55 |
57 // GoTypes is a unique set of the Go types for all declarations and |
56 // GoTypes is a unique set of the Go types for all declarations and |
58 // dependencies. Each type is represented as a zero value of the Go type. |
57 // dependencies. Each type is represented as a zero value of the Go type. |
59 // |
58 // |
60 // Declarations are Go types generated for enums and messages directly |
59 // Declarations are Go types generated for enums and messages directly |
106 ExtensionInfos []pimpl.ExtensionInfo |
105 ExtensionInfos []pimpl.ExtensionInfo |
107 |
106 |
108 // TypeRegistry is the registry to register each type descriptor. |
107 // TypeRegistry is the registry to register each type descriptor. |
109 // If nil, it uses protoregistry.GlobalTypes. |
108 // If nil, it uses protoregistry.GlobalTypes. |
110 TypeRegistry interface { |
109 TypeRegistry interface { |
111 RegisterMessage(pref.MessageType) error |
110 RegisterMessage(protoreflect.MessageType) error |
112 RegisterEnum(pref.EnumType) error |
111 RegisterEnum(protoreflect.EnumType) error |
113 RegisterExtension(pref.ExtensionType) error |
112 RegisterExtension(protoreflect.ExtensionType) error |
114 } |
113 } |
115 } |
114 } |
116 |
115 |
117 // Out is the output of the builder. |
116 // Out is the output of the builder. |
118 type Out struct { |
117 type Out struct { |
119 File pref.FileDescriptor |
118 File protoreflect.FileDescriptor |
120 } |
119 } |
121 |
120 |
122 func (tb Builder) Build() (out Out) { |
121 func (tb Builder) Build() (out Out) { |
123 // Replace the resolver with one that resolves dependencies by index, |
122 // Replace the resolver with one that resolves dependencies by index, |
124 // which is faster and more reliable than relying on the global registry. |
123 // which is faster and more reliable than relying on the global registry. |
125 if tb.File.FileRegistry == nil { |
124 if tb.File.FileRegistry == nil { |
126 tb.File.FileRegistry = preg.GlobalFiles |
125 tb.File.FileRegistry = protoregistry.GlobalFiles |
127 } |
126 } |
128 tb.File.FileRegistry = &resolverByIndex{ |
127 tb.File.FileRegistry = &resolverByIndex{ |
129 goTypes: tb.GoTypes, |
128 goTypes: tb.GoTypes, |
130 depIdxs: tb.DependencyIndexes, |
129 depIdxs: tb.DependencyIndexes, |
131 fileRegistry: tb.File.FileRegistry, |
130 fileRegistry: tb.File.FileRegistry, |
132 } |
131 } |
133 |
132 |
134 // Initialize registry if unpopulated. |
133 // Initialize registry if unpopulated. |
135 if tb.TypeRegistry == nil { |
134 if tb.TypeRegistry == nil { |
136 tb.TypeRegistry = preg.GlobalTypes |
135 tb.TypeRegistry = protoregistry.GlobalTypes |
137 } |
136 } |
138 |
137 |
139 fbOut := tb.File.Build() |
138 fbOut := tb.File.Build() |
140 out.File = fbOut.File |
139 out.File = fbOut.File |
141 |
140 |
181 // locally register concrete message type for the options. |
180 // locally register concrete message type for the options. |
182 if out.File.Path() == "google/protobuf/descriptor.proto" && out.File.Package() == "google.protobuf" { |
181 if out.File.Path() == "google/protobuf/descriptor.proto" && out.File.Package() == "google.protobuf" { |
183 for i := range fbOut.Messages { |
182 for i := range fbOut.Messages { |
184 switch fbOut.Messages[i].Name() { |
183 switch fbOut.Messages[i].Name() { |
185 case "FileOptions": |
184 case "FileOptions": |
186 descopts.File = messageGoTypes[i].(pref.ProtoMessage) |
185 descopts.File = messageGoTypes[i].(protoreflect.ProtoMessage) |
187 case "EnumOptions": |
186 case "EnumOptions": |
188 descopts.Enum = messageGoTypes[i].(pref.ProtoMessage) |
187 descopts.Enum = messageGoTypes[i].(protoreflect.ProtoMessage) |
189 case "EnumValueOptions": |
188 case "EnumValueOptions": |
190 descopts.EnumValue = messageGoTypes[i].(pref.ProtoMessage) |
189 descopts.EnumValue = messageGoTypes[i].(protoreflect.ProtoMessage) |
191 case "MessageOptions": |
190 case "MessageOptions": |
192 descopts.Message = messageGoTypes[i].(pref.ProtoMessage) |
191 descopts.Message = messageGoTypes[i].(protoreflect.ProtoMessage) |
193 case "FieldOptions": |
192 case "FieldOptions": |
194 descopts.Field = messageGoTypes[i].(pref.ProtoMessage) |
193 descopts.Field = messageGoTypes[i].(protoreflect.ProtoMessage) |
195 case "OneofOptions": |
194 case "OneofOptions": |
196 descopts.Oneof = messageGoTypes[i].(pref.ProtoMessage) |
195 descopts.Oneof = messageGoTypes[i].(protoreflect.ProtoMessage) |
197 case "ExtensionRangeOptions": |
196 case "ExtensionRangeOptions": |
198 descopts.ExtensionRange = messageGoTypes[i].(pref.ProtoMessage) |
197 descopts.ExtensionRange = messageGoTypes[i].(protoreflect.ProtoMessage) |
199 case "ServiceOptions": |
198 case "ServiceOptions": |
200 descopts.Service = messageGoTypes[i].(pref.ProtoMessage) |
199 descopts.Service = messageGoTypes[i].(protoreflect.ProtoMessage) |
201 case "MethodOptions": |
200 case "MethodOptions": |
202 descopts.Method = messageGoTypes[i].(pref.ProtoMessage) |
201 descopts.Method = messageGoTypes[i].(protoreflect.ProtoMessage) |
203 } |
202 } |
204 } |
203 } |
205 } |
204 } |
206 } |
205 } |
207 |
206 |
214 // For enum and message kinds, determine the referent Go type so |
213 // For enum and message kinds, determine the referent Go type so |
215 // that we can construct their constructors. |
214 // that we can construct their constructors. |
216 const listExtDeps = 2 |
215 const listExtDeps = 2 |
217 var goType reflect.Type |
216 var goType reflect.Type |
218 switch fbOut.Extensions[i].L1.Kind { |
217 switch fbOut.Extensions[i].L1.Kind { |
219 case pref.EnumKind: |
218 case protoreflect.EnumKind: |
220 j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx) |
219 j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx) |
221 goType = reflect.TypeOf(tb.GoTypes[j]) |
220 goType = reflect.TypeOf(tb.GoTypes[j]) |
222 depIdx++ |
221 depIdx++ |
223 case pref.MessageKind, pref.GroupKind: |
222 case protoreflect.MessageKind, protoreflect.GroupKind: |
224 j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx) |
223 j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx) |
225 goType = reflect.TypeOf(tb.GoTypes[j]) |
224 goType = reflect.TypeOf(tb.GoTypes[j]) |
226 depIdx++ |
225 depIdx++ |
227 default: |
226 default: |
228 goType = goTypeForPBKind[fbOut.Extensions[i].L1.Kind] |
227 goType = goTypeForPBKind[fbOut.Extensions[i].L1.Kind] |
240 } |
239 } |
241 |
240 |
242 return out |
241 return out |
243 } |
242 } |
244 |
243 |
245 var goTypeForPBKind = map[pref.Kind]reflect.Type{ |
244 var goTypeForPBKind = map[protoreflect.Kind]reflect.Type{ |
246 pref.BoolKind: reflect.TypeOf(bool(false)), |
245 protoreflect.BoolKind: reflect.TypeOf(bool(false)), |
247 pref.Int32Kind: reflect.TypeOf(int32(0)), |
246 protoreflect.Int32Kind: reflect.TypeOf(int32(0)), |
248 pref.Sint32Kind: reflect.TypeOf(int32(0)), |
247 protoreflect.Sint32Kind: reflect.TypeOf(int32(0)), |
249 pref.Sfixed32Kind: reflect.TypeOf(int32(0)), |
248 protoreflect.Sfixed32Kind: reflect.TypeOf(int32(0)), |
250 pref.Int64Kind: reflect.TypeOf(int64(0)), |
249 protoreflect.Int64Kind: reflect.TypeOf(int64(0)), |
251 pref.Sint64Kind: reflect.TypeOf(int64(0)), |
250 protoreflect.Sint64Kind: reflect.TypeOf(int64(0)), |
252 pref.Sfixed64Kind: reflect.TypeOf(int64(0)), |
251 protoreflect.Sfixed64Kind: reflect.TypeOf(int64(0)), |
253 pref.Uint32Kind: reflect.TypeOf(uint32(0)), |
252 protoreflect.Uint32Kind: reflect.TypeOf(uint32(0)), |
254 pref.Fixed32Kind: reflect.TypeOf(uint32(0)), |
253 protoreflect.Fixed32Kind: reflect.TypeOf(uint32(0)), |
255 pref.Uint64Kind: reflect.TypeOf(uint64(0)), |
254 protoreflect.Uint64Kind: reflect.TypeOf(uint64(0)), |
256 pref.Fixed64Kind: reflect.TypeOf(uint64(0)), |
255 protoreflect.Fixed64Kind: reflect.TypeOf(uint64(0)), |
257 pref.FloatKind: reflect.TypeOf(float32(0)), |
256 protoreflect.FloatKind: reflect.TypeOf(float32(0)), |
258 pref.DoubleKind: reflect.TypeOf(float64(0)), |
257 protoreflect.DoubleKind: reflect.TypeOf(float64(0)), |
259 pref.StringKind: reflect.TypeOf(string("")), |
258 protoreflect.StringKind: reflect.TypeOf(string("")), |
260 pref.BytesKind: reflect.TypeOf([]byte(nil)), |
259 protoreflect.BytesKind: reflect.TypeOf([]byte(nil)), |
261 } |
260 } |
262 |
261 |
263 type depIdxs []int32 |
262 type depIdxs []int32 |
264 |
263 |
265 // Get retrieves the jth element of the ith sub-list. |
264 // Get retrieves the jth element of the ith sub-list. |
272 goTypes []interface{} |
271 goTypes []interface{} |
273 depIdxs depIdxs |
272 depIdxs depIdxs |
274 fileRegistry |
273 fileRegistry |
275 } |
274 } |
276 fileRegistry interface { |
275 fileRegistry interface { |
277 FindFileByPath(string) (pref.FileDescriptor, error) |
276 FindFileByPath(string) (protoreflect.FileDescriptor, error) |
278 FindDescriptorByName(pref.FullName) (pref.Descriptor, error) |
277 FindDescriptorByName(protoreflect.FullName) (protoreflect.Descriptor, error) |
279 RegisterFile(pref.FileDescriptor) error |
278 RegisterFile(protoreflect.FileDescriptor) error |
280 } |
279 } |
281 ) |
280 ) |
282 |
281 |
283 func (r *resolverByIndex) FindEnumByIndex(i, j int32, es []fdesc.Enum, ms []fdesc.Message) pref.EnumDescriptor { |
282 func (r *resolverByIndex) FindEnumByIndex(i, j int32, es []filedesc.Enum, ms []filedesc.Message) protoreflect.EnumDescriptor { |
284 if depIdx := int(r.depIdxs.Get(i, j)); int(depIdx) < len(es)+len(ms) { |
283 if depIdx := int(r.depIdxs.Get(i, j)); int(depIdx) < len(es)+len(ms) { |
285 return &es[depIdx] |
284 return &es[depIdx] |
286 } else { |
285 } else { |
287 return pimpl.Export{}.EnumDescriptorOf(r.goTypes[depIdx]) |
286 return pimpl.Export{}.EnumDescriptorOf(r.goTypes[depIdx]) |
288 } |
287 } |
289 } |
288 } |
290 |
289 |
291 func (r *resolverByIndex) FindMessageByIndex(i, j int32, es []fdesc.Enum, ms []fdesc.Message) pref.MessageDescriptor { |
290 func (r *resolverByIndex) FindMessageByIndex(i, j int32, es []filedesc.Enum, ms []filedesc.Message) protoreflect.MessageDescriptor { |
292 if depIdx := int(r.depIdxs.Get(i, j)); depIdx < len(es)+len(ms) { |
291 if depIdx := int(r.depIdxs.Get(i, j)); depIdx < len(es)+len(ms) { |
293 return &ms[depIdx-len(es)] |
292 return &ms[depIdx-len(es)] |
294 } else { |
293 } else { |
295 return pimpl.Export{}.MessageDescriptorOf(r.goTypes[depIdx]) |
294 return pimpl.Export{}.MessageDescriptorOf(r.goTypes[depIdx]) |
296 } |
295 } |