blob: 8c49f3cdf9dd8f3aa76bce3f480f7602ca0edfdf [file] [log] [blame]
Damien Neil8012b442019-01-18 09:32:24 -08001// Copyright 2018 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 fileinit constructs protoreflect.FileDescriptors from the encoded
6// file descriptor proto messages. This package uses a custom proto unmarshaler
7// 1) to avoid a dependency on the descriptor proto 2) for performance to keep
8// the initialization cost as low as possible.
9package fileinit
10
11import (
12 "fmt"
13 "reflect"
14 "sync"
15
16 pragma "github.com/golang/protobuf/v2/internal/pragma"
Joe Tsai990b9f52019-03-13 12:56:39 -070017 ptype "github.com/golang/protobuf/v2/internal/prototype"
Damien Neil8012b442019-01-18 09:32:24 -080018 pfmt "github.com/golang/protobuf/v2/internal/typefmt"
19 "github.com/golang/protobuf/v2/proto"
20 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Damien Neil8012b442019-01-18 09:32:24 -080021)
22
23// FileBuilder construct a protoreflect.FileDescriptor from the
24// raw file descriptor and the Go types for declarations and dependencies.
25//
26//
27// Flattened Ordering
28//
29// The protobuf type system represents declarations as a tree. Certain nodes in
30// the tree require us to either associate it with a concrete Go type or to
31// resolve a dependency, which is information that must be provided separately
32// since it cannot be derived from the file descriptor alone.
33//
34// However, representing a tree as Go literals is difficult to simply do in a
35// space and time efficient way. Thus, we store them as a flattened list of
36// objects where the serialization order from the tree-based form is important.
37//
38// The "flattened ordering" is defined as a tree traversal of all enum, message,
39// extension, and service declarations using the following algorithm:
40//
41// def VisitFileDecls(fd):
42// for e in fd.Enums: yield e
43// for m in fd.Messages: yield m
44// for x in fd.Extensions: yield x
45// for s in fd.Services: yield s
46// for m in fd.Messages: yield from VisitMessageDecls(m)
47//
48// def VisitMessageDecls(md):
49// for e in md.Enums: yield e
50// for m in md.Messages: yield m
51// for x in md.Extensions: yield x
52// for m in md.Messages: yield from VisitMessageDecls(m)
53//
54// The traversal starts at the root file descriptor and yields each direct
55// declaration within each node before traversing into sub-declarations
56// that children themselves may have.
57type FileBuilder struct {
58 // RawDescriptor is the wire-encoded bytes of FileDescriptorProto.
59 RawDescriptor []byte
60
61 // GoTypes is a unique set of the Go types for all declarations and
62 // dependencies. Each type is represented as a zero value of the Go type.
63 //
64 // Declarations are Go types generated for enums and messages directly
65 // declared (not publicly imported) in the proto source file.
66 // Messages for map entries are included, but represented by nil.
67 // Enum declarations in "flattened ordering" come first, followed by
68 // message declarations in "flattened ordering". The length of each sub-list
69 // is len(EnumOutputTypes) and len(MessageOutputTypes), respectively.
70 //
71 // Dependencies are Go types for enums or messages referenced by
72 // message fields (excluding weak fields), for parent extended messages of
73 // extension fields, for enums or messages referenced by extension fields,
74 // and for input and output messages referenced by service methods.
75 // Dependencies must come after declarations, but the ordering of
76 // dependencies themselves is unspecified.
77 GoTypes []interface{}
78
79 // DependencyIndexes is an ordered list of indexes into GoTypes for the
80 // dependencies of messages, extensions, or services. There are 4 sub-lists
81 // each in "flattened ordering" concatenated back-to-back:
82 // * Extension field targets: list of the extended parent message of
83 // every extension. Length is len(ExtensionOutputTypes).
84 // * Message field dependencies: list of the enum or message type
85 // referred to by every message field.
86 // * Extension field dependencies: list of the enum or message type
87 // referred to by every extension field.
88 // * Service method dependencies: list of the input and output message type
89 // referred to by every service method.
90 DependencyIndexes []int32
91
92 // TODO: Provide a list of imported files.
93 // FileDependencies []pref.FileDescriptor
94
95 // TODO: Provide a list of extension types for options extensions.
96 // OptionDependencies []pref.ExtensionType
97
98 // EnumOutputTypes is where Init stores all initialized enum types
99 // in "flattened ordering".
100 EnumOutputTypes []pref.EnumType
101 // MessageOutputTypes is where Init stores all initialized message types
102 // in "flattened ordering"; this includes map entry types.
103 MessageOutputTypes []pref.MessageType
104 // ExtensionOutputTypes is where Init stores all initialized extension types
105 // in "flattened ordering".
106 ExtensionOutputTypes []pref.ExtensionType
107
108 // TODO: Provide ability for FileBuilder to handle registration?
109 // FilesRegistry *pref.Files
110 // TypesRegistry *pref.Types
111}
112
113// Init constructs a FileDescriptor given the parameters set in FileBuilder.
114// It assumes that the inputs are well-formed and panics if any inconsistencies
115// are encountered.
116func (fb FileBuilder) Init() pref.FileDescriptor {
117 fd := newFileDesc(fb)
118
119 for i := range fd.allEnums {
120 fb.EnumOutputTypes[i] = &fd.allEnums[i]
121 }
122 for i := range fd.allMessages {
123 fb.MessageOutputTypes[i] = &fd.allMessages[i]
124 }
125 for i := range fd.allExtensions {
126 fb.ExtensionOutputTypes[i] = &fd.allExtensions[i]
127 }
128 return fd
129}
130
131type (
132 // fileInit contains a copy of certain fields in FileBuilder for use during
133 // lazy initialization upon first use.
134 fileInit struct {
135 RawDescriptor []byte
136 GoTypes []interface{}
137 DependencyIndexes []int32
138 }
139 fileDesc struct {
140 fileInit
141
142 path string
143 protoPackage pref.FullName
144
145 fileDecls
146
147 enums enumDescs
148 messages messageDescs
149 extensions extensionDescs
150 services serviceDescs
151
152 once sync.Once
153 lazy *fileLazy // protected by once
154 }
155 fileDecls struct {
156 allEnums []enumDesc
157 allMessages []messageDesc
158 allExtensions []extensionDesc
159 }
160 fileLazy struct {
161 syntax pref.Syntax
162 imports fileImports
163 byName map[pref.FullName]pref.Descriptor
164 options []byte
165 }
166)
167
168func (fd *fileDesc) Parent() (pref.Descriptor, bool) { return nil, false }
169func (fd *fileDesc) Index() int { return 0 }
170func (fd *fileDesc) Syntax() pref.Syntax { return fd.lazyInit().syntax }
171func (fd *fileDesc) Name() pref.Name { return fd.Package().Name() }
172func (fd *fileDesc) FullName() pref.FullName { return fd.Package() }
173func (fd *fileDesc) IsPlaceholder() bool { return false }
174func (fd *fileDesc) Options() pref.OptionsMessage {
175 return unmarshalOptions(ptype.X.FileOptions(), fd.lazyInit().options)
176}
177func (fd *fileDesc) Path() string { return fd.path }
178func (fd *fileDesc) Package() pref.FullName { return fd.protoPackage }
179func (fd *fileDesc) Imports() pref.FileImports { return &fd.lazyInit().imports }
180func (fd *fileDesc) Enums() pref.EnumDescriptors { return &fd.enums }
181func (fd *fileDesc) Messages() pref.MessageDescriptors { return &fd.messages }
182func (fd *fileDesc) Extensions() pref.ExtensionDescriptors { return &fd.extensions }
183func (fd *fileDesc) Services() pref.ServiceDescriptors { return &fd.services }
184func (fd *fileDesc) DescriptorByName(s pref.FullName) pref.Descriptor { return fd.lazyInit().byName[s] }
185func (fd *fileDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, fd) }
186func (fd *fileDesc) ProtoType(pref.FileDescriptor) {}
187func (fd *fileDesc) ProtoInternal(pragma.DoNotImplement) {}
188
189type (
190 enumDesc struct {
191 baseDesc
192
193 lazy *enumLazy // protected by fileDesc.once
194 }
195 enumLazy struct {
196 typ reflect.Type
197 new func(pref.EnumNumber) pref.Enum
198
199 values enumValueDescs
200 resvNames names
201 resvRanges enumRanges
202 options []byte
203 }
204 enumValueDesc struct {
205 baseDesc
206
207 number pref.EnumNumber
208 options []byte
209 }
210)
211
212func (ed *enumDesc) GoType() reflect.Type { return ed.lazyInit().typ }
213func (ed *enumDesc) New(n pref.EnumNumber) pref.Enum { return ed.lazyInit().new(n) }
214func (ed *enumDesc) Options() pref.OptionsMessage {
215 return unmarshalOptions(ptype.X.EnumOptions(), ed.lazyInit().options)
216}
217func (ed *enumDesc) Values() pref.EnumValueDescriptors { return &ed.lazyInit().values }
218func (ed *enumDesc) ReservedNames() pref.Names { return &ed.lazyInit().resvNames }
219func (ed *enumDesc) ReservedRanges() pref.EnumRanges { return &ed.lazyInit().resvRanges }
220func (ed *enumDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, ed) }
221func (ed *enumDesc) ProtoType(pref.EnumDescriptor) {}
222func (ed *enumDesc) lazyInit() *enumLazy {
223 ed.parentFile.lazyInit() // implicitly initializes enumLazy
224 return ed.lazy
225}
226
227func (ed *enumValueDesc) Options() pref.OptionsMessage {
228 return unmarshalOptions(ptype.X.EnumValueOptions(), ed.options)
229}
230func (ed *enumValueDesc) Number() pref.EnumNumber { return ed.number }
231func (ed *enumValueDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, ed) }
232func (ed *enumValueDesc) ProtoType(pref.EnumValueDescriptor) {}
233
234type (
235 messageDesc struct {
236 baseDesc
237
238 enums enumDescs
239 messages messageDescs
240 extensions extensionDescs
241
242 lazy *messageLazy // protected by fileDesc.once
243 }
244 messageLazy struct {
245 typ reflect.Type
246 new func() pref.Message
247
248 isMapEntry bool
249 fields fieldDescs
250 oneofs oneofDescs
251 resvNames names
252 resvRanges fieldRanges
253 reqNumbers fieldNumbers
254 extRanges fieldRanges
255 extRangeOptions [][]byte
256 options []byte
257 }
258 fieldDesc struct {
259 baseDesc
260
261 number pref.FieldNumber
262 cardinality pref.Cardinality
263 kind pref.Kind
264 hasJSONName bool
265 jsonName string
266 hasPacked bool
267 isPacked bool
268 isWeak bool
269 isMap bool
270 defVal defaultValue
271 oneofType pref.OneofDescriptor
272 enumType pref.EnumDescriptor
273 messageType pref.MessageDescriptor
274 options []byte
275 }
276 oneofDesc struct {
277 baseDesc
278
279 fields oneofFields
280 options []byte
281 }
282)
283
284func (md *messageDesc) GoType() reflect.Type { return md.lazyInit().typ }
285func (md *messageDesc) New() pref.Message { return md.lazyInit().new() }
286func (md *messageDesc) Options() pref.OptionsMessage {
287 return unmarshalOptions(ptype.X.MessageOptions(), md.lazyInit().options)
288}
289func (md *messageDesc) IsMapEntry() bool { return md.lazyInit().isMapEntry }
290func (md *messageDesc) Fields() pref.FieldDescriptors { return &md.lazyInit().fields }
291func (md *messageDesc) Oneofs() pref.OneofDescriptors { return &md.lazyInit().oneofs }
292func (md *messageDesc) ReservedNames() pref.Names { return &md.lazyInit().resvNames }
293func (md *messageDesc) ReservedRanges() pref.FieldRanges { return &md.lazyInit().resvRanges }
294func (md *messageDesc) RequiredNumbers() pref.FieldNumbers { return &md.lazyInit().reqNumbers }
295func (md *messageDesc) ExtensionRanges() pref.FieldRanges { return &md.lazyInit().extRanges }
296func (md *messageDesc) ExtensionRangeOptions(i int) pref.OptionsMessage {
297 return unmarshalOptions(ptype.X.ExtensionRangeOptions(), md.lazyInit().extRangeOptions[i])
298}
299func (md *messageDesc) Enums() pref.EnumDescriptors { return &md.enums }
300func (md *messageDesc) Messages() pref.MessageDescriptors { return &md.messages }
301func (md *messageDesc) Extensions() pref.ExtensionDescriptors { return &md.extensions }
302func (md *messageDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, md) }
303func (md *messageDesc) ProtoType(pref.MessageDescriptor) {}
304func (md *messageDesc) lazyInit() *messageLazy {
305 md.parentFile.lazyInit() // implicitly initializes messageLazy
306 return md.lazy
307}
308
309func (fd *fieldDesc) Options() pref.OptionsMessage {
310 return unmarshalOptions(ptype.X.FieldOptions(), fd.options)
311}
312func (fd *fieldDesc) Number() pref.FieldNumber { return fd.number }
313func (fd *fieldDesc) Cardinality() pref.Cardinality { return fd.cardinality }
314func (fd *fieldDesc) Kind() pref.Kind { return fd.kind }
315func (fd *fieldDesc) HasJSONName() bool { return fd.hasJSONName }
316func (fd *fieldDesc) JSONName() string { return fd.jsonName }
317func (fd *fieldDesc) IsPacked() bool { return fd.isPacked }
318func (fd *fieldDesc) IsWeak() bool { return fd.isWeak }
319func (fd *fieldDesc) IsMap() bool { return fd.isMap }
320func (fd *fieldDesc) HasDefault() bool { return fd.defVal.has }
321func (fd *fieldDesc) Default() pref.Value { return fd.defVal.get() }
322func (fd *fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return fd.defVal.enum }
323func (fd *fieldDesc) OneofType() pref.OneofDescriptor { return fd.oneofType }
324func (fd *fieldDesc) ExtendedType() pref.MessageDescriptor { return nil }
325func (fd *fieldDesc) EnumType() pref.EnumDescriptor { return fd.enumType }
326func (fd *fieldDesc) MessageType() pref.MessageDescriptor { return fd.messageType }
327func (fd *fieldDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, fd) }
328func (fd *fieldDesc) ProtoType(pref.FieldDescriptor) {}
329
330func (od *oneofDesc) Options() pref.OptionsMessage {
331 return unmarshalOptions(ptype.X.OneofOptions(), od.options)
332}
333func (od *oneofDesc) Fields() pref.FieldDescriptors { return &od.fields }
334func (od *oneofDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, od) }
335func (od *oneofDesc) ProtoType(pref.OneofDescriptor) {}
336
337type (
338 extensionDesc struct {
339 baseDesc
340
341 number pref.FieldNumber
342 extendedType pref.MessageDescriptor
343
344 lazy *extensionLazy // protected by fileDesc.once
345 }
346 extensionLazy struct {
347 typ reflect.Type
348 new func() pref.Value
349 valueOf func(interface{}) pref.Value
350 interfaceOf func(pref.Value) interface{}
351
352 cardinality pref.Cardinality
353 kind pref.Kind
354 // Extensions should not have JSON names, but older versions of protoc
355 // used to set one on the descriptor. Preserve it for now to maintain
356 // the property that protoc 3.6.1 descriptors can round-trip through
357 // this package losslessly.
358 //
359 // TODO: Consider whether to drop JSONName parsing from extensions.
360 hasJSONName bool
361 jsonName string
362 isPacked bool
363 defVal defaultValue
364 enumType pref.EnumType
365 messageType pref.MessageType
366 options []byte
367 }
368)
369
370func (xd *extensionDesc) GoType() reflect.Type { return xd.lazyInit().typ }
371func (xd *extensionDesc) New() pref.Value { return xd.lazyInit().new() }
372func (xd *extensionDesc) ValueOf(v interface{}) pref.Value { return xd.lazyInit().valueOf(v) }
373func (xd *extensionDesc) InterfaceOf(v pref.Value) interface{} { return xd.lazyInit().interfaceOf(v) }
374func (xd *extensionDesc) Options() pref.OptionsMessage {
375 return unmarshalOptions(ptype.X.FieldOptions(), xd.lazyInit().options)
376}
377func (xd *extensionDesc) Number() pref.FieldNumber { return xd.number }
378func (xd *extensionDesc) Cardinality() pref.Cardinality { return xd.lazyInit().cardinality }
379func (xd *extensionDesc) Kind() pref.Kind { return xd.lazyInit().kind }
380func (xd *extensionDesc) HasJSONName() bool { return xd.lazyInit().hasJSONName }
381func (xd *extensionDesc) JSONName() string { return xd.lazyInit().jsonName }
382func (xd *extensionDesc) IsPacked() bool { return xd.lazyInit().isPacked }
383func (xd *extensionDesc) IsWeak() bool { return false }
384func (xd *extensionDesc) IsMap() bool { return false }
385func (xd *extensionDesc) HasDefault() bool { return xd.lazyInit().defVal.has }
386func (xd *extensionDesc) Default() pref.Value { return xd.lazyInit().defVal.get() }
387func (xd *extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().defVal.enum }
388func (xd *extensionDesc) OneofType() pref.OneofDescriptor { return nil }
389func (xd *extensionDesc) ExtendedType() pref.MessageDescriptor { return xd.extendedType }
390func (xd *extensionDesc) EnumType() pref.EnumDescriptor { return xd.lazyInit().enumType }
391func (xd *extensionDesc) MessageType() pref.MessageDescriptor { return xd.lazyInit().messageType }
392func (xd *extensionDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, xd) }
393func (xd *extensionDesc) ProtoType(pref.FieldDescriptor) {}
394func (xd *extensionDesc) ProtoInternal(pragma.DoNotImplement) {}
395func (xd *extensionDesc) lazyInit() *extensionLazy {
396 xd.parentFile.lazyInit() // implicitly initializes extensionLazy
397 return xd.lazy
398}
399
400type (
401 serviceDesc struct {
402 baseDesc
403
404 lazy *serviceLazy // protected by fileDesc.once
405 }
406 serviceLazy struct {
407 methods methodDescs
408 options []byte
409 }
410 methodDesc struct {
411 baseDesc
412
413 inputType pref.MessageDescriptor
414 outputType pref.MessageDescriptor
415 isStreamingClient bool
416 isStreamingServer bool
417 options []byte
418 }
419)
420
421func (sd *serviceDesc) Options() pref.OptionsMessage {
422 return unmarshalOptions(ptype.X.ServiceOptions(), sd.lazyInit().options)
423}
424func (sd *serviceDesc) Methods() pref.MethodDescriptors { return &sd.lazyInit().methods }
425func (sd *serviceDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, sd) }
426func (sd *serviceDesc) ProtoType(pref.ServiceDescriptor) {}
427func (sd *serviceDesc) ProtoInternal(pragma.DoNotImplement) {}
428func (sd *serviceDesc) lazyInit() *serviceLazy {
429 sd.parentFile.lazyInit() // implicitly initializes serviceLazy
430 return sd.lazy
431}
432
433func (md *methodDesc) Options() pref.OptionsMessage {
434 return unmarshalOptions(ptype.X.MethodOptions(), md.options)
435}
436func (md *methodDesc) InputType() pref.MessageDescriptor { return md.inputType }
437func (md *methodDesc) OutputType() pref.MessageDescriptor { return md.outputType }
438func (md *methodDesc) IsStreamingClient() bool { return md.isStreamingClient }
439func (md *methodDesc) IsStreamingServer() bool { return md.isStreamingServer }
440func (md *methodDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, md) }
441func (md *methodDesc) ProtoType(pref.MethodDescriptor) {}
442func (md *methodDesc) ProtoInternal(pragma.DoNotImplement) {}
443
444type baseDesc struct {
445 parentFile *fileDesc
446 parent pref.Descriptor
447 index int
448 fullName
449}
450
451func (d *baseDesc) Parent() (pref.Descriptor, bool) { return d.parent, true }
452func (d *baseDesc) Index() int { return d.index }
453func (d *baseDesc) Syntax() pref.Syntax { return d.parentFile.Syntax() }
454func (d *baseDesc) IsPlaceholder() bool { return false }
455func (d *baseDesc) ProtoInternal(pragma.DoNotImplement) {}
456
457type fullName struct {
458 shortLen int
459 fullName pref.FullName
460}
461
462func (s *fullName) Name() pref.Name { return pref.Name(s.fullName[len(s.fullName)-s.shortLen:]) }
463func (s *fullName) FullName() pref.FullName { return s.fullName }
464
465func unmarshalOptions(p pref.OptionsMessage, b []byte) pref.OptionsMessage {
466 if b != nil {
467 // TODO: Consider caching the unmarshaled options message.
468 p = reflect.New(reflect.TypeOf(p).Elem()).Interface().(pref.OptionsMessage)
469 if err := proto.Unmarshal(b, p.(proto.Message)); err != nil {
470 panic(err)
471 }
472 }
473 return p.(proto.Message)
474}