desc.go

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