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