blob: b53a90ff88dfc68fbbd450a65e6b81ff7ae8e144 [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
Joe Tsai35ec98f2019-03-25 14:41:32 -070016 pimpl "github.com/golang/protobuf/v2/internal/impl"
Damien Neil8012b442019-01-18 09:32:24 -080017 pragma "github.com/golang/protobuf/v2/internal/pragma"
Joe Tsai990b9f52019-03-13 12:56:39 -070018 ptype "github.com/golang/protobuf/v2/internal/prototype"
Damien Neil8012b442019-01-18 09:32:24 -080019 pfmt "github.com/golang/protobuf/v2/internal/typefmt"
20 "github.com/golang/protobuf/v2/proto"
21 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
Joe Tsai08cd8842019-03-18 13:46:39 -070022 preg "github.com/golang/protobuf/v2/reflect/protoregistry"
Joe Tsai4fddeba2019-03-20 18:29:32 -070023 piface "github.com/golang/protobuf/v2/runtime/protoiface"
Damien Neil8012b442019-01-18 09:32:24 -080024)
25
26// FileBuilder construct a protoreflect.FileDescriptor from the
27// raw file descriptor and the Go types for declarations and dependencies.
28//
29//
30// Flattened Ordering
31//
32// The protobuf type system represents declarations as a tree. Certain nodes in
33// the tree require us to either associate it with a concrete Go type or to
34// resolve a dependency, which is information that must be provided separately
35// since it cannot be derived from the file descriptor alone.
36//
37// However, representing a tree as Go literals is difficult to simply do in a
38// space and time efficient way. Thus, we store them as a flattened list of
39// objects where the serialization order from the tree-based form is important.
40//
41// The "flattened ordering" is defined as a tree traversal of all enum, message,
42// extension, and service declarations using the following algorithm:
43//
44// def VisitFileDecls(fd):
45// for e in fd.Enums: yield e
46// for m in fd.Messages: yield m
47// for x in fd.Extensions: yield x
48// for s in fd.Services: yield s
49// for m in fd.Messages: yield from VisitMessageDecls(m)
50//
51// def VisitMessageDecls(md):
52// for e in md.Enums: yield e
53// for m in md.Messages: yield m
54// for x in md.Extensions: yield x
55// for m in md.Messages: yield from VisitMessageDecls(m)
56//
57// The traversal starts at the root file descriptor and yields each direct
58// declaration within each node before traversing into sub-declarations
59// that children themselves may have.
60type FileBuilder struct {
61 // RawDescriptor is the wire-encoded bytes of FileDescriptorProto.
62 RawDescriptor []byte
63
64 // GoTypes is a unique set of the Go types for all declarations and
65 // dependencies. Each type is represented as a zero value of the Go type.
66 //
67 // Declarations are Go types generated for enums and messages directly
68 // declared (not publicly imported) in the proto source file.
69 // Messages for map entries are included, but represented by nil.
70 // Enum declarations in "flattened ordering" come first, followed by
71 // message declarations in "flattened ordering". The length of each sub-list
72 // is len(EnumOutputTypes) and len(MessageOutputTypes), respectively.
73 //
74 // Dependencies are Go types for enums or messages referenced by
75 // message fields (excluding weak fields), for parent extended messages of
76 // extension fields, for enums or messages referenced by extension fields,
77 // and for input and output messages referenced by service methods.
78 // Dependencies must come after declarations, but the ordering of
79 // dependencies themselves is unspecified.
80 GoTypes []interface{}
81
82 // DependencyIndexes is an ordered list of indexes into GoTypes for the
83 // dependencies of messages, extensions, or services. There are 4 sub-lists
84 // each in "flattened ordering" concatenated back-to-back:
85 // * Extension field targets: list of the extended parent message of
86 // every extension. Length is len(ExtensionOutputTypes).
87 // * Message field dependencies: list of the enum or message type
88 // referred to by every message field.
89 // * Extension field dependencies: list of the enum or message type
90 // referred to by every extension field.
91 // * Service method dependencies: list of the input and output message type
92 // referred to by every service method.
93 DependencyIndexes []int32
94
95 // TODO: Provide a list of imported files.
96 // FileDependencies []pref.FileDescriptor
97
98 // TODO: Provide a list of extension types for options extensions.
99 // OptionDependencies []pref.ExtensionType
100
Joe Tsaiafb455e2019-03-14 16:08:22 -0700101 // LegacyExtensions are a list of legacy extension descriptors.
102 // If provided, the pointer to the v1 ExtensionDesc will be stored into the
103 // associated v2 ExtensionType and accessible via a pseudo-internal API.
104 // Also, the v2 ExtensionType will be stored into each v1 ExtensionDesc.
105 // If non-nil, len(LegacyExtensions) must equal len(ExtensionOutputTypes).
Joe Tsai4fddeba2019-03-20 18:29:32 -0700106 LegacyExtensions []piface.ExtensionDescV1
Joe Tsaiafb455e2019-03-14 16:08:22 -0700107
Damien Neil8012b442019-01-18 09:32:24 -0800108 // EnumOutputTypes is where Init stores all initialized enum types
109 // in "flattened ordering".
110 EnumOutputTypes []pref.EnumType
111 // MessageOutputTypes is where Init stores all initialized message types
Joe Tsai4532dd72019-03-19 17:04:06 -0700112 // in "flattened ordering". This includes slots for map entry messages,
113 // which are skipped over.
Joe Tsai35ec98f2019-03-25 14:41:32 -0700114 MessageOutputTypes []pimpl.MessageType
Damien Neil8012b442019-01-18 09:32:24 -0800115 // ExtensionOutputTypes is where Init stores all initialized extension types
116 // in "flattened ordering".
117 ExtensionOutputTypes []pref.ExtensionType
118
Joe Tsai08cd8842019-03-18 13:46:39 -0700119 // FilesRegistry is the file registry to register the file descriptor.
120 // If nil, no registration occurs.
121 FilesRegistry *preg.Files
122 // TypesRegistry is the types registry to register each type descriptor.
123 // If nil, no registration occurs.
124 TypesRegistry *preg.Types
Damien Neil8012b442019-01-18 09:32:24 -0800125}
126
127// Init constructs a FileDescriptor given the parameters set in FileBuilder.
128// It assumes that the inputs are well-formed and panics if any inconsistencies
129// are encountered.
130func (fb FileBuilder) Init() pref.FileDescriptor {
131 fd := newFileDesc(fb)
132
Joe Tsai08cd8842019-03-18 13:46:39 -0700133 // Keep v1 and v2 extension descriptors in sync.
Joe Tsaiafb455e2019-03-14 16:08:22 -0700134 if fb.LegacyExtensions != nil {
135 for i := range fd.allExtensions {
136 fd.allExtensions[i].legacyDesc = &fb.LegacyExtensions[i]
137 fb.LegacyExtensions[i].Type = &fd.allExtensions[i]
138 }
139 }
140
Joe Tsai08cd8842019-03-18 13:46:39 -0700141 // Copy type descriptors to the output.
Joe Tsai35ec98f2019-03-25 14:41:32 -0700142 //
143 // While iterating over the messages, we also determine whether the message
144 // is a map entry type.
145 messageGoTypes := fb.GoTypes[len(fd.allEnums):][:len(fd.allMessages)]
Damien Neil8012b442019-01-18 09:32:24 -0800146 for i := range fd.allEnums {
147 fb.EnumOutputTypes[i] = &fd.allEnums[i]
148 }
149 for i := range fd.allMessages {
Joe Tsai35ec98f2019-03-25 14:41:32 -0700150 if messageGoTypes[i] == nil {
151 fd.allMessages[i].isMapEntry = true
152 } else {
153 fb.MessageOutputTypes[i].GoType = reflect.TypeOf(messageGoTypes[i])
154 fb.MessageOutputTypes[i].PBType = fd.allMessages[i].asDesc().(pref.MessageType)
Joe Tsai4532dd72019-03-19 17:04:06 -0700155 }
Damien Neil8012b442019-01-18 09:32:24 -0800156 }
157 for i := range fd.allExtensions {
158 fb.ExtensionOutputTypes[i] = &fd.allExtensions[i]
159 }
Joe Tsai08cd8842019-03-18 13:46:39 -0700160
161 // Register file and type descriptors.
162 if fb.FilesRegistry != nil {
163 if err := fb.FilesRegistry.Register(fd); err != nil {
164 panic(err)
165 }
166 }
167 if fb.TypesRegistry != nil {
168 for i := range fd.allEnums {
169 if err := fb.TypesRegistry.Register(&fd.allEnums[i]); err != nil {
170 panic(err)
171 }
172 }
173 for i := range fd.allMessages {
Joe Tsai4532dd72019-03-19 17:04:06 -0700174 if mt, _ := fd.allMessages[i].asDesc().(pref.MessageType); mt != nil {
175 if err := fb.TypesRegistry.Register(mt); err != nil {
176 panic(err)
177 }
Joe Tsai08cd8842019-03-18 13:46:39 -0700178 }
179 }
180 for i := range fd.allExtensions {
181 if err := fb.TypesRegistry.Register(&fd.allExtensions[i]); err != nil {
182 panic(err)
183 }
184 }
185 }
186
Damien Neil8012b442019-01-18 09:32:24 -0800187 return fd
188}
189
190type (
191 // fileInit contains a copy of certain fields in FileBuilder for use during
192 // lazy initialization upon first use.
193 fileInit struct {
194 RawDescriptor []byte
195 GoTypes []interface{}
196 DependencyIndexes []int32
197 }
198 fileDesc struct {
199 fileInit
200
201 path string
202 protoPackage pref.FullName
203
204 fileDecls
205
206 enums enumDescs
207 messages messageDescs
208 extensions extensionDescs
209 services serviceDescs
210
211 once sync.Once
212 lazy *fileLazy // protected by once
213 }
214 fileDecls struct {
215 allEnums []enumDesc
216 allMessages []messageDesc
217 allExtensions []extensionDesc
218 }
219 fileLazy struct {
220 syntax pref.Syntax
221 imports fileImports
222 byName map[pref.FullName]pref.Descriptor
223 options []byte
224 }
225)
226
227func (fd *fileDesc) Parent() (pref.Descriptor, bool) { return nil, false }
228func (fd *fileDesc) Index() int { return 0 }
229func (fd *fileDesc) Syntax() pref.Syntax { return fd.lazyInit().syntax }
230func (fd *fileDesc) Name() pref.Name { return fd.Package().Name() }
231func (fd *fileDesc) FullName() pref.FullName { return fd.Package() }
232func (fd *fileDesc) IsPlaceholder() bool { return false }
233func (fd *fileDesc) Options() pref.OptionsMessage {
234 return unmarshalOptions(ptype.X.FileOptions(), fd.lazyInit().options)
235}
236func (fd *fileDesc) Path() string { return fd.path }
237func (fd *fileDesc) Package() pref.FullName { return fd.protoPackage }
238func (fd *fileDesc) Imports() pref.FileImports { return &fd.lazyInit().imports }
239func (fd *fileDesc) Enums() pref.EnumDescriptors { return &fd.enums }
240func (fd *fileDesc) Messages() pref.MessageDescriptors { return &fd.messages }
241func (fd *fileDesc) Extensions() pref.ExtensionDescriptors { return &fd.extensions }
242func (fd *fileDesc) Services() pref.ServiceDescriptors { return &fd.services }
243func (fd *fileDesc) DescriptorByName(s pref.FullName) pref.Descriptor { return fd.lazyInit().byName[s] }
244func (fd *fileDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, fd) }
245func (fd *fileDesc) ProtoType(pref.FileDescriptor) {}
246func (fd *fileDesc) ProtoInternal(pragma.DoNotImplement) {}
247
248type (
249 enumDesc struct {
250 baseDesc
251
252 lazy *enumLazy // protected by fileDesc.once
253 }
254 enumLazy struct {
255 typ reflect.Type
256 new func(pref.EnumNumber) pref.Enum
257
258 values enumValueDescs
259 resvNames names
260 resvRanges enumRanges
261 options []byte
262 }
263 enumValueDesc struct {
264 baseDesc
265
266 number pref.EnumNumber
267 options []byte
268 }
269)
270
271func (ed *enumDesc) GoType() reflect.Type { return ed.lazyInit().typ }
272func (ed *enumDesc) New(n pref.EnumNumber) pref.Enum { return ed.lazyInit().new(n) }
273func (ed *enumDesc) Options() pref.OptionsMessage {
274 return unmarshalOptions(ptype.X.EnumOptions(), ed.lazyInit().options)
275}
276func (ed *enumDesc) Values() pref.EnumValueDescriptors { return &ed.lazyInit().values }
277func (ed *enumDesc) ReservedNames() pref.Names { return &ed.lazyInit().resvNames }
278func (ed *enumDesc) ReservedRanges() pref.EnumRanges { return &ed.lazyInit().resvRanges }
279func (ed *enumDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, ed) }
280func (ed *enumDesc) ProtoType(pref.EnumDescriptor) {}
281func (ed *enumDesc) lazyInit() *enumLazy {
282 ed.parentFile.lazyInit() // implicitly initializes enumLazy
283 return ed.lazy
284}
285
286func (ed *enumValueDesc) Options() pref.OptionsMessage {
287 return unmarshalOptions(ptype.X.EnumValueOptions(), ed.options)
288}
289func (ed *enumValueDesc) Number() pref.EnumNumber { return ed.number }
290func (ed *enumValueDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, ed) }
291func (ed *enumValueDesc) ProtoType(pref.EnumValueDescriptor) {}
292
293type (
Joe Tsai4532dd72019-03-19 17:04:06 -0700294 messageType struct{ *messageDesc }
295 messageDescriptor struct{ *messageDesc }
296
297 // messageDesc does not implement protoreflect.Descriptor to avoid
298 // accidental usages of it as such. Use the asDesc method to retrieve one.
Damien Neil8012b442019-01-18 09:32:24 -0800299 messageDesc struct {
300 baseDesc
301
302 enums enumDescs
303 messages messageDescs
304 extensions extensionDescs
305
Joe Tsai4532dd72019-03-19 17:04:06 -0700306 isMapEntry bool
307 lazy *messageLazy // protected by fileDesc.once
Damien Neil8012b442019-01-18 09:32:24 -0800308 }
309 messageLazy struct {
310 typ reflect.Type
311 new func() pref.Message
312
Joe Tsai1321a0e2019-03-20 09:46:22 -0700313 isMessageSet bool
Damien Neil8012b442019-01-18 09:32:24 -0800314 fields fieldDescs
315 oneofs oneofDescs
316 resvNames names
317 resvRanges fieldRanges
318 reqNumbers fieldNumbers
319 extRanges fieldRanges
320 extRangeOptions [][]byte
321 options []byte
322 }
323 fieldDesc struct {
324 baseDesc
325
326 number pref.FieldNumber
327 cardinality pref.Cardinality
328 kind pref.Kind
329 hasJSONName bool
330 jsonName string
331 hasPacked bool
332 isPacked bool
333 isWeak bool
334 isMap bool
335 defVal defaultValue
336 oneofType pref.OneofDescriptor
337 enumType pref.EnumDescriptor
338 messageType pref.MessageDescriptor
339 options []byte
340 }
341 oneofDesc struct {
342 baseDesc
343
344 fields oneofFields
345 options []byte
346 }
347)
348
Joe Tsai4532dd72019-03-19 17:04:06 -0700349func (md *messageDesc) options() pref.OptionsMessage {
Damien Neil8012b442019-01-18 09:32:24 -0800350 return unmarshalOptions(ptype.X.MessageOptions(), md.lazyInit().options)
351}
Joe Tsai4532dd72019-03-19 17:04:06 -0700352func (md *messageDesc) IsMapEntry() bool { return md.isMapEntry }
Damien Neil8012b442019-01-18 09:32:24 -0800353func (md *messageDesc) Fields() pref.FieldDescriptors { return &md.lazyInit().fields }
354func (md *messageDesc) Oneofs() pref.OneofDescriptors { return &md.lazyInit().oneofs }
355func (md *messageDesc) ReservedNames() pref.Names { return &md.lazyInit().resvNames }
356func (md *messageDesc) ReservedRanges() pref.FieldRanges { return &md.lazyInit().resvRanges }
357func (md *messageDesc) RequiredNumbers() pref.FieldNumbers { return &md.lazyInit().reqNumbers }
358func (md *messageDesc) ExtensionRanges() pref.FieldRanges { return &md.lazyInit().extRanges }
359func (md *messageDesc) ExtensionRangeOptions(i int) pref.OptionsMessage {
360 return unmarshalOptions(ptype.X.ExtensionRangeOptions(), md.lazyInit().extRangeOptions[i])
361}
362func (md *messageDesc) Enums() pref.EnumDescriptors { return &md.enums }
363func (md *messageDesc) Messages() pref.MessageDescriptors { return &md.messages }
364func (md *messageDesc) Extensions() pref.ExtensionDescriptors { return &md.extensions }
Damien Neil8012b442019-01-18 09:32:24 -0800365func (md *messageDesc) ProtoType(pref.MessageDescriptor) {}
Joe Tsai4532dd72019-03-19 17:04:06 -0700366func (md *messageDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, md.asDesc()) }
Damien Neil8012b442019-01-18 09:32:24 -0800367func (md *messageDesc) lazyInit() *messageLazy {
368 md.parentFile.lazyInit() // implicitly initializes messageLazy
369 return md.lazy
370}
371
Joe Tsai1321a0e2019-03-20 09:46:22 -0700372// IsMessageSet is a pseudo-internal API for checking whether a message
373// should serialize in the proto1 message format.
Joe Tsaia5f43e82019-04-10 17:11:20 -0700374//
375// WARNING: This method is exempt from the compatibility promise and may be
376// removed in the future without warning.
Joe Tsai1321a0e2019-03-20 09:46:22 -0700377func (md *messageDesc) IsMessageSet() bool {
378 return md.lazyInit().isMessageSet
379}
380
Joe Tsai4532dd72019-03-19 17:04:06 -0700381// asDesc returns a protoreflect.MessageDescriptor or protoreflect.MessageType
382// depending on whether the message is a map entry or not.
383func (mb *messageDesc) asDesc() pref.MessageDescriptor {
384 if !mb.isMapEntry {
385 return messageType{mb}
386 }
387 return messageDescriptor{mb}
388}
389func (mt messageType) GoType() reflect.Type { return mt.lazyInit().typ }
390func (mt messageType) New() pref.Message { return mt.lazyInit().new() }
391func (mt messageType) Options() pref.OptionsMessage { return mt.options() }
392func (md messageDescriptor) Options() pref.OptionsMessage { return md.options() }
393
Damien Neil8012b442019-01-18 09:32:24 -0800394func (fd *fieldDesc) Options() pref.OptionsMessage {
395 return unmarshalOptions(ptype.X.FieldOptions(), fd.options)
396}
397func (fd *fieldDesc) Number() pref.FieldNumber { return fd.number }
398func (fd *fieldDesc) Cardinality() pref.Cardinality { return fd.cardinality }
399func (fd *fieldDesc) Kind() pref.Kind { return fd.kind }
400func (fd *fieldDesc) HasJSONName() bool { return fd.hasJSONName }
401func (fd *fieldDesc) JSONName() string { return fd.jsonName }
402func (fd *fieldDesc) IsPacked() bool { return fd.isPacked }
403func (fd *fieldDesc) IsWeak() bool { return fd.isWeak }
404func (fd *fieldDesc) IsMap() bool { return fd.isMap }
405func (fd *fieldDesc) HasDefault() bool { return fd.defVal.has }
406func (fd *fieldDesc) Default() pref.Value { return fd.defVal.get() }
407func (fd *fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return fd.defVal.enum }
408func (fd *fieldDesc) OneofType() pref.OneofDescriptor { return fd.oneofType }
409func (fd *fieldDesc) ExtendedType() pref.MessageDescriptor { return nil }
410func (fd *fieldDesc) EnumType() pref.EnumDescriptor { return fd.enumType }
411func (fd *fieldDesc) MessageType() pref.MessageDescriptor { return fd.messageType }
412func (fd *fieldDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, fd) }
413func (fd *fieldDesc) ProtoType(pref.FieldDescriptor) {}
414
415func (od *oneofDesc) Options() pref.OptionsMessage {
416 return unmarshalOptions(ptype.X.OneofOptions(), od.options)
417}
418func (od *oneofDesc) Fields() pref.FieldDescriptors { return &od.fields }
419func (od *oneofDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, od) }
420func (od *oneofDesc) ProtoType(pref.OneofDescriptor) {}
421
422type (
423 extensionDesc struct {
424 baseDesc
425
426 number pref.FieldNumber
427 extendedType pref.MessageDescriptor
428
Joe Tsai4fddeba2019-03-20 18:29:32 -0700429 legacyDesc *piface.ExtensionDescV1
Joe Tsaiafb455e2019-03-14 16:08:22 -0700430
Damien Neil8012b442019-01-18 09:32:24 -0800431 lazy *extensionLazy // protected by fileDesc.once
432 }
433 extensionLazy struct {
434 typ reflect.Type
435 new func() pref.Value
436 valueOf func(interface{}) pref.Value
437 interfaceOf func(pref.Value) interface{}
438
439 cardinality pref.Cardinality
440 kind pref.Kind
441 // Extensions should not have JSON names, but older versions of protoc
442 // used to set one on the descriptor. Preserve it for now to maintain
443 // the property that protoc 3.6.1 descriptors can round-trip through
444 // this package losslessly.
445 //
446 // TODO: Consider whether to drop JSONName parsing from extensions.
447 hasJSONName bool
448 jsonName string
449 isPacked bool
450 defVal defaultValue
451 enumType pref.EnumType
452 messageType pref.MessageType
453 options []byte
454 }
455)
456
457func (xd *extensionDesc) GoType() reflect.Type { return xd.lazyInit().typ }
458func (xd *extensionDesc) New() pref.Value { return xd.lazyInit().new() }
459func (xd *extensionDesc) ValueOf(v interface{}) pref.Value { return xd.lazyInit().valueOf(v) }
460func (xd *extensionDesc) InterfaceOf(v pref.Value) interface{} { return xd.lazyInit().interfaceOf(v) }
461func (xd *extensionDesc) Options() pref.OptionsMessage {
462 return unmarshalOptions(ptype.X.FieldOptions(), xd.lazyInit().options)
463}
464func (xd *extensionDesc) Number() pref.FieldNumber { return xd.number }
465func (xd *extensionDesc) Cardinality() pref.Cardinality { return xd.lazyInit().cardinality }
466func (xd *extensionDesc) Kind() pref.Kind { return xd.lazyInit().kind }
467func (xd *extensionDesc) HasJSONName() bool { return xd.lazyInit().hasJSONName }
468func (xd *extensionDesc) JSONName() string { return xd.lazyInit().jsonName }
469func (xd *extensionDesc) IsPacked() bool { return xd.lazyInit().isPacked }
470func (xd *extensionDesc) IsWeak() bool { return false }
471func (xd *extensionDesc) IsMap() bool { return false }
472func (xd *extensionDesc) HasDefault() bool { return xd.lazyInit().defVal.has }
473func (xd *extensionDesc) Default() pref.Value { return xd.lazyInit().defVal.get() }
474func (xd *extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().defVal.enum }
475func (xd *extensionDesc) OneofType() pref.OneofDescriptor { return nil }
476func (xd *extensionDesc) ExtendedType() pref.MessageDescriptor { return xd.extendedType }
477func (xd *extensionDesc) EnumType() pref.EnumDescriptor { return xd.lazyInit().enumType }
478func (xd *extensionDesc) MessageType() pref.MessageDescriptor { return xd.lazyInit().messageType }
479func (xd *extensionDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, xd) }
480func (xd *extensionDesc) ProtoType(pref.FieldDescriptor) {}
481func (xd *extensionDesc) ProtoInternal(pragma.DoNotImplement) {}
482func (xd *extensionDesc) lazyInit() *extensionLazy {
483 xd.parentFile.lazyInit() // implicitly initializes extensionLazy
484 return xd.lazy
485}
486
Joe Tsaiafb455e2019-03-14 16:08:22 -0700487// ProtoLegacyExtensionDesc is a pseudo-internal API for allowing the v1 code
488// to be able to retrieve a v1 ExtensionDesc.
Joe Tsaia5f43e82019-04-10 17:11:20 -0700489//
490// WARNING: This method is exempt from the compatibility promise and may be
491// removed in the future without warning.
492func (xd *extensionDesc) ProtoLegacyExtensionDesc() *piface.ExtensionDescV1 {
493 return xd.legacyDesc
494}
Joe Tsaiafb455e2019-03-14 16:08:22 -0700495
Damien Neil8012b442019-01-18 09:32:24 -0800496type (
497 serviceDesc struct {
498 baseDesc
499
500 lazy *serviceLazy // protected by fileDesc.once
501 }
502 serviceLazy struct {
503 methods methodDescs
504 options []byte
505 }
506 methodDesc struct {
507 baseDesc
508
509 inputType pref.MessageDescriptor
510 outputType pref.MessageDescriptor
511 isStreamingClient bool
512 isStreamingServer bool
513 options []byte
514 }
515)
516
517func (sd *serviceDesc) Options() pref.OptionsMessage {
518 return unmarshalOptions(ptype.X.ServiceOptions(), sd.lazyInit().options)
519}
520func (sd *serviceDesc) Methods() pref.MethodDescriptors { return &sd.lazyInit().methods }
521func (sd *serviceDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, sd) }
522func (sd *serviceDesc) ProtoType(pref.ServiceDescriptor) {}
523func (sd *serviceDesc) ProtoInternal(pragma.DoNotImplement) {}
524func (sd *serviceDesc) lazyInit() *serviceLazy {
525 sd.parentFile.lazyInit() // implicitly initializes serviceLazy
526 return sd.lazy
527}
528
529func (md *methodDesc) Options() pref.OptionsMessage {
530 return unmarshalOptions(ptype.X.MethodOptions(), md.options)
531}
532func (md *methodDesc) InputType() pref.MessageDescriptor { return md.inputType }
533func (md *methodDesc) OutputType() pref.MessageDescriptor { return md.outputType }
534func (md *methodDesc) IsStreamingClient() bool { return md.isStreamingClient }
535func (md *methodDesc) IsStreamingServer() bool { return md.isStreamingServer }
536func (md *methodDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, md) }
537func (md *methodDesc) ProtoType(pref.MethodDescriptor) {}
538func (md *methodDesc) ProtoInternal(pragma.DoNotImplement) {}
539
540type baseDesc struct {
541 parentFile *fileDesc
542 parent pref.Descriptor
543 index int
544 fullName
545}
546
547func (d *baseDesc) Parent() (pref.Descriptor, bool) { return d.parent, true }
548func (d *baseDesc) Index() int { return d.index }
549func (d *baseDesc) Syntax() pref.Syntax { return d.parentFile.Syntax() }
550func (d *baseDesc) IsPlaceholder() bool { return false }
551func (d *baseDesc) ProtoInternal(pragma.DoNotImplement) {}
552
553type fullName struct {
554 shortLen int
555 fullName pref.FullName
556}
557
558func (s *fullName) Name() pref.Name { return pref.Name(s.fullName[len(s.fullName)-s.shortLen:]) }
559func (s *fullName) FullName() pref.FullName { return s.fullName }
560
561func unmarshalOptions(p pref.OptionsMessage, b []byte) pref.OptionsMessage {
562 if b != nil {
563 // TODO: Consider caching the unmarshaled options message.
564 p = reflect.New(reflect.TypeOf(p).Elem()).Interface().(pref.OptionsMessage)
565 if err := proto.Unmarshal(b, p.(proto.Message)); err != nil {
566 panic(err)
567 }
568 }
569 return p.(proto.Message)
570}