blob: 6d3b1b497a30f96abdffd5c83834a07448e5114e [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
111 // in "flattened ordering"; this includes map entry types.
112 MessageOutputTypes []pref.MessageType
113 // ExtensionOutputTypes is where Init stores all initialized extension types
114 // in "flattened ordering".
115 ExtensionOutputTypes []pref.ExtensionType
116
Joe Tsai08cd8842019-03-18 13:46:39 -0700117 // FilesRegistry is the file registry to register the file descriptor.
118 // If nil, no registration occurs.
119 FilesRegistry *preg.Files
120 // TypesRegistry is the types registry to register each type descriptor.
121 // If nil, no registration occurs.
122 TypesRegistry *preg.Types
Damien Neil8012b442019-01-18 09:32:24 -0800123}
124
125// Init constructs a FileDescriptor given the parameters set in FileBuilder.
126// It assumes that the inputs are well-formed and panics if any inconsistencies
127// are encountered.
128func (fb FileBuilder) Init() pref.FileDescriptor {
129 fd := newFileDesc(fb)
130
Joe Tsai08cd8842019-03-18 13:46:39 -0700131 // Keep v1 and v2 extension descriptors in sync.
Joe Tsaiafb455e2019-03-14 16:08:22 -0700132 if fb.LegacyExtensions != nil {
133 for i := range fd.allExtensions {
134 fd.allExtensions[i].legacyDesc = &fb.LegacyExtensions[i]
135 fb.LegacyExtensions[i].Type = &fd.allExtensions[i]
136 }
137 }
138
Joe Tsai08cd8842019-03-18 13:46:39 -0700139 // Copy type descriptors to the output.
Damien Neil8012b442019-01-18 09:32:24 -0800140 for i := range fd.allEnums {
141 fb.EnumOutputTypes[i] = &fd.allEnums[i]
142 }
143 for i := range fd.allMessages {
144 fb.MessageOutputTypes[i] = &fd.allMessages[i]
145 }
146 for i := range fd.allExtensions {
147 fb.ExtensionOutputTypes[i] = &fd.allExtensions[i]
148 }
Joe Tsai08cd8842019-03-18 13:46:39 -0700149
150 // Register file and type descriptors.
151 if fb.FilesRegistry != nil {
152 if err := fb.FilesRegistry.Register(fd); err != nil {
153 panic(err)
154 }
155 }
156 if fb.TypesRegistry != nil {
157 for i := range fd.allEnums {
158 if err := fb.TypesRegistry.Register(&fd.allEnums[i]); err != nil {
159 panic(err)
160 }
161 }
162 for i := range fd.allMessages {
163 if err := fb.TypesRegistry.Register(&fd.allMessages[i]); err != nil {
164 panic(err)
165 }
166 }
167 for i := range fd.allExtensions {
168 if err := fb.TypesRegistry.Register(&fd.allExtensions[i]); err != nil {
169 panic(err)
170 }
171 }
172 }
173
Damien Neil8012b442019-01-18 09:32:24 -0800174 return fd
175}
176
177type (
178 // fileInit contains a copy of certain fields in FileBuilder for use during
179 // lazy initialization upon first use.
180 fileInit struct {
181 RawDescriptor []byte
182 GoTypes []interface{}
183 DependencyIndexes []int32
184 }
185 fileDesc struct {
186 fileInit
187
188 path string
189 protoPackage pref.FullName
190
191 fileDecls
192
193 enums enumDescs
194 messages messageDescs
195 extensions extensionDescs
196 services serviceDescs
197
198 once sync.Once
199 lazy *fileLazy // protected by once
200 }
201 fileDecls struct {
202 allEnums []enumDesc
203 allMessages []messageDesc
204 allExtensions []extensionDesc
205 }
206 fileLazy struct {
207 syntax pref.Syntax
208 imports fileImports
209 byName map[pref.FullName]pref.Descriptor
210 options []byte
211 }
212)
213
214func (fd *fileDesc) Parent() (pref.Descriptor, bool) { return nil, false }
215func (fd *fileDesc) Index() int { return 0 }
216func (fd *fileDesc) Syntax() pref.Syntax { return fd.lazyInit().syntax }
217func (fd *fileDesc) Name() pref.Name { return fd.Package().Name() }
218func (fd *fileDesc) FullName() pref.FullName { return fd.Package() }
219func (fd *fileDesc) IsPlaceholder() bool { return false }
220func (fd *fileDesc) Options() pref.OptionsMessage {
221 return unmarshalOptions(ptype.X.FileOptions(), fd.lazyInit().options)
222}
223func (fd *fileDesc) Path() string { return fd.path }
224func (fd *fileDesc) Package() pref.FullName { return fd.protoPackage }
225func (fd *fileDesc) Imports() pref.FileImports { return &fd.lazyInit().imports }
226func (fd *fileDesc) Enums() pref.EnumDescriptors { return &fd.enums }
227func (fd *fileDesc) Messages() pref.MessageDescriptors { return &fd.messages }
228func (fd *fileDesc) Extensions() pref.ExtensionDescriptors { return &fd.extensions }
229func (fd *fileDesc) Services() pref.ServiceDescriptors { return &fd.services }
230func (fd *fileDesc) DescriptorByName(s pref.FullName) pref.Descriptor { return fd.lazyInit().byName[s] }
231func (fd *fileDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, fd) }
232func (fd *fileDesc) ProtoType(pref.FileDescriptor) {}
233func (fd *fileDesc) ProtoInternal(pragma.DoNotImplement) {}
234
235type (
236 enumDesc struct {
237 baseDesc
238
239 lazy *enumLazy // protected by fileDesc.once
240 }
241 enumLazy struct {
242 typ reflect.Type
243 new func(pref.EnumNumber) pref.Enum
244
245 values enumValueDescs
246 resvNames names
247 resvRanges enumRanges
248 options []byte
249 }
250 enumValueDesc struct {
251 baseDesc
252
253 number pref.EnumNumber
254 options []byte
255 }
256)
257
258func (ed *enumDesc) GoType() reflect.Type { return ed.lazyInit().typ }
259func (ed *enumDesc) New(n pref.EnumNumber) pref.Enum { return ed.lazyInit().new(n) }
260func (ed *enumDesc) Options() pref.OptionsMessage {
261 return unmarshalOptions(ptype.X.EnumOptions(), ed.lazyInit().options)
262}
263func (ed *enumDesc) Values() pref.EnumValueDescriptors { return &ed.lazyInit().values }
264func (ed *enumDesc) ReservedNames() pref.Names { return &ed.lazyInit().resvNames }
265func (ed *enumDesc) ReservedRanges() pref.EnumRanges { return &ed.lazyInit().resvRanges }
266func (ed *enumDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, ed) }
267func (ed *enumDesc) ProtoType(pref.EnumDescriptor) {}
268func (ed *enumDesc) lazyInit() *enumLazy {
269 ed.parentFile.lazyInit() // implicitly initializes enumLazy
270 return ed.lazy
271}
272
273func (ed *enumValueDesc) Options() pref.OptionsMessage {
274 return unmarshalOptions(ptype.X.EnumValueOptions(), ed.options)
275}
276func (ed *enumValueDesc) Number() pref.EnumNumber { return ed.number }
277func (ed *enumValueDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, ed) }
278func (ed *enumValueDesc) ProtoType(pref.EnumValueDescriptor) {}
279
280type (
281 messageDesc struct {
282 baseDesc
283
284 enums enumDescs
285 messages messageDescs
286 extensions extensionDescs
287
288 lazy *messageLazy // protected by fileDesc.once
289 }
290 messageLazy struct {
291 typ reflect.Type
292 new func() pref.Message
293
294 isMapEntry bool
Joe Tsai1321a0e2019-03-20 09:46:22 -0700295 isMessageSet bool
Damien Neil8012b442019-01-18 09:32:24 -0800296 fields fieldDescs
297 oneofs oneofDescs
298 resvNames names
299 resvRanges fieldRanges
300 reqNumbers fieldNumbers
301 extRanges fieldRanges
302 extRangeOptions [][]byte
303 options []byte
304 }
305 fieldDesc struct {
306 baseDesc
307
308 number pref.FieldNumber
309 cardinality pref.Cardinality
310 kind pref.Kind
311 hasJSONName bool
312 jsonName string
313 hasPacked bool
314 isPacked bool
315 isWeak bool
316 isMap bool
317 defVal defaultValue
318 oneofType pref.OneofDescriptor
319 enumType pref.EnumDescriptor
320 messageType pref.MessageDescriptor
321 options []byte
322 }
323 oneofDesc struct {
324 baseDesc
325
326 fields oneofFields
327 options []byte
328 }
329)
330
331func (md *messageDesc) GoType() reflect.Type { return md.lazyInit().typ }
332func (md *messageDesc) New() pref.Message { return md.lazyInit().new() }
333func (md *messageDesc) Options() pref.OptionsMessage {
334 return unmarshalOptions(ptype.X.MessageOptions(), md.lazyInit().options)
335}
336func (md *messageDesc) IsMapEntry() bool { return md.lazyInit().isMapEntry }
337func (md *messageDesc) Fields() pref.FieldDescriptors { return &md.lazyInit().fields }
338func (md *messageDesc) Oneofs() pref.OneofDescriptors { return &md.lazyInit().oneofs }
339func (md *messageDesc) ReservedNames() pref.Names { return &md.lazyInit().resvNames }
340func (md *messageDesc) ReservedRanges() pref.FieldRanges { return &md.lazyInit().resvRanges }
341func (md *messageDesc) RequiredNumbers() pref.FieldNumbers { return &md.lazyInit().reqNumbers }
342func (md *messageDesc) ExtensionRanges() pref.FieldRanges { return &md.lazyInit().extRanges }
343func (md *messageDesc) ExtensionRangeOptions(i int) pref.OptionsMessage {
344 return unmarshalOptions(ptype.X.ExtensionRangeOptions(), md.lazyInit().extRangeOptions[i])
345}
346func (md *messageDesc) Enums() pref.EnumDescriptors { return &md.enums }
347func (md *messageDesc) Messages() pref.MessageDescriptors { return &md.messages }
348func (md *messageDesc) Extensions() pref.ExtensionDescriptors { return &md.extensions }
349func (md *messageDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, md) }
350func (md *messageDesc) ProtoType(pref.MessageDescriptor) {}
351func (md *messageDesc) lazyInit() *messageLazy {
352 md.parentFile.lazyInit() // implicitly initializes messageLazy
353 return md.lazy
354}
355
Joe Tsai1321a0e2019-03-20 09:46:22 -0700356// IsMessageSet is a pseudo-internal API for checking whether a message
357// should serialize in the proto1 message format.
358func (md *messageDesc) IsMessageSet() bool {
359 return md.lazyInit().isMessageSet
360}
361
Damien Neil8012b442019-01-18 09:32:24 -0800362func (fd *fieldDesc) Options() pref.OptionsMessage {
363 return unmarshalOptions(ptype.X.FieldOptions(), fd.options)
364}
365func (fd *fieldDesc) Number() pref.FieldNumber { return fd.number }
366func (fd *fieldDesc) Cardinality() pref.Cardinality { return fd.cardinality }
367func (fd *fieldDesc) Kind() pref.Kind { return fd.kind }
368func (fd *fieldDesc) HasJSONName() bool { return fd.hasJSONName }
369func (fd *fieldDesc) JSONName() string { return fd.jsonName }
370func (fd *fieldDesc) IsPacked() bool { return fd.isPacked }
371func (fd *fieldDesc) IsWeak() bool { return fd.isWeak }
372func (fd *fieldDesc) IsMap() bool { return fd.isMap }
373func (fd *fieldDesc) HasDefault() bool { return fd.defVal.has }
374func (fd *fieldDesc) Default() pref.Value { return fd.defVal.get() }
375func (fd *fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return fd.defVal.enum }
376func (fd *fieldDesc) OneofType() pref.OneofDescriptor { return fd.oneofType }
377func (fd *fieldDesc) ExtendedType() pref.MessageDescriptor { return nil }
378func (fd *fieldDesc) EnumType() pref.EnumDescriptor { return fd.enumType }
379func (fd *fieldDesc) MessageType() pref.MessageDescriptor { return fd.messageType }
380func (fd *fieldDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, fd) }
381func (fd *fieldDesc) ProtoType(pref.FieldDescriptor) {}
382
383func (od *oneofDesc) Options() pref.OptionsMessage {
384 return unmarshalOptions(ptype.X.OneofOptions(), od.options)
385}
386func (od *oneofDesc) Fields() pref.FieldDescriptors { return &od.fields }
387func (od *oneofDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, od) }
388func (od *oneofDesc) ProtoType(pref.OneofDescriptor) {}
389
390type (
391 extensionDesc struct {
392 baseDesc
393
394 number pref.FieldNumber
395 extendedType pref.MessageDescriptor
396
Joe Tsaiafb455e2019-03-14 16:08:22 -0700397 legacyDesc *papi.ExtensionDesc
398
Damien Neil8012b442019-01-18 09:32:24 -0800399 lazy *extensionLazy // protected by fileDesc.once
400 }
401 extensionLazy struct {
402 typ reflect.Type
403 new func() pref.Value
404 valueOf func(interface{}) pref.Value
405 interfaceOf func(pref.Value) interface{}
406
407 cardinality pref.Cardinality
408 kind pref.Kind
409 // Extensions should not have JSON names, but older versions of protoc
410 // used to set one on the descriptor. Preserve it for now to maintain
411 // the property that protoc 3.6.1 descriptors can round-trip through
412 // this package losslessly.
413 //
414 // TODO: Consider whether to drop JSONName parsing from extensions.
415 hasJSONName bool
416 jsonName string
417 isPacked bool
418 defVal defaultValue
419 enumType pref.EnumType
420 messageType pref.MessageType
421 options []byte
422 }
423)
424
425func (xd *extensionDesc) GoType() reflect.Type { return xd.lazyInit().typ }
426func (xd *extensionDesc) New() pref.Value { return xd.lazyInit().new() }
427func (xd *extensionDesc) ValueOf(v interface{}) pref.Value { return xd.lazyInit().valueOf(v) }
428func (xd *extensionDesc) InterfaceOf(v pref.Value) interface{} { return xd.lazyInit().interfaceOf(v) }
429func (xd *extensionDesc) Options() pref.OptionsMessage {
430 return unmarshalOptions(ptype.X.FieldOptions(), xd.lazyInit().options)
431}
432func (xd *extensionDesc) Number() pref.FieldNumber { return xd.number }
433func (xd *extensionDesc) Cardinality() pref.Cardinality { return xd.lazyInit().cardinality }
434func (xd *extensionDesc) Kind() pref.Kind { return xd.lazyInit().kind }
435func (xd *extensionDesc) HasJSONName() bool { return xd.lazyInit().hasJSONName }
436func (xd *extensionDesc) JSONName() string { return xd.lazyInit().jsonName }
437func (xd *extensionDesc) IsPacked() bool { return xd.lazyInit().isPacked }
438func (xd *extensionDesc) IsWeak() bool { return false }
439func (xd *extensionDesc) IsMap() bool { return false }
440func (xd *extensionDesc) HasDefault() bool { return xd.lazyInit().defVal.has }
441func (xd *extensionDesc) Default() pref.Value { return xd.lazyInit().defVal.get() }
442func (xd *extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().defVal.enum }
443func (xd *extensionDesc) OneofType() pref.OneofDescriptor { return nil }
444func (xd *extensionDesc) ExtendedType() pref.MessageDescriptor { return xd.extendedType }
445func (xd *extensionDesc) EnumType() pref.EnumDescriptor { return xd.lazyInit().enumType }
446func (xd *extensionDesc) MessageType() pref.MessageDescriptor { return xd.lazyInit().messageType }
447func (xd *extensionDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, xd) }
448func (xd *extensionDesc) ProtoType(pref.FieldDescriptor) {}
449func (xd *extensionDesc) ProtoInternal(pragma.DoNotImplement) {}
450func (xd *extensionDesc) lazyInit() *extensionLazy {
451 xd.parentFile.lazyInit() // implicitly initializes extensionLazy
452 return xd.lazy
453}
454
Joe Tsaiafb455e2019-03-14 16:08:22 -0700455// ProtoLegacyExtensionDesc is a pseudo-internal API for allowing the v1 code
456// to be able to retrieve a v1 ExtensionDesc.
457func (xd *extensionDesc) ProtoLegacyExtensionDesc() *papi.ExtensionDesc { return xd.legacyDesc }
458
Damien Neil8012b442019-01-18 09:32:24 -0800459type (
460 serviceDesc struct {
461 baseDesc
462
463 lazy *serviceLazy // protected by fileDesc.once
464 }
465 serviceLazy struct {
466 methods methodDescs
467 options []byte
468 }
469 methodDesc struct {
470 baseDesc
471
472 inputType pref.MessageDescriptor
473 outputType pref.MessageDescriptor
474 isStreamingClient bool
475 isStreamingServer bool
476 options []byte
477 }
478)
479
480func (sd *serviceDesc) Options() pref.OptionsMessage {
481 return unmarshalOptions(ptype.X.ServiceOptions(), sd.lazyInit().options)
482}
483func (sd *serviceDesc) Methods() pref.MethodDescriptors { return &sd.lazyInit().methods }
484func (sd *serviceDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, sd) }
485func (sd *serviceDesc) ProtoType(pref.ServiceDescriptor) {}
486func (sd *serviceDesc) ProtoInternal(pragma.DoNotImplement) {}
487func (sd *serviceDesc) lazyInit() *serviceLazy {
488 sd.parentFile.lazyInit() // implicitly initializes serviceLazy
489 return sd.lazy
490}
491
492func (md *methodDesc) Options() pref.OptionsMessage {
493 return unmarshalOptions(ptype.X.MethodOptions(), md.options)
494}
495func (md *methodDesc) InputType() pref.MessageDescriptor { return md.inputType }
496func (md *methodDesc) OutputType() pref.MessageDescriptor { return md.outputType }
497func (md *methodDesc) IsStreamingClient() bool { return md.isStreamingClient }
498func (md *methodDesc) IsStreamingServer() bool { return md.isStreamingServer }
499func (md *methodDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, md) }
500func (md *methodDesc) ProtoType(pref.MethodDescriptor) {}
501func (md *methodDesc) ProtoInternal(pragma.DoNotImplement) {}
502
503type baseDesc struct {
504 parentFile *fileDesc
505 parent pref.Descriptor
506 index int
507 fullName
508}
509
510func (d *baseDesc) Parent() (pref.Descriptor, bool) { return d.parent, true }
511func (d *baseDesc) Index() int { return d.index }
512func (d *baseDesc) Syntax() pref.Syntax { return d.parentFile.Syntax() }
513func (d *baseDesc) IsPlaceholder() bool { return false }
514func (d *baseDesc) ProtoInternal(pragma.DoNotImplement) {}
515
516type fullName struct {
517 shortLen int
518 fullName pref.FullName
519}
520
521func (s *fullName) Name() pref.Name { return pref.Name(s.fullName[len(s.fullName)-s.shortLen:]) }
522func (s *fullName) FullName() pref.FullName { return s.fullName }
523
524func unmarshalOptions(p pref.OptionsMessage, b []byte) pref.OptionsMessage {
525 if b != nil {
526 // TODO: Consider caching the unmarshaled options message.
527 p = reflect.New(reflect.TypeOf(p).Elem()).Interface().(pref.OptionsMessage)
528 if err := proto.Unmarshal(b, p.(proto.Message)); err != nil {
529 panic(err)
530 }
531 }
532 return p.(proto.Message)
533}