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