blob: dbfe3778e7d611460d8f4b35418907c806740408 [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
295 fields fieldDescs
296 oneofs oneofDescs
297 resvNames names
298 resvRanges fieldRanges
299 reqNumbers fieldNumbers
300 extRanges fieldRanges
301 extRangeOptions [][]byte
302 options []byte
303 }
304 fieldDesc struct {
305 baseDesc
306
307 number pref.FieldNumber
308 cardinality pref.Cardinality
309 kind pref.Kind
310 hasJSONName bool
311 jsonName string
312 hasPacked bool
313 isPacked bool
314 isWeak bool
315 isMap bool
316 defVal defaultValue
317 oneofType pref.OneofDescriptor
318 enumType pref.EnumDescriptor
319 messageType pref.MessageDescriptor
320 options []byte
321 }
322 oneofDesc struct {
323 baseDesc
324
325 fields oneofFields
326 options []byte
327 }
328)
329
330func (md *messageDesc) GoType() reflect.Type { return md.lazyInit().typ }
331func (md *messageDesc) New() pref.Message { return md.lazyInit().new() }
332func (md *messageDesc) Options() pref.OptionsMessage {
333 return unmarshalOptions(ptype.X.MessageOptions(), md.lazyInit().options)
334}
335func (md *messageDesc) IsMapEntry() bool { return md.lazyInit().isMapEntry }
336func (md *messageDesc) Fields() pref.FieldDescriptors { return &md.lazyInit().fields }
337func (md *messageDesc) Oneofs() pref.OneofDescriptors { return &md.lazyInit().oneofs }
338func (md *messageDesc) ReservedNames() pref.Names { return &md.lazyInit().resvNames }
339func (md *messageDesc) ReservedRanges() pref.FieldRanges { return &md.lazyInit().resvRanges }
340func (md *messageDesc) RequiredNumbers() pref.FieldNumbers { return &md.lazyInit().reqNumbers }
341func (md *messageDesc) ExtensionRanges() pref.FieldRanges { return &md.lazyInit().extRanges }
342func (md *messageDesc) ExtensionRangeOptions(i int) pref.OptionsMessage {
343 return unmarshalOptions(ptype.X.ExtensionRangeOptions(), md.lazyInit().extRangeOptions[i])
344}
345func (md *messageDesc) Enums() pref.EnumDescriptors { return &md.enums }
346func (md *messageDesc) Messages() pref.MessageDescriptors { return &md.messages }
347func (md *messageDesc) Extensions() pref.ExtensionDescriptors { return &md.extensions }
348func (md *messageDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, md) }
349func (md *messageDesc) ProtoType(pref.MessageDescriptor) {}
350func (md *messageDesc) lazyInit() *messageLazy {
351 md.parentFile.lazyInit() // implicitly initializes messageLazy
352 return md.lazy
353}
354
355func (fd *fieldDesc) Options() pref.OptionsMessage {
356 return unmarshalOptions(ptype.X.FieldOptions(), fd.options)
357}
358func (fd *fieldDesc) Number() pref.FieldNumber { return fd.number }
359func (fd *fieldDesc) Cardinality() pref.Cardinality { return fd.cardinality }
360func (fd *fieldDesc) Kind() pref.Kind { return fd.kind }
361func (fd *fieldDesc) HasJSONName() bool { return fd.hasJSONName }
362func (fd *fieldDesc) JSONName() string { return fd.jsonName }
363func (fd *fieldDesc) IsPacked() bool { return fd.isPacked }
364func (fd *fieldDesc) IsWeak() bool { return fd.isWeak }
365func (fd *fieldDesc) IsMap() bool { return fd.isMap }
366func (fd *fieldDesc) HasDefault() bool { return fd.defVal.has }
367func (fd *fieldDesc) Default() pref.Value { return fd.defVal.get() }
368func (fd *fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return fd.defVal.enum }
369func (fd *fieldDesc) OneofType() pref.OneofDescriptor { return fd.oneofType }
370func (fd *fieldDesc) ExtendedType() pref.MessageDescriptor { return nil }
371func (fd *fieldDesc) EnumType() pref.EnumDescriptor { return fd.enumType }
372func (fd *fieldDesc) MessageType() pref.MessageDescriptor { return fd.messageType }
373func (fd *fieldDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, fd) }
374func (fd *fieldDesc) ProtoType(pref.FieldDescriptor) {}
375
376func (od *oneofDesc) Options() pref.OptionsMessage {
377 return unmarshalOptions(ptype.X.OneofOptions(), od.options)
378}
379func (od *oneofDesc) Fields() pref.FieldDescriptors { return &od.fields }
380func (od *oneofDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, od) }
381func (od *oneofDesc) ProtoType(pref.OneofDescriptor) {}
382
383type (
384 extensionDesc struct {
385 baseDesc
386
387 number pref.FieldNumber
388 extendedType pref.MessageDescriptor
389
Joe Tsaiafb455e2019-03-14 16:08:22 -0700390 legacyDesc *papi.ExtensionDesc
391
Damien Neil8012b442019-01-18 09:32:24 -0800392 lazy *extensionLazy // protected by fileDesc.once
393 }
394 extensionLazy struct {
395 typ reflect.Type
396 new func() pref.Value
397 valueOf func(interface{}) pref.Value
398 interfaceOf func(pref.Value) interface{}
399
400 cardinality pref.Cardinality
401 kind pref.Kind
402 // Extensions should not have JSON names, but older versions of protoc
403 // used to set one on the descriptor. Preserve it for now to maintain
404 // the property that protoc 3.6.1 descriptors can round-trip through
405 // this package losslessly.
406 //
407 // TODO: Consider whether to drop JSONName parsing from extensions.
408 hasJSONName bool
409 jsonName string
410 isPacked bool
411 defVal defaultValue
412 enumType pref.EnumType
413 messageType pref.MessageType
414 options []byte
415 }
416)
417
418func (xd *extensionDesc) GoType() reflect.Type { return xd.lazyInit().typ }
419func (xd *extensionDesc) New() pref.Value { return xd.lazyInit().new() }
420func (xd *extensionDesc) ValueOf(v interface{}) pref.Value { return xd.lazyInit().valueOf(v) }
421func (xd *extensionDesc) InterfaceOf(v pref.Value) interface{} { return xd.lazyInit().interfaceOf(v) }
422func (xd *extensionDesc) Options() pref.OptionsMessage {
423 return unmarshalOptions(ptype.X.FieldOptions(), xd.lazyInit().options)
424}
425func (xd *extensionDesc) Number() pref.FieldNumber { return xd.number }
426func (xd *extensionDesc) Cardinality() pref.Cardinality { return xd.lazyInit().cardinality }
427func (xd *extensionDesc) Kind() pref.Kind { return xd.lazyInit().kind }
428func (xd *extensionDesc) HasJSONName() bool { return xd.lazyInit().hasJSONName }
429func (xd *extensionDesc) JSONName() string { return xd.lazyInit().jsonName }
430func (xd *extensionDesc) IsPacked() bool { return xd.lazyInit().isPacked }
431func (xd *extensionDesc) IsWeak() bool { return false }
432func (xd *extensionDesc) IsMap() bool { return false }
433func (xd *extensionDesc) HasDefault() bool { return xd.lazyInit().defVal.has }
434func (xd *extensionDesc) Default() pref.Value { return xd.lazyInit().defVal.get() }
435func (xd *extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().defVal.enum }
436func (xd *extensionDesc) OneofType() pref.OneofDescriptor { return nil }
437func (xd *extensionDesc) ExtendedType() pref.MessageDescriptor { return xd.extendedType }
438func (xd *extensionDesc) EnumType() pref.EnumDescriptor { return xd.lazyInit().enumType }
439func (xd *extensionDesc) MessageType() pref.MessageDescriptor { return xd.lazyInit().messageType }
440func (xd *extensionDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, xd) }
441func (xd *extensionDesc) ProtoType(pref.FieldDescriptor) {}
442func (xd *extensionDesc) ProtoInternal(pragma.DoNotImplement) {}
443func (xd *extensionDesc) lazyInit() *extensionLazy {
444 xd.parentFile.lazyInit() // implicitly initializes extensionLazy
445 return xd.lazy
446}
447
Joe Tsaiafb455e2019-03-14 16:08:22 -0700448// ProtoLegacyExtensionDesc is a pseudo-internal API for allowing the v1 code
449// to be able to retrieve a v1 ExtensionDesc.
450func (xd *extensionDesc) ProtoLegacyExtensionDesc() *papi.ExtensionDesc { return xd.legacyDesc }
451
Damien Neil8012b442019-01-18 09:32:24 -0800452type (
453 serviceDesc struct {
454 baseDesc
455
456 lazy *serviceLazy // protected by fileDesc.once
457 }
458 serviceLazy struct {
459 methods methodDescs
460 options []byte
461 }
462 methodDesc struct {
463 baseDesc
464
465 inputType pref.MessageDescriptor
466 outputType pref.MessageDescriptor
467 isStreamingClient bool
468 isStreamingServer bool
469 options []byte
470 }
471)
472
473func (sd *serviceDesc) Options() pref.OptionsMessage {
474 return unmarshalOptions(ptype.X.ServiceOptions(), sd.lazyInit().options)
475}
476func (sd *serviceDesc) Methods() pref.MethodDescriptors { return &sd.lazyInit().methods }
477func (sd *serviceDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, sd) }
478func (sd *serviceDesc) ProtoType(pref.ServiceDescriptor) {}
479func (sd *serviceDesc) ProtoInternal(pragma.DoNotImplement) {}
480func (sd *serviceDesc) lazyInit() *serviceLazy {
481 sd.parentFile.lazyInit() // implicitly initializes serviceLazy
482 return sd.lazy
483}
484
485func (md *methodDesc) Options() pref.OptionsMessage {
486 return unmarshalOptions(ptype.X.MethodOptions(), md.options)
487}
488func (md *methodDesc) InputType() pref.MessageDescriptor { return md.inputType }
489func (md *methodDesc) OutputType() pref.MessageDescriptor { return md.outputType }
490func (md *methodDesc) IsStreamingClient() bool { return md.isStreamingClient }
491func (md *methodDesc) IsStreamingServer() bool { return md.isStreamingServer }
492func (md *methodDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, md) }
493func (md *methodDesc) ProtoType(pref.MethodDescriptor) {}
494func (md *methodDesc) ProtoInternal(pragma.DoNotImplement) {}
495
496type baseDesc struct {
497 parentFile *fileDesc
498 parent pref.Descriptor
499 index int
500 fullName
501}
502
503func (d *baseDesc) Parent() (pref.Descriptor, bool) { return d.parent, true }
504func (d *baseDesc) Index() int { return d.index }
505func (d *baseDesc) Syntax() pref.Syntax { return d.parentFile.Syntax() }
506func (d *baseDesc) IsPlaceholder() bool { return false }
507func (d *baseDesc) ProtoInternal(pragma.DoNotImplement) {}
508
509type fullName struct {
510 shortLen int
511 fullName pref.FullName
512}
513
514func (s *fullName) Name() pref.Name { return pref.Name(s.fullName[len(s.fullName)-s.shortLen:]) }
515func (s *fullName) FullName() pref.FullName { return s.fullName }
516
517func unmarshalOptions(p pref.OptionsMessage, b []byte) pref.OptionsMessage {
518 if b != nil {
519 // TODO: Consider caching the unmarshaled options message.
520 p = reflect.New(reflect.TypeOf(p).Elem()).Interface().(pref.OptionsMessage)
521 if err := proto.Unmarshal(b, p.(proto.Message)); err != nil {
522 panic(err)
523 }
524 }
525 return p.(proto.Message)
526}