blob: 8854cabb53a9c786df06e5c82013358af73c828c [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 Tsaia2dd2282019-04-10 16:45:04 -070016 descopts "github.com/golang/protobuf/v2/internal/descopts"
Joe Tsai35ec98f2019-03-25 14:41:32 -070017 pimpl "github.com/golang/protobuf/v2/internal/impl"
Damien Neil8012b442019-01-18 09:32:24 -080018 pragma "github.com/golang/protobuf/v2/internal/pragma"
19 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
Joe Tsaia2dd2282019-04-10 16:45:04 -0700161 // As a special-case for descriptor.proto,
162 // locally register concrete message type for the options.
163 if fd.Path() == "google/protobuf/descriptor.proto" && fd.Package() == "google.protobuf" {
164 for i := range fd.allMessages {
165 switch fd.allMessages[i].Name() {
166 case "FileOptions":
167 descopts.File = messageGoTypes[i].(pref.ProtoMessage)
168 case "EnumOptions":
169 descopts.Enum = messageGoTypes[i].(pref.ProtoMessage)
170 case "EnumValueOptions":
171 descopts.EnumValue = messageGoTypes[i].(pref.ProtoMessage)
172 case "MessageOptions":
173 descopts.Message = messageGoTypes[i].(pref.ProtoMessage)
174 case "FieldOptions":
175 descopts.Field = messageGoTypes[i].(pref.ProtoMessage)
176 case "OneofOptions":
177 descopts.Oneof = messageGoTypes[i].(pref.ProtoMessage)
178 case "ExtensionRangeOptions":
179 descopts.ExtensionRange = messageGoTypes[i].(pref.ProtoMessage)
180 case "ServiceOptions":
181 descopts.Service = messageGoTypes[i].(pref.ProtoMessage)
182 case "MethodOptions":
183 descopts.Method = messageGoTypes[i].(pref.ProtoMessage)
184 }
185 }
186 }
187
Joe Tsai08cd8842019-03-18 13:46:39 -0700188 // Register file and type descriptors.
189 if fb.FilesRegistry != nil {
190 if err := fb.FilesRegistry.Register(fd); err != nil {
191 panic(err)
192 }
193 }
194 if fb.TypesRegistry != nil {
195 for i := range fd.allEnums {
196 if err := fb.TypesRegistry.Register(&fd.allEnums[i]); err != nil {
197 panic(err)
198 }
199 }
200 for i := range fd.allMessages {
Joe Tsai4532dd72019-03-19 17:04:06 -0700201 if mt, _ := fd.allMessages[i].asDesc().(pref.MessageType); mt != nil {
202 if err := fb.TypesRegistry.Register(mt); err != nil {
203 panic(err)
204 }
Joe Tsai08cd8842019-03-18 13:46:39 -0700205 }
206 }
207 for i := range fd.allExtensions {
208 if err := fb.TypesRegistry.Register(&fd.allExtensions[i]); err != nil {
209 panic(err)
210 }
211 }
212 }
213
Damien Neil8012b442019-01-18 09:32:24 -0800214 return fd
215}
216
217type (
218 // fileInit contains a copy of certain fields in FileBuilder for use during
219 // lazy initialization upon first use.
220 fileInit struct {
Damien Neil8012b442019-01-18 09:32:24 -0800221 GoTypes []interface{}
222 DependencyIndexes []int32
223 }
224 fileDesc struct {
225 fileInit
Joe Tsaie089c0f2019-04-16 01:46:14 -0700226 rawDesc []byte
Damien Neil8012b442019-01-18 09:32:24 -0800227
228 path string
229 protoPackage pref.FullName
230
231 fileDecls
232
233 enums enumDescs
234 messages messageDescs
235 extensions extensionDescs
236 services serviceDescs
237
238 once sync.Once
239 lazy *fileLazy // protected by once
240 }
241 fileDecls struct {
242 allEnums []enumDesc
243 allMessages []messageDesc
244 allExtensions []extensionDesc
245 }
246 fileLazy struct {
247 syntax pref.Syntax
248 imports fileImports
Damien Neil8012b442019-01-18 09:32:24 -0800249 options []byte
250 }
251)
252
Joe Tsai67c1d9b2019-05-12 02:27:46 -0700253func (fd *fileDesc) ParentFile() pref.FileDescriptor { return fd }
Damien Neil8012b442019-01-18 09:32:24 -0800254func (fd *fileDesc) Parent() (pref.Descriptor, bool) { return nil, false }
255func (fd *fileDesc) Index() int { return 0 }
256func (fd *fileDesc) Syntax() pref.Syntax { return fd.lazyInit().syntax }
257func (fd *fileDesc) Name() pref.Name { return fd.Package().Name() }
258func (fd *fileDesc) FullName() pref.FullName { return fd.Package() }
259func (fd *fileDesc) IsPlaceholder() bool { return false }
Joe Tsaia2dd2282019-04-10 16:45:04 -0700260func (fd *fileDesc) Options() pref.ProtoMessage {
261 return unmarshalOptions(descopts.File, fd.lazyInit().options)
Damien Neil8012b442019-01-18 09:32:24 -0800262}
Damien Neil2300c182019-04-15 13:05:13 -0700263func (fd *fileDesc) Path() string { return fd.path }
264func (fd *fileDesc) Package() pref.FullName { return fd.protoPackage }
265func (fd *fileDesc) Imports() pref.FileImports { return &fd.lazyInit().imports }
266func (fd *fileDesc) Enums() pref.EnumDescriptors { return &fd.enums }
267func (fd *fileDesc) Messages() pref.MessageDescriptors { return &fd.messages }
268func (fd *fileDesc) Extensions() pref.ExtensionDescriptors { return &fd.extensions }
269func (fd *fileDesc) Services() pref.ServiceDescriptors { return &fd.services }
270func (fd *fileDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, fd) }
271func (fd *fileDesc) ProtoType(pref.FileDescriptor) {}
272func (fd *fileDesc) ProtoInternal(pragma.DoNotImplement) {}
Damien Neil8012b442019-01-18 09:32:24 -0800273
Joe Tsaie089c0f2019-04-16 01:46:14 -0700274// ProtoLegacyRawDesc is a pseudo-internal API for allowing the v1 code
275// to be able to retrieve the raw descriptor.
276//
277// WARNING: This method is exempt from the compatibility promise and may be
278// removed in the future without warning.
279func (fd *fileDesc) ProtoLegacyRawDesc() []byte {
280 return fd.rawDesc
281}
282
Damien Neil8012b442019-01-18 09:32:24 -0800283type (
284 enumDesc struct {
285 baseDesc
286
287 lazy *enumLazy // protected by fileDesc.once
288 }
289 enumLazy struct {
290 typ reflect.Type
291 new func(pref.EnumNumber) pref.Enum
292
293 values enumValueDescs
294 resvNames names
295 resvRanges enumRanges
296 options []byte
297 }
298 enumValueDesc struct {
299 baseDesc
300
301 number pref.EnumNumber
302 options []byte
303 }
304)
305
Joe Tsai0fc49f82019-05-01 12:29:25 -0700306func (ed *enumDesc) Descriptor() pref.EnumDescriptor { return ed }
Damien Neil8012b442019-01-18 09:32:24 -0800307func (ed *enumDesc) GoType() reflect.Type { return ed.lazyInit().typ }
308func (ed *enumDesc) New(n pref.EnumNumber) pref.Enum { return ed.lazyInit().new(n) }
Joe Tsaia2dd2282019-04-10 16:45:04 -0700309func (ed *enumDesc) Options() pref.ProtoMessage {
310 return unmarshalOptions(descopts.Enum, ed.lazyInit().options)
Damien Neil8012b442019-01-18 09:32:24 -0800311}
312func (ed *enumDesc) Values() pref.EnumValueDescriptors { return &ed.lazyInit().values }
313func (ed *enumDesc) ReservedNames() pref.Names { return &ed.lazyInit().resvNames }
314func (ed *enumDesc) ReservedRanges() pref.EnumRanges { return &ed.lazyInit().resvRanges }
315func (ed *enumDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, ed) }
316func (ed *enumDesc) ProtoType(pref.EnumDescriptor) {}
317func (ed *enumDesc) lazyInit() *enumLazy {
318 ed.parentFile.lazyInit() // implicitly initializes enumLazy
319 return ed.lazy
320}
321
Joe Tsaia2dd2282019-04-10 16:45:04 -0700322func (ed *enumValueDesc) Options() pref.ProtoMessage {
323 return unmarshalOptions(descopts.EnumValue, ed.options)
Damien Neil8012b442019-01-18 09:32:24 -0800324}
325func (ed *enumValueDesc) Number() pref.EnumNumber { return ed.number }
326func (ed *enumValueDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, ed) }
327func (ed *enumValueDesc) ProtoType(pref.EnumValueDescriptor) {}
328
329type (
Joe Tsai4532dd72019-03-19 17:04:06 -0700330 messageType struct{ *messageDesc }
331 messageDescriptor struct{ *messageDesc }
332
333 // messageDesc does not implement protoreflect.Descriptor to avoid
334 // accidental usages of it as such. Use the asDesc method to retrieve one.
Damien Neil8012b442019-01-18 09:32:24 -0800335 messageDesc struct {
336 baseDesc
337
338 enums enumDescs
339 messages messageDescs
340 extensions extensionDescs
341
Joe Tsai4532dd72019-03-19 17:04:06 -0700342 isMapEntry bool
343 lazy *messageLazy // protected by fileDesc.once
Damien Neil8012b442019-01-18 09:32:24 -0800344 }
345 messageLazy struct {
346 typ reflect.Type
347 new func() pref.Message
348
Joe Tsai1321a0e2019-03-20 09:46:22 -0700349 isMessageSet bool
Damien Neil8012b442019-01-18 09:32:24 -0800350 fields fieldDescs
351 oneofs oneofDescs
352 resvNames names
353 resvRanges fieldRanges
354 reqNumbers fieldNumbers
355 extRanges fieldRanges
356 extRangeOptions [][]byte
357 options []byte
358 }
359 fieldDesc struct {
360 baseDesc
361
362 number pref.FieldNumber
363 cardinality pref.Cardinality
364 kind pref.Kind
365 hasJSONName bool
366 jsonName string
367 hasPacked bool
368 isPacked bool
369 isWeak bool
370 isMap bool
371 defVal defaultValue
372 oneofType pref.OneofDescriptor
373 enumType pref.EnumDescriptor
374 messageType pref.MessageDescriptor
375 options []byte
376 }
377 oneofDesc struct {
378 baseDesc
379
380 fields oneofFields
381 options []byte
382 }
383)
384
Joe Tsaia2dd2282019-04-10 16:45:04 -0700385func (md *messageDesc) options() pref.ProtoMessage {
386 return unmarshalOptions(descopts.Message, md.lazyInit().options)
Damien Neil8012b442019-01-18 09:32:24 -0800387}
Joe Tsai4532dd72019-03-19 17:04:06 -0700388func (md *messageDesc) IsMapEntry() bool { return md.isMapEntry }
Damien Neil8012b442019-01-18 09:32:24 -0800389func (md *messageDesc) Fields() pref.FieldDescriptors { return &md.lazyInit().fields }
390func (md *messageDesc) Oneofs() pref.OneofDescriptors { return &md.lazyInit().oneofs }
391func (md *messageDesc) ReservedNames() pref.Names { return &md.lazyInit().resvNames }
392func (md *messageDesc) ReservedRanges() pref.FieldRanges { return &md.lazyInit().resvRanges }
393func (md *messageDesc) RequiredNumbers() pref.FieldNumbers { return &md.lazyInit().reqNumbers }
394func (md *messageDesc) ExtensionRanges() pref.FieldRanges { return &md.lazyInit().extRanges }
Joe Tsaia2dd2282019-04-10 16:45:04 -0700395func (md *messageDesc) ExtensionRangeOptions(i int) pref.ProtoMessage {
396 return unmarshalOptions(descopts.ExtensionRange, md.lazyInit().extRangeOptions[i])
Damien Neil8012b442019-01-18 09:32:24 -0800397}
398func (md *messageDesc) Enums() pref.EnumDescriptors { return &md.enums }
399func (md *messageDesc) Messages() pref.MessageDescriptors { return &md.messages }
400func (md *messageDesc) Extensions() pref.ExtensionDescriptors { return &md.extensions }
Damien Neil8012b442019-01-18 09:32:24 -0800401func (md *messageDesc) ProtoType(pref.MessageDescriptor) {}
Joe Tsai4532dd72019-03-19 17:04:06 -0700402func (md *messageDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, md.asDesc()) }
Damien Neil8012b442019-01-18 09:32:24 -0800403func (md *messageDesc) lazyInit() *messageLazy {
404 md.parentFile.lazyInit() // implicitly initializes messageLazy
405 return md.lazy
406}
407
Joe Tsai1321a0e2019-03-20 09:46:22 -0700408// IsMessageSet is a pseudo-internal API for checking whether a message
409// should serialize in the proto1 message format.
Joe Tsaia5f43e82019-04-10 17:11:20 -0700410//
411// WARNING: This method is exempt from the compatibility promise and may be
412// removed in the future without warning.
Joe Tsai1321a0e2019-03-20 09:46:22 -0700413func (md *messageDesc) IsMessageSet() bool {
414 return md.lazyInit().isMessageSet
415}
416
Joe Tsai4532dd72019-03-19 17:04:06 -0700417// asDesc returns a protoreflect.MessageDescriptor or protoreflect.MessageType
418// depending on whether the message is a map entry or not.
419func (mb *messageDesc) asDesc() pref.MessageDescriptor {
420 if !mb.isMapEntry {
421 return messageType{mb}
422 }
423 return messageDescriptor{mb}
424}
Joe Tsai0fc49f82019-05-01 12:29:25 -0700425func (mt messageType) Descriptor() pref.MessageDescriptor { return messageDescriptor{mt.messageDesc} }
426func (mt messageType) GoType() reflect.Type { return mt.lazyInit().typ }
427func (mt messageType) New() pref.Message { return mt.lazyInit().new() }
428func (mt messageType) Options() pref.ProtoMessage { return mt.options() }
429func (md messageDescriptor) Options() pref.ProtoMessage { return md.options() }
Joe Tsai4532dd72019-03-19 17:04:06 -0700430
Joe Tsaia2dd2282019-04-10 16:45:04 -0700431func (fd *fieldDesc) Options() pref.ProtoMessage {
432 return unmarshalOptions(descopts.Field, fd.options)
Damien Neil8012b442019-01-18 09:32:24 -0800433}
Joe Tsaiac31a352019-05-13 14:32:56 -0700434func (fd *fieldDesc) Number() pref.FieldNumber { return fd.number }
435func (fd *fieldDesc) Cardinality() pref.Cardinality { return fd.cardinality }
436func (fd *fieldDesc) Kind() pref.Kind { return fd.kind }
437func (fd *fieldDesc) HasJSONName() bool { return fd.hasJSONName }
438func (fd *fieldDesc) JSONName() string { return fd.jsonName }
439func (fd *fieldDesc) IsPacked() bool { return fd.isPacked }
440func (fd *fieldDesc) IsExtension() bool { return false }
441func (fd *fieldDesc) IsWeak() bool { return fd.isWeak }
442func (fd *fieldDesc) IsList() bool { return fd.cardinality == pref.Repeated && !fd.IsMap() }
443func (fd *fieldDesc) IsMap() bool { return fd.isMap }
444func (fd *fieldDesc) MapKey() pref.FieldDescriptor {
445 if !fd.isMap {
446 return nil
447 }
448 return fd.Message().Fields().ByNumber(1)
449}
450func (fd *fieldDesc) MapValue() pref.FieldDescriptor {
451 if !fd.isMap {
452 return nil
453 }
454 return fd.Message().Fields().ByNumber(2)
455}
Damien Neil8012b442019-01-18 09:32:24 -0800456func (fd *fieldDesc) HasDefault() bool { return fd.defVal.has }
457func (fd *fieldDesc) Default() pref.Value { return fd.defVal.get() }
458func (fd *fieldDesc) DefaultEnumValue() pref.EnumValueDescriptor { return fd.defVal.enum }
Joe Tsaiac31a352019-05-13 14:32:56 -0700459func (fd *fieldDesc) ContainingOneof() pref.OneofDescriptor { return fd.oneofType }
460func (fd *fieldDesc) ContainingMessage() pref.MessageDescriptor {
461 return fd.parent.(pref.MessageDescriptor)
462}
463func (fd *fieldDesc) Enum() pref.EnumDescriptor { return fd.enumType }
464func (fd *fieldDesc) Message() pref.MessageDescriptor { return fd.messageType }
465func (fd *fieldDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, fd) }
466func (fd *fieldDesc) ProtoType(pref.FieldDescriptor) {}
467
468// TODO: Remove this.
469func (fd *fieldDesc) Oneof() pref.OneofDescriptor { return fd.oneofType }
470func (fd *fieldDesc) Extendee() pref.MessageDescriptor { return nil }
Damien Neil8012b442019-01-18 09:32:24 -0800471
Joe Tsaia2dd2282019-04-10 16:45:04 -0700472func (od *oneofDesc) Options() pref.ProtoMessage {
473 return unmarshalOptions(descopts.Oneof, od.options)
Damien Neil8012b442019-01-18 09:32:24 -0800474}
475func (od *oneofDesc) Fields() pref.FieldDescriptors { return &od.fields }
476func (od *oneofDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, od) }
477func (od *oneofDesc) ProtoType(pref.OneofDescriptor) {}
478
479type (
480 extensionDesc struct {
481 baseDesc
482
483 number pref.FieldNumber
484 extendedType pref.MessageDescriptor
485
Joe Tsai4fddeba2019-03-20 18:29:32 -0700486 legacyDesc *piface.ExtensionDescV1
Joe Tsaiafb455e2019-03-14 16:08:22 -0700487
Damien Neil8012b442019-01-18 09:32:24 -0800488 lazy *extensionLazy // protected by fileDesc.once
489 }
490 extensionLazy struct {
491 typ reflect.Type
492 new func() pref.Value
493 valueOf func(interface{}) pref.Value
494 interfaceOf func(pref.Value) interface{}
495
496 cardinality pref.Cardinality
497 kind pref.Kind
498 // Extensions should not have JSON names, but older versions of protoc
499 // used to set one on the descriptor. Preserve it for now to maintain
500 // the property that protoc 3.6.1 descriptors can round-trip through
501 // this package losslessly.
502 //
503 // TODO: Consider whether to drop JSONName parsing from extensions.
504 hasJSONName bool
505 jsonName string
506 isPacked bool
507 defVal defaultValue
Joe Tsai0fc49f82019-05-01 12:29:25 -0700508 enumType pref.EnumDescriptor
509 messageType pref.MessageDescriptor
Damien Neil8012b442019-01-18 09:32:24 -0800510 options []byte
511 }
512)
513
Joe Tsai0fc49f82019-05-01 12:29:25 -0700514func (xd *extensionDesc) Descriptor() pref.ExtensionDescriptor { return xd }
Damien Neil8012b442019-01-18 09:32:24 -0800515func (xd *extensionDesc) GoType() reflect.Type { return xd.lazyInit().typ }
516func (xd *extensionDesc) New() pref.Value { return xd.lazyInit().new() }
517func (xd *extensionDesc) ValueOf(v interface{}) pref.Value { return xd.lazyInit().valueOf(v) }
518func (xd *extensionDesc) InterfaceOf(v pref.Value) interface{} { return xd.lazyInit().interfaceOf(v) }
Joe Tsaia2dd2282019-04-10 16:45:04 -0700519func (xd *extensionDesc) Options() pref.ProtoMessage {
520 return unmarshalOptions(descopts.Field, xd.lazyInit().options)
Damien Neil8012b442019-01-18 09:32:24 -0800521}
522func (xd *extensionDesc) Number() pref.FieldNumber { return xd.number }
523func (xd *extensionDesc) Cardinality() pref.Cardinality { return xd.lazyInit().cardinality }
524func (xd *extensionDesc) Kind() pref.Kind { return xd.lazyInit().kind }
525func (xd *extensionDesc) HasJSONName() bool { return xd.lazyInit().hasJSONName }
526func (xd *extensionDesc) JSONName() string { return xd.lazyInit().jsonName }
527func (xd *extensionDesc) IsPacked() bool { return xd.lazyInit().isPacked }
Joe Tsaiac31a352019-05-13 14:32:56 -0700528func (xd *extensionDesc) IsExtension() bool { return true }
Damien Neil8012b442019-01-18 09:32:24 -0800529func (xd *extensionDesc) IsWeak() bool { return false }
Joe Tsaiac31a352019-05-13 14:32:56 -0700530func (xd *extensionDesc) IsList() bool { return xd.Cardinality() == pref.Repeated }
Damien Neil8012b442019-01-18 09:32:24 -0800531func (xd *extensionDesc) IsMap() bool { return false }
Joe Tsaiac31a352019-05-13 14:32:56 -0700532func (xd *extensionDesc) MapKey() pref.FieldDescriptor { return nil }
533func (xd *extensionDesc) MapValue() pref.FieldDescriptor { return nil }
Damien Neil8012b442019-01-18 09:32:24 -0800534func (xd *extensionDesc) HasDefault() bool { return xd.lazyInit().defVal.has }
535func (xd *extensionDesc) Default() pref.Value { return xd.lazyInit().defVal.get() }
536func (xd *extensionDesc) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().defVal.enum }
Joe Tsaiac31a352019-05-13 14:32:56 -0700537func (xd *extensionDesc) ContainingOneof() pref.OneofDescriptor { return nil }
538func (xd *extensionDesc) ContainingMessage() pref.MessageDescriptor { return xd.extendedType }
Joe Tsaid24bc722019-04-15 23:39:09 -0700539func (xd *extensionDesc) Enum() pref.EnumDescriptor { return xd.lazyInit().enumType }
540func (xd *extensionDesc) Message() pref.MessageDescriptor { return xd.lazyInit().messageType }
Damien Neil8012b442019-01-18 09:32:24 -0800541func (xd *extensionDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, xd) }
542func (xd *extensionDesc) ProtoType(pref.FieldDescriptor) {}
543func (xd *extensionDesc) ProtoInternal(pragma.DoNotImplement) {}
544func (xd *extensionDesc) lazyInit() *extensionLazy {
545 xd.parentFile.lazyInit() // implicitly initializes extensionLazy
546 return xd.lazy
547}
548
Joe Tsaiafb455e2019-03-14 16:08:22 -0700549// ProtoLegacyExtensionDesc is a pseudo-internal API for allowing the v1 code
550// to be able to retrieve a v1 ExtensionDesc.
Joe Tsaia5f43e82019-04-10 17:11:20 -0700551//
552// WARNING: This method is exempt from the compatibility promise and may be
553// removed in the future without warning.
554func (xd *extensionDesc) ProtoLegacyExtensionDesc() *piface.ExtensionDescV1 {
555 return xd.legacyDesc
556}
Joe Tsaiafb455e2019-03-14 16:08:22 -0700557
Joe Tsaiac31a352019-05-13 14:32:56 -0700558// TODO: Remove this.
559func (xd *extensionDesc) Oneof() pref.OneofDescriptor { return nil }
560func (xd *extensionDesc) Extendee() pref.MessageDescriptor { return xd.extendedType }
561
Damien Neil8012b442019-01-18 09:32:24 -0800562type (
563 serviceDesc struct {
564 baseDesc
565
566 lazy *serviceLazy // protected by fileDesc.once
567 }
568 serviceLazy struct {
569 methods methodDescs
570 options []byte
571 }
572 methodDesc struct {
573 baseDesc
574
575 inputType pref.MessageDescriptor
576 outputType pref.MessageDescriptor
577 isStreamingClient bool
578 isStreamingServer bool
579 options []byte
580 }
581)
582
Joe Tsaia2dd2282019-04-10 16:45:04 -0700583func (sd *serviceDesc) Options() pref.ProtoMessage {
584 return unmarshalOptions(descopts.Service, sd.lazyInit().options)
Damien Neil8012b442019-01-18 09:32:24 -0800585}
586func (sd *serviceDesc) Methods() pref.MethodDescriptors { return &sd.lazyInit().methods }
587func (sd *serviceDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, sd) }
588func (sd *serviceDesc) ProtoType(pref.ServiceDescriptor) {}
589func (sd *serviceDesc) ProtoInternal(pragma.DoNotImplement) {}
590func (sd *serviceDesc) lazyInit() *serviceLazy {
591 sd.parentFile.lazyInit() // implicitly initializes serviceLazy
592 return sd.lazy
593}
594
Joe Tsaia2dd2282019-04-10 16:45:04 -0700595func (md *methodDesc) Options() pref.ProtoMessage {
596 return unmarshalOptions(descopts.Method, md.options)
Damien Neil8012b442019-01-18 09:32:24 -0800597}
Joe Tsaid24bc722019-04-15 23:39:09 -0700598func (md *methodDesc) Input() pref.MessageDescriptor { return md.inputType }
599func (md *methodDesc) Output() pref.MessageDescriptor { return md.outputType }
Damien Neil8012b442019-01-18 09:32:24 -0800600func (md *methodDesc) IsStreamingClient() bool { return md.isStreamingClient }
601func (md *methodDesc) IsStreamingServer() bool { return md.isStreamingServer }
602func (md *methodDesc) Format(s fmt.State, r rune) { pfmt.FormatDesc(s, r, md) }
603func (md *methodDesc) ProtoType(pref.MethodDescriptor) {}
604func (md *methodDesc) ProtoInternal(pragma.DoNotImplement) {}
605
606type baseDesc struct {
607 parentFile *fileDesc
608 parent pref.Descriptor
609 index int
610 fullName
611}
612
Joe Tsai67c1d9b2019-05-12 02:27:46 -0700613func (d *baseDesc) ParentFile() pref.FileDescriptor { return d.parentFile }
Damien Neil8012b442019-01-18 09:32:24 -0800614func (d *baseDesc) Parent() (pref.Descriptor, bool) { return d.parent, true }
615func (d *baseDesc) Index() int { return d.index }
616func (d *baseDesc) Syntax() pref.Syntax { return d.parentFile.Syntax() }
617func (d *baseDesc) IsPlaceholder() bool { return false }
618func (d *baseDesc) ProtoInternal(pragma.DoNotImplement) {}
619
620type fullName struct {
621 shortLen int
622 fullName pref.FullName
623}
624
625func (s *fullName) Name() pref.Name { return pref.Name(s.fullName[len(s.fullName)-s.shortLen:]) }
626func (s *fullName) FullName() pref.FullName { return s.fullName }
627
Joe Tsaia2dd2282019-04-10 16:45:04 -0700628func unmarshalOptions(p pref.ProtoMessage, b []byte) pref.ProtoMessage {
Damien Neil8012b442019-01-18 09:32:24 -0800629 if b != nil {
630 // TODO: Consider caching the unmarshaled options message.
Joe Tsaia2dd2282019-04-10 16:45:04 -0700631 p = reflect.New(reflect.TypeOf(p).Elem()).Interface().(pref.ProtoMessage)
Damien Neil8012b442019-01-18 09:32:24 -0800632 if err := proto.Unmarshal(b, p.(proto.Message)); err != nil {
633 panic(err)
634 }
635 }
636 return p.(proto.Message)
637}