blob: a9fe07c216e190a6fc5135c575d6b8739fb69fd3 [file] [log] [blame]
Scott Baker105df152020-04-13 15:55:14 -07001// Copyright 2019 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
5package filedesc
6
7import (
8 "bytes"
9 "fmt"
10 "sync"
11 "sync/atomic"
12
13 "google.golang.org/protobuf/internal/descfmt"
14 "google.golang.org/protobuf/internal/descopts"
15 "google.golang.org/protobuf/internal/encoding/defval"
16 "google.golang.org/protobuf/internal/pragma"
17 "google.golang.org/protobuf/internal/strs"
18 pref "google.golang.org/protobuf/reflect/protoreflect"
19 "google.golang.org/protobuf/reflect/protoregistry"
20)
21
22// The types in this file may have a suffix:
23// • L0: Contains fields common to all descriptors (except File) and
24// must be initialized up front.
25// • L1: Contains fields specific to a descriptor and
26// must be initialized up front.
27// • L2: Contains fields that are lazily initialized when constructing
28// from the raw file descriptor. When constructing as a literal, the L2
29// fields must be initialized up front.
30//
31// The types are exported so that packages like reflect/protodesc can
32// directly construct descriptors.
33
34type (
35 File struct {
36 fileRaw
37 L1 FileL1
38
39 once uint32 // atomically set if L2 is valid
40 mu sync.Mutex // protects L2
41 L2 *FileL2
42 }
43 FileL1 struct {
44 Syntax pref.Syntax
45 Path string
46 Package pref.FullName
47
48 Enums Enums
49 Messages Messages
50 Extensions Extensions
51 Services Services
52 }
53 FileL2 struct {
54 Options func() pref.ProtoMessage
55 Imports FileImports
56 Locations SourceLocations
57 }
58)
59
60func (fd *File) ParentFile() pref.FileDescriptor { return fd }
61func (fd *File) Parent() pref.Descriptor { return nil }
62func (fd *File) Index() int { return 0 }
63func (fd *File) Syntax() pref.Syntax { return fd.L1.Syntax }
64func (fd *File) Name() pref.Name { return fd.L1.Package.Name() }
65func (fd *File) FullName() pref.FullName { return fd.L1.Package }
66func (fd *File) IsPlaceholder() bool { return false }
67func (fd *File) Options() pref.ProtoMessage {
68 if f := fd.lazyInit().Options; f != nil {
69 return f()
70 }
71 return descopts.File
72}
73func (fd *File) Path() string { return fd.L1.Path }
74func (fd *File) Package() pref.FullName { return fd.L1.Package }
75func (fd *File) Imports() pref.FileImports { return &fd.lazyInit().Imports }
76func (fd *File) Enums() pref.EnumDescriptors { return &fd.L1.Enums }
77func (fd *File) Messages() pref.MessageDescriptors { return &fd.L1.Messages }
78func (fd *File) Extensions() pref.ExtensionDescriptors { return &fd.L1.Extensions }
79func (fd *File) Services() pref.ServiceDescriptors { return &fd.L1.Services }
80func (fd *File) SourceLocations() pref.SourceLocations { return &fd.L2.Locations }
81func (fd *File) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) }
82func (fd *File) ProtoType(pref.FileDescriptor) {}
83func (fd *File) ProtoInternal(pragma.DoNotImplement) {}
84
85func (fd *File) lazyInit() *FileL2 {
86 if atomic.LoadUint32(&fd.once) == 0 {
87 fd.lazyInitOnce()
88 }
89 return fd.L2
90}
91
92func (fd *File) lazyInitOnce() {
93 fd.mu.Lock()
94 if fd.L2 == nil {
95 fd.lazyRawInit() // recursively initializes all L2 structures
96 }
97 atomic.StoreUint32(&fd.once, 1)
98 fd.mu.Unlock()
99}
100
101// ProtoLegacyRawDesc is a pseudo-internal API for allowing the v1 code
102// to be able to retrieve the raw descriptor.
103//
104// WARNING: This method is exempt from the compatibility promise and may be
105// removed in the future without warning.
106func (fd *File) ProtoLegacyRawDesc() []byte {
107 return fd.builder.RawDescriptor
108}
109
110// GoPackagePath is a pseudo-internal API for determining the Go package path
111// that this file descriptor is declared in.
112//
113// WARNING: This method is exempt from the compatibility promise and may be
114// removed in the future without warning.
115func (fd *File) GoPackagePath() string {
116 return fd.builder.GoPackagePath
117}
118
119type (
120 Enum struct {
121 Base
122 L1 EnumL1
123 L2 *EnumL2 // protected by fileDesc.once
124 }
125 EnumL1 struct {
126 eagerValues bool // controls whether EnumL2.Values is already populated
127 }
128 EnumL2 struct {
129 Options func() pref.ProtoMessage
130 Values EnumValues
131 ReservedNames Names
132 ReservedRanges EnumRanges
133 }
134
135 EnumValue struct {
136 Base
137 L1 EnumValueL1
138 }
139 EnumValueL1 struct {
140 Options func() pref.ProtoMessage
141 Number pref.EnumNumber
142 }
143)
144
145func (ed *Enum) Options() pref.ProtoMessage {
146 if f := ed.lazyInit().Options; f != nil {
147 return f()
148 }
149 return descopts.Enum
150}
151func (ed *Enum) Values() pref.EnumValueDescriptors {
152 if ed.L1.eagerValues {
153 return &ed.L2.Values
154 }
155 return &ed.lazyInit().Values
156}
157func (ed *Enum) ReservedNames() pref.Names { return &ed.lazyInit().ReservedNames }
158func (ed *Enum) ReservedRanges() pref.EnumRanges { return &ed.lazyInit().ReservedRanges }
159func (ed *Enum) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) }
160func (ed *Enum) ProtoType(pref.EnumDescriptor) {}
161func (ed *Enum) lazyInit() *EnumL2 {
162 ed.L0.ParentFile.lazyInit() // implicitly initializes L2
163 return ed.L2
164}
165
166func (ed *EnumValue) Options() pref.ProtoMessage {
167 if f := ed.L1.Options; f != nil {
168 return f()
169 }
170 return descopts.EnumValue
171}
172func (ed *EnumValue) Number() pref.EnumNumber { return ed.L1.Number }
173func (ed *EnumValue) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) }
174func (ed *EnumValue) ProtoType(pref.EnumValueDescriptor) {}
175
176type (
177 Message struct {
178 Base
179 L1 MessageL1
180 L2 *MessageL2 // protected by fileDesc.once
181 }
182 MessageL1 struct {
183 Enums Enums
184 Messages Messages
185 Extensions Extensions
186 IsMapEntry bool // promoted from google.protobuf.MessageOptions
187 IsMessageSet bool // promoted from google.protobuf.MessageOptions
188 }
189 MessageL2 struct {
190 Options func() pref.ProtoMessage
191 Fields Fields
192 Oneofs Oneofs
193 ReservedNames Names
194 ReservedRanges FieldRanges
195 RequiredNumbers FieldNumbers // must be consistent with Fields.Cardinality
196 ExtensionRanges FieldRanges
197 ExtensionRangeOptions []func() pref.ProtoMessage // must be same length as ExtensionRanges
198 }
199
200 Field struct {
201 Base
202 L1 FieldL1
203 }
204 FieldL1 struct {
205 Options func() pref.ProtoMessage
206 Number pref.FieldNumber
207 Cardinality pref.Cardinality // must be consistent with Message.RequiredNumbers
208 Kind pref.Kind
209 JSONName jsonName
210 IsWeak bool // promoted from google.protobuf.FieldOptions
211 HasPacked bool // promoted from google.protobuf.FieldOptions
212 IsPacked bool // promoted from google.protobuf.FieldOptions
213 HasEnforceUTF8 bool // promoted from google.protobuf.FieldOptions
214 EnforceUTF8 bool // promoted from google.protobuf.FieldOptions
215 Default defaultValue
216 ContainingOneof pref.OneofDescriptor // must be consistent with Message.Oneofs.Fields
217 Enum pref.EnumDescriptor
218 Message pref.MessageDescriptor
219 }
220
221 Oneof struct {
222 Base
223 L1 OneofL1
224 }
225 OneofL1 struct {
226 Options func() pref.ProtoMessage
227 Fields OneofFields // must be consistent with Message.Fields.ContainingOneof
228 }
229)
230
231func (md *Message) Options() pref.ProtoMessage {
232 if f := md.lazyInit().Options; f != nil {
233 return f()
234 }
235 return descopts.Message
236}
237func (md *Message) IsMapEntry() bool { return md.L1.IsMapEntry }
238func (md *Message) Fields() pref.FieldDescriptors { return &md.lazyInit().Fields }
239func (md *Message) Oneofs() pref.OneofDescriptors { return &md.lazyInit().Oneofs }
240func (md *Message) ReservedNames() pref.Names { return &md.lazyInit().ReservedNames }
241func (md *Message) ReservedRanges() pref.FieldRanges { return &md.lazyInit().ReservedRanges }
242func (md *Message) RequiredNumbers() pref.FieldNumbers { return &md.lazyInit().RequiredNumbers }
243func (md *Message) ExtensionRanges() pref.FieldRanges { return &md.lazyInit().ExtensionRanges }
244func (md *Message) ExtensionRangeOptions(i int) pref.ProtoMessage {
245 if f := md.lazyInit().ExtensionRangeOptions[i]; f != nil {
246 return f()
247 }
248 return descopts.ExtensionRange
249}
250func (md *Message) Enums() pref.EnumDescriptors { return &md.L1.Enums }
251func (md *Message) Messages() pref.MessageDescriptors { return &md.L1.Messages }
252func (md *Message) Extensions() pref.ExtensionDescriptors { return &md.L1.Extensions }
253func (md *Message) ProtoType(pref.MessageDescriptor) {}
254func (md *Message) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) }
255func (md *Message) lazyInit() *MessageL2 {
256 md.L0.ParentFile.lazyInit() // implicitly initializes L2
257 return md.L2
258}
259
260// IsMessageSet is a pseudo-internal API for checking whether a message
261// should serialize in the proto1 message format.
262//
263// WARNING: This method is exempt from the compatibility promise and may be
264// removed in the future without warning.
265func (md *Message) IsMessageSet() bool {
266 return md.L1.IsMessageSet
267}
268
269func (fd *Field) Options() pref.ProtoMessage {
270 if f := fd.L1.Options; f != nil {
271 return f()
272 }
273 return descopts.Field
274}
275func (fd *Field) Number() pref.FieldNumber { return fd.L1.Number }
276func (fd *Field) Cardinality() pref.Cardinality { return fd.L1.Cardinality }
277func (fd *Field) Kind() pref.Kind { return fd.L1.Kind }
278func (fd *Field) HasJSONName() bool { return fd.L1.JSONName.has }
279func (fd *Field) JSONName() string { return fd.L1.JSONName.get(fd) }
280func (fd *Field) IsPacked() bool {
281 if !fd.L1.HasPacked && fd.L0.ParentFile.L1.Syntax != pref.Proto2 && fd.L1.Cardinality == pref.Repeated {
282 switch fd.L1.Kind {
283 case pref.StringKind, pref.BytesKind, pref.MessageKind, pref.GroupKind:
284 default:
285 return true
286 }
287 }
288 return fd.L1.IsPacked
289}
290func (fd *Field) IsExtension() bool { return false }
291func (fd *Field) IsWeak() bool { return fd.L1.IsWeak }
292func (fd *Field) IsList() bool { return fd.Cardinality() == pref.Repeated && !fd.IsMap() }
293func (fd *Field) IsMap() bool { return fd.Message() != nil && fd.Message().IsMapEntry() }
294func (fd *Field) MapKey() pref.FieldDescriptor {
295 if !fd.IsMap() {
296 return nil
297 }
298 return fd.Message().Fields().ByNumber(1)
299}
300func (fd *Field) MapValue() pref.FieldDescriptor {
301 if !fd.IsMap() {
302 return nil
303 }
304 return fd.Message().Fields().ByNumber(2)
305}
306func (fd *Field) HasDefault() bool { return fd.L1.Default.has }
307func (fd *Field) Default() pref.Value { return fd.L1.Default.get(fd) }
308func (fd *Field) DefaultEnumValue() pref.EnumValueDescriptor { return fd.L1.Default.enum }
309func (fd *Field) ContainingOneof() pref.OneofDescriptor { return fd.L1.ContainingOneof }
310func (fd *Field) ContainingMessage() pref.MessageDescriptor {
311 return fd.L0.Parent.(pref.MessageDescriptor)
312}
313func (fd *Field) Enum() pref.EnumDescriptor {
314 return fd.L1.Enum
315}
316func (fd *Field) Message() pref.MessageDescriptor {
317 if fd.L1.IsWeak {
318 if d, _ := protoregistry.GlobalFiles.FindDescriptorByName(fd.L1.Message.FullName()); d != nil {
319 return d.(pref.MessageDescriptor)
320 }
321 }
322 return fd.L1.Message
323}
324func (fd *Field) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) }
325func (fd *Field) ProtoType(pref.FieldDescriptor) {}
326
327// EnforceUTF8 is a pseudo-internal API to determine whether to enforce UTF-8
328// validation for the string field. This exists for Google-internal use only
329// since proto3 did not enforce UTF-8 validity prior to the open-source release.
330// If this method does not exist, the default is to enforce valid UTF-8.
331//
332// WARNING: This method is exempt from the compatibility promise and may be
333// removed in the future without warning.
334func (fd *Field) EnforceUTF8() bool {
335 if fd.L1.HasEnforceUTF8 {
336 return fd.L1.EnforceUTF8
337 }
338 return fd.L0.ParentFile.L1.Syntax == pref.Proto3
339}
340
341func (od *Oneof) Options() pref.ProtoMessage {
342 if f := od.L1.Options; f != nil {
343 return f()
344 }
345 return descopts.Oneof
346}
347func (od *Oneof) Fields() pref.FieldDescriptors { return &od.L1.Fields }
348func (od *Oneof) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, od) }
349func (od *Oneof) ProtoType(pref.OneofDescriptor) {}
350
351type (
352 Extension struct {
353 Base
354 L1 ExtensionL1
355 L2 *ExtensionL2 // protected by fileDesc.once
356 }
357 ExtensionL1 struct {
358 Number pref.FieldNumber
359 Extendee pref.MessageDescriptor
360 Cardinality pref.Cardinality
361 Kind pref.Kind
362 }
363 ExtensionL2 struct {
364 Options func() pref.ProtoMessage
365 JSONName jsonName
366 IsPacked bool // promoted from google.protobuf.FieldOptions
367 Default defaultValue
368 Enum pref.EnumDescriptor
369 Message pref.MessageDescriptor
370 }
371)
372
373func (xd *Extension) Options() pref.ProtoMessage {
374 if f := xd.lazyInit().Options; f != nil {
375 return f()
376 }
377 return descopts.Field
378}
379func (xd *Extension) Number() pref.FieldNumber { return xd.L1.Number }
380func (xd *Extension) Cardinality() pref.Cardinality { return xd.L1.Cardinality }
381func (xd *Extension) Kind() pref.Kind { return xd.L1.Kind }
382func (xd *Extension) HasJSONName() bool { return xd.lazyInit().JSONName.has }
383func (xd *Extension) JSONName() string { return xd.lazyInit().JSONName.get(xd) }
384func (xd *Extension) IsPacked() bool { return xd.lazyInit().IsPacked }
385func (xd *Extension) IsExtension() bool { return true }
386func (xd *Extension) IsWeak() bool { return false }
387func (xd *Extension) IsList() bool { return xd.Cardinality() == pref.Repeated }
388func (xd *Extension) IsMap() bool { return false }
389func (xd *Extension) MapKey() pref.FieldDescriptor { return nil }
390func (xd *Extension) MapValue() pref.FieldDescriptor { return nil }
391func (xd *Extension) HasDefault() bool { return xd.lazyInit().Default.has }
392func (xd *Extension) Default() pref.Value { return xd.lazyInit().Default.get(xd) }
393func (xd *Extension) DefaultEnumValue() pref.EnumValueDescriptor { return xd.lazyInit().Default.enum }
394func (xd *Extension) ContainingOneof() pref.OneofDescriptor { return nil }
395func (xd *Extension) ContainingMessage() pref.MessageDescriptor { return xd.L1.Extendee }
396func (xd *Extension) Enum() pref.EnumDescriptor { return xd.lazyInit().Enum }
397func (xd *Extension) Message() pref.MessageDescriptor { return xd.lazyInit().Message }
398func (xd *Extension) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, xd) }
399func (xd *Extension) ProtoType(pref.FieldDescriptor) {}
400func (xd *Extension) ProtoInternal(pragma.DoNotImplement) {}
401func (xd *Extension) lazyInit() *ExtensionL2 {
402 xd.L0.ParentFile.lazyInit() // implicitly initializes L2
403 return xd.L2
404}
405
406type (
407 Service struct {
408 Base
409 L1 ServiceL1
410 L2 *ServiceL2 // protected by fileDesc.once
411 }
412 ServiceL1 struct{}
413 ServiceL2 struct {
414 Options func() pref.ProtoMessage
415 Methods Methods
416 }
417
418 Method struct {
419 Base
420 L1 MethodL1
421 }
422 MethodL1 struct {
423 Options func() pref.ProtoMessage
424 Input pref.MessageDescriptor
425 Output pref.MessageDescriptor
426 IsStreamingClient bool
427 IsStreamingServer bool
428 }
429)
430
431func (sd *Service) Options() pref.ProtoMessage {
432 if f := sd.lazyInit().Options; f != nil {
433 return f()
434 }
435 return descopts.Service
436}
437func (sd *Service) Methods() pref.MethodDescriptors { return &sd.lazyInit().Methods }
438func (sd *Service) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, sd) }
439func (sd *Service) ProtoType(pref.ServiceDescriptor) {}
440func (sd *Service) ProtoInternal(pragma.DoNotImplement) {}
441func (sd *Service) lazyInit() *ServiceL2 {
442 sd.L0.ParentFile.lazyInit() // implicitly initializes L2
443 return sd.L2
444}
445
446func (md *Method) Options() pref.ProtoMessage {
447 if f := md.L1.Options; f != nil {
448 return f()
449 }
450 return descopts.Method
451}
452func (md *Method) Input() pref.MessageDescriptor { return md.L1.Input }
453func (md *Method) Output() pref.MessageDescriptor { return md.L1.Output }
454func (md *Method) IsStreamingClient() bool { return md.L1.IsStreamingClient }
455func (md *Method) IsStreamingServer() bool { return md.L1.IsStreamingServer }
456func (md *Method) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) }
457func (md *Method) ProtoType(pref.MethodDescriptor) {}
458func (md *Method) ProtoInternal(pragma.DoNotImplement) {}
459
460// Surrogate files are can be used to create standalone descriptors
461// where the syntax is only information derived from the parent file.
462var (
463 SurrogateProto2 = &File{L1: FileL1{Syntax: pref.Proto2}, L2: &FileL2{}}
464 SurrogateProto3 = &File{L1: FileL1{Syntax: pref.Proto3}, L2: &FileL2{}}
465)
466
467type (
468 Base struct {
469 L0 BaseL0
470 }
471 BaseL0 struct {
472 FullName pref.FullName // must be populated
473 ParentFile *File // must be populated
474 Parent pref.Descriptor
475 Index int
476 }
477)
478
479func (d *Base) Name() pref.Name { return d.L0.FullName.Name() }
480func (d *Base) FullName() pref.FullName { return d.L0.FullName }
481func (d *Base) ParentFile() pref.FileDescriptor {
482 if d.L0.ParentFile == SurrogateProto2 || d.L0.ParentFile == SurrogateProto3 {
483 return nil // surrogate files are not real parents
484 }
485 return d.L0.ParentFile
486}
487func (d *Base) Parent() pref.Descriptor { return d.L0.Parent }
488func (d *Base) Index() int { return d.L0.Index }
489func (d *Base) Syntax() pref.Syntax { return d.L0.ParentFile.Syntax() }
490func (d *Base) IsPlaceholder() bool { return false }
491func (d *Base) ProtoInternal(pragma.DoNotImplement) {}
492
493type jsonName struct {
494 has bool
495 once sync.Once
496 name string
497}
498
499// Init initializes the name. It is exported for use by other internal packages.
500func (js *jsonName) Init(s string) {
501 js.has = true
502 js.name = s
503}
504
505func (js *jsonName) get(fd pref.FieldDescriptor) string {
506 if !js.has {
507 js.once.Do(func() {
508 js.name = strs.JSONCamelCase(string(fd.Name()))
509 })
510 }
511 return js.name
512}
513
514func DefaultValue(v pref.Value, ev pref.EnumValueDescriptor) defaultValue {
515 dv := defaultValue{has: v.IsValid(), val: v, enum: ev}
516 if b, ok := v.Interface().([]byte); ok {
517 // Store a copy of the default bytes, so that we can detect
518 // accidental mutations of the original value.
519 dv.bytes = append([]byte(nil), b...)
520 }
521 return dv
522}
523
524func unmarshalDefault(b []byte, k pref.Kind, pf *File, ed pref.EnumDescriptor) defaultValue {
525 var evs pref.EnumValueDescriptors
526 if k == pref.EnumKind {
527 // If the enum is declared within the same file, be careful not to
528 // blindly call the Values method, lest we bind ourselves in a deadlock.
529 if e, ok := ed.(*Enum); ok && e.L0.ParentFile == pf {
530 evs = &e.L2.Values
531 } else {
532 evs = ed.Values()
533 }
534
535 // If we are unable to resolve the enum dependency, use a placeholder
536 // enum value since we will not be able to parse the default value.
537 if ed.IsPlaceholder() && pref.Name(b).IsValid() {
538 v := pref.ValueOfEnum(0)
539 ev := PlaceholderEnumValue(ed.FullName().Parent().Append(pref.Name(b)))
540 return DefaultValue(v, ev)
541 }
542 }
543
544 v, ev, err := defval.Unmarshal(string(b), k, evs, defval.Descriptor)
545 if err != nil {
546 panic(err)
547 }
548 return DefaultValue(v, ev)
549}
550
551type defaultValue struct {
552 has bool
553 val pref.Value
554 enum pref.EnumValueDescriptor
555 bytes []byte
556}
557
558func (dv *defaultValue) get(fd pref.FieldDescriptor) pref.Value {
559 // Return the zero value as the default if unpopulated.
560 if !dv.has {
561 if fd.Cardinality() == pref.Repeated {
562 return pref.Value{}
563 }
564 switch fd.Kind() {
565 case pref.BoolKind:
566 return pref.ValueOfBool(false)
567 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
568 return pref.ValueOfInt32(0)
569 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
570 return pref.ValueOfInt64(0)
571 case pref.Uint32Kind, pref.Fixed32Kind:
572 return pref.ValueOfUint32(0)
573 case pref.Uint64Kind, pref.Fixed64Kind:
574 return pref.ValueOfUint64(0)
575 case pref.FloatKind:
576 return pref.ValueOfFloat32(0)
577 case pref.DoubleKind:
578 return pref.ValueOfFloat64(0)
579 case pref.StringKind:
580 return pref.ValueOfString("")
581 case pref.BytesKind:
582 return pref.ValueOfBytes(nil)
583 case pref.EnumKind:
584 if evs := fd.Enum().Values(); evs.Len() > 0 {
585 return pref.ValueOfEnum(evs.Get(0).Number())
586 }
587 return pref.ValueOfEnum(0)
588 }
589 }
590
591 if len(dv.bytes) > 0 && !bytes.Equal(dv.bytes, dv.val.Bytes()) {
592 // TODO: Avoid panic if we're running with the race detector
593 // and instead spawn a goroutine that periodically resets
594 // this value back to the original to induce a race.
595 panic("detected mutation on the default bytes")
596 }
597 return dv.val
598}