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