blob: dbcf90b871fd710449022f4f55c4dbaecf557a93 [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// 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"
Abhay Kumara2ae5992025-11-10 14:02:24 +000010 "strings"
khenaidood948f772021-08-11 17:49:24 -040011 "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"
mgouda64be8822025-05-30 10:44:00 +053021 "google.golang.org/protobuf/reflect/protoreflect"
khenaidood948f772021-08-11 17:49:24 -040022)
23
mgouda64be8822025-05-30 10:44:00 +053024// 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
Abhay Kumara2ae5992025-11-10 14:02:24 +000034 Edition2024 Edition = 1001
mgouda64be8822025-05-30 10:44:00 +053035 EditionUnsupported Edition = 100000
36)
37
khenaidood948f772021-08-11 17:49:24 -040038// 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
mgouda64be8822025-05-30 10:44:00 +053042// 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.
khenaidood948f772021-08-11 17:49:24 -040045// • 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 {
mgouda64be8822025-05-30 10:44:00 +053062 Syntax protoreflect.Syntax
63 Edition Edition // Only used if Syntax == Editions
khenaidood948f772021-08-11 17:49:24 -040064 Path string
mgouda64be8822025-05-30 10:44:00 +053065 Package protoreflect.FullName
khenaidood948f772021-08-11 17:49:24 -040066
67 Enums Enums
68 Messages Messages
69 Extensions Extensions
70 Services Services
mgouda64be8822025-05-30 10:44:00 +053071
72 EditionFeatures EditionFeatures
khenaidood948f772021-08-11 17:49:24 -040073 }
74 FileL2 struct {
Abhay Kumara2ae5992025-11-10 14:02:24 +000075 Options func() protoreflect.ProtoMessage
76 Imports FileImports
77 OptionImports func() protoreflect.FileImports
78 Locations SourceLocations
khenaidood948f772021-08-11 17:49:24 -040079 }
mgouda64be8822025-05-30 10:44:00 +053080
Abhay Kumara2ae5992025-11-10 14:02:24 +000081 // EditionFeatures is a frequently-instantiated struct, so please take care
82 // to minimize padding when adding new fields to this struct (add them in
83 // the right place/order).
mgouda64be8822025-05-30 10:44:00 +053084 EditionFeatures struct {
Abhay Kumara2ae5992025-11-10 14:02:24 +000085 // StripEnumPrefix determines if the plugin generates enum value
86 // constants as-is, with their prefix stripped, or both variants.
87 StripEnumPrefix int
88
mgouda64be8822025-05-30 10:44:00 +053089 // IsFieldPresence is true if field_presence is EXPLICIT
90 // https://protobuf.dev/editions/features/#field_presence
91 IsFieldPresence bool
Abhay Kumara2ae5992025-11-10 14:02:24 +000092
mgouda64be8822025-05-30 10:44:00 +053093 // IsFieldPresence is true if field_presence is LEGACY_REQUIRED
94 // https://protobuf.dev/editions/features/#field_presence
95 IsLegacyRequired bool
Abhay Kumara2ae5992025-11-10 14:02:24 +000096
mgouda64be8822025-05-30 10:44:00 +053097 // IsOpenEnum is true if enum_type is OPEN
98 // https://protobuf.dev/editions/features/#enum_type
99 IsOpenEnum bool
Abhay Kumara2ae5992025-11-10 14:02:24 +0000100
mgouda64be8822025-05-30 10:44:00 +0530101 // IsPacked is true if repeated_field_encoding is PACKED
102 // https://protobuf.dev/editions/features/#repeated_field_encoding
103 IsPacked bool
Abhay Kumara2ae5992025-11-10 14:02:24 +0000104
mgouda64be8822025-05-30 10:44:00 +0530105 // IsUTF8Validated is true if utf_validation is VERIFY
106 // https://protobuf.dev/editions/features/#utf8_validation
107 IsUTF8Validated bool
Abhay Kumara2ae5992025-11-10 14:02:24 +0000108
mgouda64be8822025-05-30 10:44:00 +0530109 // IsDelimitedEncoded is true if message_encoding is DELIMITED
110 // https://protobuf.dev/editions/features/#message_encoding
111 IsDelimitedEncoded bool
Abhay Kumara2ae5992025-11-10 14:02:24 +0000112
mgouda64be8822025-05-30 10:44:00 +0530113 // IsJSONCompliant is true if json_format is ALLOW
114 // https://protobuf.dev/editions/features/#json_format
115 IsJSONCompliant bool
Abhay Kumara2ae5992025-11-10 14:02:24 +0000116
mgouda64be8822025-05-30 10:44:00 +0530117 // GenerateLegacyUnmarshalJSON determines if the plugin generates the
118 // UnmarshalJSON([]byte) error method for enums.
119 GenerateLegacyUnmarshalJSON bool
Abhay Kumara2ae5992025-11-10 14:02:24 +0000120 // APILevel controls which API (Open, Hybrid or Opaque) should be used
121 // for generated code (.pb.go files).
122 APILevel int
mgouda64be8822025-05-30 10:44:00 +0530123 }
khenaidood948f772021-08-11 17:49:24 -0400124)
125
mgouda64be8822025-05-30 10:44:00 +0530126func (fd *File) ParentFile() protoreflect.FileDescriptor { return fd }
127func (fd *File) Parent() protoreflect.Descriptor { return nil }
128func (fd *File) Index() int { return 0 }
129func (fd *File) Syntax() protoreflect.Syntax { return fd.L1.Syntax }
130func (fd *File) Name() protoreflect.Name { return fd.L1.Package.Name() }
131func (fd *File) FullName() protoreflect.FullName { return fd.L1.Package }
132func (fd *File) IsPlaceholder() bool { return false }
133func (fd *File) Options() protoreflect.ProtoMessage {
khenaidood948f772021-08-11 17:49:24 -0400134 if f := fd.lazyInit().Options; f != nil {
135 return f()
136 }
137 return descopts.File
138}
mgouda64be8822025-05-30 10:44:00 +0530139func (fd *File) Path() string { return fd.L1.Path }
140func (fd *File) Package() protoreflect.FullName { return fd.L1.Package }
141func (fd *File) Imports() protoreflect.FileImports { return &fd.lazyInit().Imports }
142func (fd *File) Enums() protoreflect.EnumDescriptors { return &fd.L1.Enums }
143func (fd *File) Messages() protoreflect.MessageDescriptors { return &fd.L1.Messages }
144func (fd *File) Extensions() protoreflect.ExtensionDescriptors { return &fd.L1.Extensions }
145func (fd *File) Services() protoreflect.ServiceDescriptors { return &fd.L1.Services }
146func (fd *File) SourceLocations() protoreflect.SourceLocations { return &fd.lazyInit().Locations }
147func (fd *File) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) }
148func (fd *File) ProtoType(protoreflect.FileDescriptor) {}
149func (fd *File) ProtoInternal(pragma.DoNotImplement) {}
khenaidood948f772021-08-11 17:49:24 -0400150
Abhay Kumara2ae5992025-11-10 14:02:24 +0000151// The next two are not part of the FileDescriptor interface. They are just used to reconstruct
152// the original FileDescriptor proto.
153func (fd *File) Edition() int32 { return int32(fd.L1.Edition) }
154func (fd *File) OptionImports() protoreflect.FileImports {
155 if f := fd.lazyInit().OptionImports; f != nil {
156 return f()
157 }
158 return emptyFiles
159}
160
khenaidood948f772021-08-11 17:49:24 -0400161func (fd *File) lazyInit() *FileL2 {
162 if atomic.LoadUint32(&fd.once) == 0 {
163 fd.lazyInitOnce()
164 }
165 return fd.L2
166}
167
168func (fd *File) lazyInitOnce() {
169 fd.mu.Lock()
170 if fd.L2 == nil {
171 fd.lazyRawInit() // recursively initializes all L2 structures
172 }
173 atomic.StoreUint32(&fd.once, 1)
174 fd.mu.Unlock()
175}
176
177// GoPackagePath is a pseudo-internal API for determining the Go package path
178// that this file descriptor is declared in.
179//
180// WARNING: This method is exempt from the compatibility promise and may be
181// removed in the future without warning.
182func (fd *File) GoPackagePath() string {
183 return fd.builder.GoPackagePath
184}
185
186type (
187 Enum struct {
188 Base
189 L1 EnumL1
190 L2 *EnumL2 // protected by fileDesc.once
191 }
192 EnumL1 struct {
mgouda64be8822025-05-30 10:44:00 +0530193 EditionFeatures EditionFeatures
Abhay Kumara2ae5992025-11-10 14:02:24 +0000194 Visibility int32
195 eagerValues bool // controls whether EnumL2.Values is already populated
khenaidood948f772021-08-11 17:49:24 -0400196 }
197 EnumL2 struct {
mgouda64be8822025-05-30 10:44:00 +0530198 Options func() protoreflect.ProtoMessage
khenaidood948f772021-08-11 17:49:24 -0400199 Values EnumValues
200 ReservedNames Names
201 ReservedRanges EnumRanges
202 }
203
204 EnumValue struct {
205 Base
206 L1 EnumValueL1
207 }
208 EnumValueL1 struct {
mgouda64be8822025-05-30 10:44:00 +0530209 Options func() protoreflect.ProtoMessage
210 Number protoreflect.EnumNumber
khenaidood948f772021-08-11 17:49:24 -0400211 }
212)
213
mgouda64be8822025-05-30 10:44:00 +0530214func (ed *Enum) Options() protoreflect.ProtoMessage {
khenaidood948f772021-08-11 17:49:24 -0400215 if f := ed.lazyInit().Options; f != nil {
216 return f()
217 }
218 return descopts.Enum
219}
mgouda64be8822025-05-30 10:44:00 +0530220func (ed *Enum) Values() protoreflect.EnumValueDescriptors {
khenaidood948f772021-08-11 17:49:24 -0400221 if ed.L1.eagerValues {
222 return &ed.L2.Values
223 }
224 return &ed.lazyInit().Values
225}
mgouda64be8822025-05-30 10:44:00 +0530226func (ed *Enum) ReservedNames() protoreflect.Names { return &ed.lazyInit().ReservedNames }
227func (ed *Enum) ReservedRanges() protoreflect.EnumRanges { return &ed.lazyInit().ReservedRanges }
228func (ed *Enum) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) }
229func (ed *Enum) ProtoType(protoreflect.EnumDescriptor) {}
Abhay Kumara2ae5992025-11-10 14:02:24 +0000230
231// This is not part of the EnumDescriptor interface. It is just used to reconstruct
232// the original FileDescriptor proto.
233func (ed *Enum) Visibility() int32 { return ed.L1.Visibility }
234
khenaidood948f772021-08-11 17:49:24 -0400235func (ed *Enum) lazyInit() *EnumL2 {
236 ed.L0.ParentFile.lazyInit() // implicitly initializes L2
237 return ed.L2
238}
Abhay Kumara2ae5992025-11-10 14:02:24 +0000239func (ed *Enum) IsClosed() bool {
240 return !ed.L1.EditionFeatures.IsOpenEnum
241}
khenaidood948f772021-08-11 17:49:24 -0400242
mgouda64be8822025-05-30 10:44:00 +0530243func (ed *EnumValue) Options() protoreflect.ProtoMessage {
khenaidood948f772021-08-11 17:49:24 -0400244 if f := ed.L1.Options; f != nil {
245 return f()
246 }
247 return descopts.EnumValue
248}
mgouda64be8822025-05-30 10:44:00 +0530249func (ed *EnumValue) Number() protoreflect.EnumNumber { return ed.L1.Number }
250func (ed *EnumValue) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) }
251func (ed *EnumValue) ProtoType(protoreflect.EnumValueDescriptor) {}
khenaidood948f772021-08-11 17:49:24 -0400252
253type (
254 Message struct {
255 Base
256 L1 MessageL1
257 L2 *MessageL2 // protected by fileDesc.once
258 }
259 MessageL1 struct {
Abhay Kumara2ae5992025-11-10 14:02:24 +0000260 Enums Enums
261 Messages Messages
262 Extensions Extensions
mgouda64be8822025-05-30 10:44:00 +0530263 EditionFeatures EditionFeatures
Abhay Kumara2ae5992025-11-10 14:02:24 +0000264 Visibility int32
265 IsMapEntry bool // promoted from google.protobuf.MessageOptions
266 IsMessageSet bool // promoted from google.protobuf.MessageOptions
khenaidood948f772021-08-11 17:49:24 -0400267 }
268 MessageL2 struct {
mgouda64be8822025-05-30 10:44:00 +0530269 Options func() protoreflect.ProtoMessage
khenaidood948f772021-08-11 17:49:24 -0400270 Fields Fields
271 Oneofs Oneofs
272 ReservedNames Names
273 ReservedRanges FieldRanges
274 RequiredNumbers FieldNumbers // must be consistent with Fields.Cardinality
275 ExtensionRanges FieldRanges
mgouda64be8822025-05-30 10:44:00 +0530276 ExtensionRangeOptions []func() protoreflect.ProtoMessage // must be same length as ExtensionRanges
khenaidood948f772021-08-11 17:49:24 -0400277 }
278
279 Field struct {
280 Base
281 L1 FieldL1
282 }
283 FieldL1 struct {
mgouda64be8822025-05-30 10:44:00 +0530284 Options func() protoreflect.ProtoMessage
285 Number protoreflect.FieldNumber
286 Cardinality protoreflect.Cardinality // must be consistent with Message.RequiredNumbers
287 Kind protoreflect.Kind
khenaidood948f772021-08-11 17:49:24 -0400288 StringName stringName
289 IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto
Abhay Kumara2ae5992025-11-10 14:02:24 +0000290 IsLazy bool // promoted from google.protobuf.FieldOptions
khenaidood948f772021-08-11 17:49:24 -0400291 Default defaultValue
mgouda64be8822025-05-30 10:44:00 +0530292 ContainingOneof protoreflect.OneofDescriptor // must be consistent with Message.Oneofs.Fields
293 Enum protoreflect.EnumDescriptor
294 Message protoreflect.MessageDescriptor
295
296 EditionFeatures EditionFeatures
khenaidood948f772021-08-11 17:49:24 -0400297 }
298
299 Oneof struct {
300 Base
301 L1 OneofL1
302 }
303 OneofL1 struct {
mgouda64be8822025-05-30 10:44:00 +0530304 Options func() protoreflect.ProtoMessage
khenaidood948f772021-08-11 17:49:24 -0400305 Fields OneofFields // must be consistent with Message.Fields.ContainingOneof
mgouda64be8822025-05-30 10:44:00 +0530306
307 EditionFeatures EditionFeatures
khenaidood948f772021-08-11 17:49:24 -0400308 }
309)
310
mgouda64be8822025-05-30 10:44:00 +0530311func (md *Message) Options() protoreflect.ProtoMessage {
khenaidood948f772021-08-11 17:49:24 -0400312 if f := md.lazyInit().Options; f != nil {
313 return f()
314 }
315 return descopts.Message
316}
mgouda64be8822025-05-30 10:44:00 +0530317func (md *Message) IsMapEntry() bool { return md.L1.IsMapEntry }
318func (md *Message) Fields() protoreflect.FieldDescriptors { return &md.lazyInit().Fields }
319func (md *Message) Oneofs() protoreflect.OneofDescriptors { return &md.lazyInit().Oneofs }
320func (md *Message) ReservedNames() protoreflect.Names { return &md.lazyInit().ReservedNames }
321func (md *Message) ReservedRanges() protoreflect.FieldRanges { return &md.lazyInit().ReservedRanges }
322func (md *Message) RequiredNumbers() protoreflect.FieldNumbers { return &md.lazyInit().RequiredNumbers }
323func (md *Message) ExtensionRanges() protoreflect.FieldRanges { return &md.lazyInit().ExtensionRanges }
324func (md *Message) ExtensionRangeOptions(i int) protoreflect.ProtoMessage {
khenaidood948f772021-08-11 17:49:24 -0400325 if f := md.lazyInit().ExtensionRangeOptions[i]; f != nil {
326 return f()
327 }
328 return descopts.ExtensionRange
329}
mgouda64be8822025-05-30 10:44:00 +0530330func (md *Message) Enums() protoreflect.EnumDescriptors { return &md.L1.Enums }
331func (md *Message) Messages() protoreflect.MessageDescriptors { return &md.L1.Messages }
332func (md *Message) Extensions() protoreflect.ExtensionDescriptors { return &md.L1.Extensions }
333func (md *Message) ProtoType(protoreflect.MessageDescriptor) {}
334func (md *Message) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) }
Abhay Kumara2ae5992025-11-10 14:02:24 +0000335
336// This is not part of the MessageDescriptor interface. It is just used to reconstruct
337// the original FileDescriptor proto.
338func (md *Message) Visibility() int32 { return md.L1.Visibility }
339
khenaidood948f772021-08-11 17:49:24 -0400340func (md *Message) lazyInit() *MessageL2 {
341 md.L0.ParentFile.lazyInit() // implicitly initializes L2
342 return md.L2
343}
344
345// IsMessageSet is a pseudo-internal API for checking whether a message
346// should serialize in the proto1 message format.
347//
348// WARNING: This method is exempt from the compatibility promise and may be
349// removed in the future without warning.
350func (md *Message) IsMessageSet() bool {
351 return md.L1.IsMessageSet
352}
353
mgouda64be8822025-05-30 10:44:00 +0530354func (fd *Field) Options() protoreflect.ProtoMessage {
khenaidood948f772021-08-11 17:49:24 -0400355 if f := fd.L1.Options; f != nil {
356 return f()
357 }
358 return descopts.Field
359}
mgouda64be8822025-05-30 10:44:00 +0530360func (fd *Field) Number() protoreflect.FieldNumber { return fd.L1.Number }
361func (fd *Field) Cardinality() protoreflect.Cardinality { return fd.L1.Cardinality }
362func (fd *Field) Kind() protoreflect.Kind {
363 return fd.L1.Kind
364}
365func (fd *Field) HasJSONName() bool { return fd.L1.StringName.hasJSON }
366func (fd *Field) JSONName() string { return fd.L1.StringName.getJSON(fd) }
367func (fd *Field) TextName() string { return fd.L1.StringName.getText(fd) }
khenaidood948f772021-08-11 17:49:24 -0400368func (fd *Field) HasPresence() bool {
mgouda64be8822025-05-30 10:44:00 +0530369 if fd.L1.Cardinality == protoreflect.Repeated {
370 return false
371 }
Abhay Kumara2ae5992025-11-10 14:02:24 +0000372 return fd.IsExtension() || fd.L1.EditionFeatures.IsFieldPresence || fd.L1.Message != nil || fd.L1.ContainingOneof != nil
khenaidood948f772021-08-11 17:49:24 -0400373}
374func (fd *Field) HasOptionalKeyword() bool {
mgouda64be8822025-05-30 10:44:00 +0530375 return (fd.L0.ParentFile.L1.Syntax == protoreflect.Proto2 && fd.L1.Cardinality == protoreflect.Optional && fd.L1.ContainingOneof == nil) || fd.L1.IsProto3Optional
khenaidood948f772021-08-11 17:49:24 -0400376}
377func (fd *Field) IsPacked() bool {
mgouda64be8822025-05-30 10:44:00 +0530378 if fd.L1.Cardinality != protoreflect.Repeated {
379 return false
380 }
381 switch fd.L1.Kind {
382 case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind:
383 return false
384 }
Abhay Kumara2ae5992025-11-10 14:02:24 +0000385 return fd.L1.EditionFeatures.IsPacked
khenaidood948f772021-08-11 17:49:24 -0400386}
387func (fd *Field) IsExtension() bool { return false }
Abhay Kumara2ae5992025-11-10 14:02:24 +0000388func (fd *Field) IsWeak() bool { return false }
389func (fd *Field) IsLazy() bool { return fd.L1.IsLazy }
mgouda64be8822025-05-30 10:44:00 +0530390func (fd *Field) IsList() bool { return fd.Cardinality() == protoreflect.Repeated && !fd.IsMap() }
khenaidood948f772021-08-11 17:49:24 -0400391func (fd *Field) IsMap() bool { return fd.Message() != nil && fd.Message().IsMapEntry() }
mgouda64be8822025-05-30 10:44:00 +0530392func (fd *Field) MapKey() protoreflect.FieldDescriptor {
khenaidood948f772021-08-11 17:49:24 -0400393 if !fd.IsMap() {
394 return nil
395 }
396 return fd.Message().Fields().ByNumber(genid.MapEntry_Key_field_number)
397}
mgouda64be8822025-05-30 10:44:00 +0530398func (fd *Field) MapValue() protoreflect.FieldDescriptor {
khenaidood948f772021-08-11 17:49:24 -0400399 if !fd.IsMap() {
400 return nil
401 }
402 return fd.Message().Fields().ByNumber(genid.MapEntry_Value_field_number)
403}
mgouda64be8822025-05-30 10:44:00 +0530404func (fd *Field) HasDefault() bool { return fd.L1.Default.has }
405func (fd *Field) Default() protoreflect.Value { return fd.L1.Default.get(fd) }
406func (fd *Field) DefaultEnumValue() protoreflect.EnumValueDescriptor { return fd.L1.Default.enum }
407func (fd *Field) ContainingOneof() protoreflect.OneofDescriptor { return fd.L1.ContainingOneof }
408func (fd *Field) ContainingMessage() protoreflect.MessageDescriptor {
409 return fd.L0.Parent.(protoreflect.MessageDescriptor)
khenaidood948f772021-08-11 17:49:24 -0400410}
mgouda64be8822025-05-30 10:44:00 +0530411func (fd *Field) Enum() protoreflect.EnumDescriptor {
khenaidood948f772021-08-11 17:49:24 -0400412 return fd.L1.Enum
413}
mgouda64be8822025-05-30 10:44:00 +0530414func (fd *Field) Message() protoreflect.MessageDescriptor {
khenaidood948f772021-08-11 17:49:24 -0400415 return fd.L1.Message
416}
Abhay Kumara2ae5992025-11-10 14:02:24 +0000417func (fd *Field) IsMapEntry() bool {
418 parent, ok := fd.L0.Parent.(protoreflect.MessageDescriptor)
419 return ok && parent.IsMapEntry()
420}
mgouda64be8822025-05-30 10:44:00 +0530421func (fd *Field) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) }
422func (fd *Field) ProtoType(protoreflect.FieldDescriptor) {}
khenaidood948f772021-08-11 17:49:24 -0400423
424// EnforceUTF8 is a pseudo-internal API to determine whether to enforce UTF-8
425// validation for the string field. This exists for Google-internal use only
426// since proto3 did not enforce UTF-8 validity prior to the open-source release.
427// If this method does not exist, the default is to enforce valid UTF-8.
428//
429// WARNING: This method is exempt from the compatibility promise and may be
430// removed in the future without warning.
431func (fd *Field) EnforceUTF8() bool {
Abhay Kumara2ae5992025-11-10 14:02:24 +0000432 return fd.L1.EditionFeatures.IsUTF8Validated
khenaidood948f772021-08-11 17:49:24 -0400433}
434
435func (od *Oneof) IsSynthetic() bool {
mgouda64be8822025-05-30 10:44:00 +0530436 return od.L0.ParentFile.L1.Syntax == protoreflect.Proto3 && len(od.L1.Fields.List) == 1 && od.L1.Fields.List[0].HasOptionalKeyword()
khenaidood948f772021-08-11 17:49:24 -0400437}
mgouda64be8822025-05-30 10:44:00 +0530438func (od *Oneof) Options() protoreflect.ProtoMessage {
khenaidood948f772021-08-11 17:49:24 -0400439 if f := od.L1.Options; f != nil {
440 return f()
441 }
442 return descopts.Oneof
443}
mgouda64be8822025-05-30 10:44:00 +0530444func (od *Oneof) Fields() protoreflect.FieldDescriptors { return &od.L1.Fields }
445func (od *Oneof) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, od) }
446func (od *Oneof) ProtoType(protoreflect.OneofDescriptor) {}
khenaidood948f772021-08-11 17:49:24 -0400447
448type (
449 Extension struct {
450 Base
451 L1 ExtensionL1
452 L2 *ExtensionL2 // protected by fileDesc.once
453 }
454 ExtensionL1 struct {
mgouda64be8822025-05-30 10:44:00 +0530455 Number protoreflect.FieldNumber
456 Extendee protoreflect.MessageDescriptor
457 Cardinality protoreflect.Cardinality
458 Kind protoreflect.Kind
Abhay Kumara2ae5992025-11-10 14:02:24 +0000459 IsLazy bool
mgouda64be8822025-05-30 10:44:00 +0530460 EditionFeatures EditionFeatures
khenaidood948f772021-08-11 17:49:24 -0400461 }
462 ExtensionL2 struct {
mgouda64be8822025-05-30 10:44:00 +0530463 Options func() protoreflect.ProtoMessage
khenaidood948f772021-08-11 17:49:24 -0400464 StringName stringName
465 IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto
khenaidood948f772021-08-11 17:49:24 -0400466 Default defaultValue
mgouda64be8822025-05-30 10:44:00 +0530467 Enum protoreflect.EnumDescriptor
468 Message protoreflect.MessageDescriptor
khenaidood948f772021-08-11 17:49:24 -0400469 }
470)
471
mgouda64be8822025-05-30 10:44:00 +0530472func (xd *Extension) Options() protoreflect.ProtoMessage {
khenaidood948f772021-08-11 17:49:24 -0400473 if f := xd.lazyInit().Options; f != nil {
474 return f()
475 }
476 return descopts.Field
477}
mgouda64be8822025-05-30 10:44:00 +0530478func (xd *Extension) Number() protoreflect.FieldNumber { return xd.L1.Number }
479func (xd *Extension) Cardinality() protoreflect.Cardinality { return xd.L1.Cardinality }
480func (xd *Extension) Kind() protoreflect.Kind { return xd.L1.Kind }
481func (xd *Extension) HasJSONName() bool { return xd.lazyInit().StringName.hasJSON }
482func (xd *Extension) JSONName() string { return xd.lazyInit().StringName.getJSON(xd) }
483func (xd *Extension) TextName() string { return xd.lazyInit().StringName.getText(xd) }
484func (xd *Extension) HasPresence() bool { return xd.L1.Cardinality != protoreflect.Repeated }
khenaidood948f772021-08-11 17:49:24 -0400485func (xd *Extension) HasOptionalKeyword() bool {
mgouda64be8822025-05-30 10:44:00 +0530486 return (xd.L0.ParentFile.L1.Syntax == protoreflect.Proto2 && xd.L1.Cardinality == protoreflect.Optional) || xd.lazyInit().IsProto3Optional
khenaidood948f772021-08-11 17:49:24 -0400487}
Abhay Kumara2ae5992025-11-10 14:02:24 +0000488func (xd *Extension) IsPacked() bool {
489 if xd.L1.Cardinality != protoreflect.Repeated {
490 return false
491 }
492 switch xd.L1.Kind {
493 case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind:
494 return false
495 }
496 return xd.L1.EditionFeatures.IsPacked
497}
mgouda64be8822025-05-30 10:44:00 +0530498func (xd *Extension) IsExtension() bool { return true }
499func (xd *Extension) IsWeak() bool { return false }
Abhay Kumara2ae5992025-11-10 14:02:24 +0000500func (xd *Extension) IsLazy() bool { return xd.L1.IsLazy }
mgouda64be8822025-05-30 10:44:00 +0530501func (xd *Extension) IsList() bool { return xd.Cardinality() == protoreflect.Repeated }
502func (xd *Extension) IsMap() bool { return false }
503func (xd *Extension) MapKey() protoreflect.FieldDescriptor { return nil }
504func (xd *Extension) MapValue() protoreflect.FieldDescriptor { return nil }
505func (xd *Extension) HasDefault() bool { return xd.lazyInit().Default.has }
506func (xd *Extension) Default() protoreflect.Value { return xd.lazyInit().Default.get(xd) }
507func (xd *Extension) DefaultEnumValue() protoreflect.EnumValueDescriptor {
508 return xd.lazyInit().Default.enum
509}
510func (xd *Extension) ContainingOneof() protoreflect.OneofDescriptor { return nil }
511func (xd *Extension) ContainingMessage() protoreflect.MessageDescriptor { return xd.L1.Extendee }
512func (xd *Extension) Enum() protoreflect.EnumDescriptor { return xd.lazyInit().Enum }
513func (xd *Extension) Message() protoreflect.MessageDescriptor { return xd.lazyInit().Message }
514func (xd *Extension) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, xd) }
515func (xd *Extension) ProtoType(protoreflect.FieldDescriptor) {}
516func (xd *Extension) ProtoInternal(pragma.DoNotImplement) {}
khenaidood948f772021-08-11 17:49:24 -0400517func (xd *Extension) lazyInit() *ExtensionL2 {
518 xd.L0.ParentFile.lazyInit() // implicitly initializes L2
519 return xd.L2
520}
521
522type (
523 Service struct {
524 Base
525 L1 ServiceL1
526 L2 *ServiceL2 // protected by fileDesc.once
527 }
528 ServiceL1 struct{}
529 ServiceL2 struct {
mgouda64be8822025-05-30 10:44:00 +0530530 Options func() protoreflect.ProtoMessage
khenaidood948f772021-08-11 17:49:24 -0400531 Methods Methods
532 }
533
534 Method struct {
535 Base
536 L1 MethodL1
537 }
538 MethodL1 struct {
mgouda64be8822025-05-30 10:44:00 +0530539 Options func() protoreflect.ProtoMessage
540 Input protoreflect.MessageDescriptor
541 Output protoreflect.MessageDescriptor
khenaidood948f772021-08-11 17:49:24 -0400542 IsStreamingClient bool
543 IsStreamingServer bool
544 }
545)
546
mgouda64be8822025-05-30 10:44:00 +0530547func (sd *Service) Options() protoreflect.ProtoMessage {
khenaidood948f772021-08-11 17:49:24 -0400548 if f := sd.lazyInit().Options; f != nil {
549 return f()
550 }
551 return descopts.Service
552}
mgouda64be8822025-05-30 10:44:00 +0530553func (sd *Service) Methods() protoreflect.MethodDescriptors { return &sd.lazyInit().Methods }
554func (sd *Service) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, sd) }
555func (sd *Service) ProtoType(protoreflect.ServiceDescriptor) {}
556func (sd *Service) ProtoInternal(pragma.DoNotImplement) {}
khenaidood948f772021-08-11 17:49:24 -0400557func (sd *Service) lazyInit() *ServiceL2 {
558 sd.L0.ParentFile.lazyInit() // implicitly initializes L2
559 return sd.L2
560}
561
mgouda64be8822025-05-30 10:44:00 +0530562func (md *Method) Options() protoreflect.ProtoMessage {
khenaidood948f772021-08-11 17:49:24 -0400563 if f := md.L1.Options; f != nil {
564 return f()
565 }
566 return descopts.Method
567}
mgouda64be8822025-05-30 10:44:00 +0530568func (md *Method) Input() protoreflect.MessageDescriptor { return md.L1.Input }
569func (md *Method) Output() protoreflect.MessageDescriptor { return md.L1.Output }
570func (md *Method) IsStreamingClient() bool { return md.L1.IsStreamingClient }
571func (md *Method) IsStreamingServer() bool { return md.L1.IsStreamingServer }
572func (md *Method) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) }
573func (md *Method) ProtoType(protoreflect.MethodDescriptor) {}
574func (md *Method) ProtoInternal(pragma.DoNotImplement) {}
khenaidood948f772021-08-11 17:49:24 -0400575
576// Surrogate files are can be used to create standalone descriptors
577// where the syntax is only information derived from the parent file.
578var (
Abhay Kumara2ae5992025-11-10 14:02:24 +0000579 SurrogateProto2 = &File{L1: FileL1{Syntax: protoreflect.Proto2}, L2: &FileL2{}}
580 SurrogateProto3 = &File{L1: FileL1{Syntax: protoreflect.Proto3}, L2: &FileL2{}}
581 SurrogateEdition2023 = &File{L1: FileL1{Syntax: protoreflect.Editions, Edition: Edition2023}, L2: &FileL2{}}
khenaidood948f772021-08-11 17:49:24 -0400582)
583
584type (
585 Base struct {
586 L0 BaseL0
587 }
588 BaseL0 struct {
mgouda64be8822025-05-30 10:44:00 +0530589 FullName protoreflect.FullName // must be populated
590 ParentFile *File // must be populated
591 Parent protoreflect.Descriptor
khenaidood948f772021-08-11 17:49:24 -0400592 Index int
593 }
594)
595
mgouda64be8822025-05-30 10:44:00 +0530596func (d *Base) Name() protoreflect.Name { return d.L0.FullName.Name() }
597func (d *Base) FullName() protoreflect.FullName { return d.L0.FullName }
598func (d *Base) ParentFile() protoreflect.FileDescriptor {
khenaidood948f772021-08-11 17:49:24 -0400599 if d.L0.ParentFile == SurrogateProto2 || d.L0.ParentFile == SurrogateProto3 {
600 return nil // surrogate files are not real parents
601 }
602 return d.L0.ParentFile
603}
mgouda64be8822025-05-30 10:44:00 +0530604func (d *Base) Parent() protoreflect.Descriptor { return d.L0.Parent }
khenaidood948f772021-08-11 17:49:24 -0400605func (d *Base) Index() int { return d.L0.Index }
mgouda64be8822025-05-30 10:44:00 +0530606func (d *Base) Syntax() protoreflect.Syntax { return d.L0.ParentFile.Syntax() }
khenaidood948f772021-08-11 17:49:24 -0400607func (d *Base) IsPlaceholder() bool { return false }
608func (d *Base) ProtoInternal(pragma.DoNotImplement) {}
609
610type stringName struct {
611 hasJSON bool
612 once sync.Once
613 nameJSON string
614 nameText string
615}
616
617// InitJSON initializes the name. It is exported for use by other internal packages.
618func (s *stringName) InitJSON(name string) {
619 s.hasJSON = true
620 s.nameJSON = name
621}
622
Abhay Kumara2ae5992025-11-10 14:02:24 +0000623// Returns true if this field is structured like the synthetic field of a proto2
624// group. This allows us to expand our treatment of delimited fields without
625// breaking proto2 files that have been upgraded to editions.
626func isGroupLike(fd protoreflect.FieldDescriptor) bool {
627 // Groups are always group types.
628 if fd.Kind() != protoreflect.GroupKind {
629 return false
630 }
631
632 // Group fields are always the lowercase type name.
633 if strings.ToLower(string(fd.Message().Name())) != string(fd.Name()) {
634 return false
635 }
636
637 // Groups could only be defined in the same file they're used.
638 if fd.Message().ParentFile() != fd.ParentFile() {
639 return false
640 }
641
642 // Group messages are always defined in the same scope as the field. File
643 // level extensions will compare NULL == NULL here, which is why the file
644 // comparison above is necessary to ensure both come from the same file.
645 if fd.IsExtension() {
646 return fd.Parent() == fd.Message().Parent()
647 }
648 return fd.ContainingMessage() == fd.Message().Parent()
649}
650
mgouda64be8822025-05-30 10:44:00 +0530651func (s *stringName) lazyInit(fd protoreflect.FieldDescriptor) *stringName {
khenaidood948f772021-08-11 17:49:24 -0400652 s.once.Do(func() {
653 if fd.IsExtension() {
654 // For extensions, JSON and text are formatted the same way.
655 var name string
656 if messageset.IsMessageSetExtension(fd) {
657 name = string("[" + fd.FullName().Parent() + "]")
658 } else {
659 name = string("[" + fd.FullName() + "]")
660 }
661 s.nameJSON = name
662 s.nameText = name
663 } else {
664 // Format the JSON name.
665 if !s.hasJSON {
666 s.nameJSON = strs.JSONCamelCase(string(fd.Name()))
667 }
668
669 // Format the text name.
670 s.nameText = string(fd.Name())
Abhay Kumara2ae5992025-11-10 14:02:24 +0000671 if isGroupLike(fd) {
khenaidood948f772021-08-11 17:49:24 -0400672 s.nameText = string(fd.Message().Name())
673 }
674 }
675 })
676 return s
677}
678
mgouda64be8822025-05-30 10:44:00 +0530679func (s *stringName) getJSON(fd protoreflect.FieldDescriptor) string { return s.lazyInit(fd).nameJSON }
680func (s *stringName) getText(fd protoreflect.FieldDescriptor) string { return s.lazyInit(fd).nameText }
khenaidood948f772021-08-11 17:49:24 -0400681
mgouda64be8822025-05-30 10:44:00 +0530682func DefaultValue(v protoreflect.Value, ev protoreflect.EnumValueDescriptor) defaultValue {
khenaidood948f772021-08-11 17:49:24 -0400683 dv := defaultValue{has: v.IsValid(), val: v, enum: ev}
684 if b, ok := v.Interface().([]byte); ok {
685 // Store a copy of the default bytes, so that we can detect
686 // accidental mutations of the original value.
687 dv.bytes = append([]byte(nil), b...)
688 }
689 return dv
690}
691
mgouda64be8822025-05-30 10:44:00 +0530692func unmarshalDefault(b []byte, k protoreflect.Kind, pf *File, ed protoreflect.EnumDescriptor) defaultValue {
693 var evs protoreflect.EnumValueDescriptors
694 if k == protoreflect.EnumKind {
khenaidood948f772021-08-11 17:49:24 -0400695 // If the enum is declared within the same file, be careful not to
696 // blindly call the Values method, lest we bind ourselves in a deadlock.
697 if e, ok := ed.(*Enum); ok && e.L0.ParentFile == pf {
698 evs = &e.L2.Values
699 } else {
700 evs = ed.Values()
701 }
702
703 // If we are unable to resolve the enum dependency, use a placeholder
704 // enum value since we will not be able to parse the default value.
mgouda64be8822025-05-30 10:44:00 +0530705 if ed.IsPlaceholder() && protoreflect.Name(b).IsValid() {
706 v := protoreflect.ValueOfEnum(0)
707 ev := PlaceholderEnumValue(ed.FullName().Parent().Append(protoreflect.Name(b)))
khenaidood948f772021-08-11 17:49:24 -0400708 return DefaultValue(v, ev)
709 }
710 }
711
712 v, ev, err := defval.Unmarshal(string(b), k, evs, defval.Descriptor)
713 if err != nil {
714 panic(err)
715 }
716 return DefaultValue(v, ev)
717}
718
719type defaultValue struct {
720 has bool
mgouda64be8822025-05-30 10:44:00 +0530721 val protoreflect.Value
722 enum protoreflect.EnumValueDescriptor
khenaidood948f772021-08-11 17:49:24 -0400723 bytes []byte
724}
725
mgouda64be8822025-05-30 10:44:00 +0530726func (dv *defaultValue) get(fd protoreflect.FieldDescriptor) protoreflect.Value {
khenaidood948f772021-08-11 17:49:24 -0400727 // Return the zero value as the default if unpopulated.
728 if !dv.has {
mgouda64be8822025-05-30 10:44:00 +0530729 if fd.Cardinality() == protoreflect.Repeated {
730 return protoreflect.Value{}
khenaidood948f772021-08-11 17:49:24 -0400731 }
732 switch fd.Kind() {
mgouda64be8822025-05-30 10:44:00 +0530733 case protoreflect.BoolKind:
734 return protoreflect.ValueOfBool(false)
735 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
736 return protoreflect.ValueOfInt32(0)
737 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
738 return protoreflect.ValueOfInt64(0)
739 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
740 return protoreflect.ValueOfUint32(0)
741 case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
742 return protoreflect.ValueOfUint64(0)
743 case protoreflect.FloatKind:
744 return protoreflect.ValueOfFloat32(0)
745 case protoreflect.DoubleKind:
746 return protoreflect.ValueOfFloat64(0)
747 case protoreflect.StringKind:
748 return protoreflect.ValueOfString("")
749 case protoreflect.BytesKind:
750 return protoreflect.ValueOfBytes(nil)
751 case protoreflect.EnumKind:
khenaidood948f772021-08-11 17:49:24 -0400752 if evs := fd.Enum().Values(); evs.Len() > 0 {
mgouda64be8822025-05-30 10:44:00 +0530753 return protoreflect.ValueOfEnum(evs.Get(0).Number())
khenaidood948f772021-08-11 17:49:24 -0400754 }
mgouda64be8822025-05-30 10:44:00 +0530755 return protoreflect.ValueOfEnum(0)
khenaidood948f772021-08-11 17:49:24 -0400756 }
757 }
758
759 if len(dv.bytes) > 0 && !bytes.Equal(dv.bytes, dv.val.Bytes()) {
760 // TODO: Avoid panic if we're running with the race detector
761 // and instead spawn a goroutine that periodically resets
762 // this value back to the original to induce a race.
763 panic(fmt.Sprintf("detected mutation on the default bytes for %v", fd.FullName()))
764 }
765 return dv.val
766}