blob: c775e5832f01a87d94a36bf3f869943311441323 [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301// 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 Kumarfe505f22025-11-10 14:16:31 +000010 "strings"
Naveen Sampath04696f72022-06-13 15:19:14 +053011 "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"
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053021 "google.golang.org/protobuf/reflect/protoreflect"
Naveen Sampath04696f72022-06-13 15:19:14 +053022)
23
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +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 Kumarfe505f22025-11-10 14:16:31 +000034 Edition2024 Edition = 1001
bseenivadd66c362026-02-12 19:13:26 +053035 EditionUnstable Edition = 9999
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053036 EditionUnsupported Edition = 100000
37)
38
Naveen Sampath04696f72022-06-13 15:19:14 +053039// The types in this file may have a suffix:
40// • L0: Contains fields common to all descriptors (except File) and
41// must be initialized up front.
42// • L1: Contains fields specific to a descriptor and
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053043// must be initialized up front. If the associated proto uses Editions, the
44// Editions features must always be resolved. If not explicitly set, the
45// appropriate default must be resolved and set.
Naveen Sampath04696f72022-06-13 15:19:14 +053046// • L2: Contains fields that are lazily initialized when constructing
47// from the raw file descriptor. When constructing as a literal, the L2
48// fields must be initialized up front.
49//
50// The types are exported so that packages like reflect/protodesc can
51// directly construct descriptors.
52
53type (
54 File struct {
55 fileRaw
56 L1 FileL1
57
58 once uint32 // atomically set if L2 is valid
59 mu sync.Mutex // protects L2
60 L2 *FileL2
61 }
62 FileL1 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053063 Syntax protoreflect.Syntax
64 Edition Edition // Only used if Syntax == Editions
Naveen Sampath04696f72022-06-13 15:19:14 +053065 Path string
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053066 Package protoreflect.FullName
Naveen Sampath04696f72022-06-13 15:19:14 +053067
68 Enums Enums
69 Messages Messages
70 Extensions Extensions
71 Services Services
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053072
73 EditionFeatures EditionFeatures
Naveen Sampath04696f72022-06-13 15:19:14 +053074 }
75 FileL2 struct {
Abhay Kumarfe505f22025-11-10 14:16:31 +000076 Options func() protoreflect.ProtoMessage
77 Imports FileImports
78 OptionImports func() protoreflect.FileImports
79 Locations SourceLocations
Naveen Sampath04696f72022-06-13 15:19:14 +053080 }
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053081
Abhay Kumarfe505f22025-11-10 14:16:31 +000082 // EditionFeatures is a frequently-instantiated struct, so please take care
83 // to minimize padding when adding new fields to this struct (add them in
84 // the right place/order).
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053085 EditionFeatures struct {
Abhay Kumarfe505f22025-11-10 14:16:31 +000086 // StripEnumPrefix determines if the plugin generates enum value
87 // constants as-is, with their prefix stripped, or both variants.
88 StripEnumPrefix int
89
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053090 // IsFieldPresence is true if field_presence is EXPLICIT
91 // https://protobuf.dev/editions/features/#field_presence
92 IsFieldPresence bool
Abhay Kumarfe505f22025-11-10 14:16:31 +000093
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053094 // IsFieldPresence is true if field_presence is LEGACY_REQUIRED
95 // https://protobuf.dev/editions/features/#field_presence
96 IsLegacyRequired bool
Abhay Kumarfe505f22025-11-10 14:16:31 +000097
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +053098 // IsOpenEnum is true if enum_type is OPEN
99 // https://protobuf.dev/editions/features/#enum_type
100 IsOpenEnum bool
Abhay Kumarfe505f22025-11-10 14:16:31 +0000101
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530102 // IsPacked is true if repeated_field_encoding is PACKED
103 // https://protobuf.dev/editions/features/#repeated_field_encoding
104 IsPacked bool
Abhay Kumarfe505f22025-11-10 14:16:31 +0000105
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530106 // IsUTF8Validated is true if utf_validation is VERIFY
107 // https://protobuf.dev/editions/features/#utf8_validation
108 IsUTF8Validated bool
Abhay Kumarfe505f22025-11-10 14:16:31 +0000109
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530110 // IsDelimitedEncoded is true if message_encoding is DELIMITED
111 // https://protobuf.dev/editions/features/#message_encoding
112 IsDelimitedEncoded bool
Abhay Kumarfe505f22025-11-10 14:16:31 +0000113
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530114 // IsJSONCompliant is true if json_format is ALLOW
115 // https://protobuf.dev/editions/features/#json_format
116 IsJSONCompliant bool
Abhay Kumarfe505f22025-11-10 14:16:31 +0000117
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530118 // GenerateLegacyUnmarshalJSON determines if the plugin generates the
119 // UnmarshalJSON([]byte) error method for enums.
120 GenerateLegacyUnmarshalJSON bool
Abhay Kumarfe505f22025-11-10 14:16:31 +0000121 // APILevel controls which API (Open, Hybrid or Opaque) should be used
122 // for generated code (.pb.go files).
123 APILevel int
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530124 }
Naveen Sampath04696f72022-06-13 15:19:14 +0530125)
126
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530127func (fd *File) ParentFile() protoreflect.FileDescriptor { return fd }
128func (fd *File) Parent() protoreflect.Descriptor { return nil }
129func (fd *File) Index() int { return 0 }
130func (fd *File) Syntax() protoreflect.Syntax { return fd.L1.Syntax }
131func (fd *File) Name() protoreflect.Name { return fd.L1.Package.Name() }
132func (fd *File) FullName() protoreflect.FullName { return fd.L1.Package }
133func (fd *File) IsPlaceholder() bool { return false }
134func (fd *File) Options() protoreflect.ProtoMessage {
Naveen Sampath04696f72022-06-13 15:19:14 +0530135 if f := fd.lazyInit().Options; f != nil {
136 return f()
137 }
138 return descopts.File
139}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530140func (fd *File) Path() string { return fd.L1.Path }
141func (fd *File) Package() protoreflect.FullName { return fd.L1.Package }
142func (fd *File) Imports() protoreflect.FileImports { return &fd.lazyInit().Imports }
143func (fd *File) Enums() protoreflect.EnumDescriptors { return &fd.L1.Enums }
144func (fd *File) Messages() protoreflect.MessageDescriptors { return &fd.L1.Messages }
145func (fd *File) Extensions() protoreflect.ExtensionDescriptors { return &fd.L1.Extensions }
146func (fd *File) Services() protoreflect.ServiceDescriptors { return &fd.L1.Services }
147func (fd *File) SourceLocations() protoreflect.SourceLocations { return &fd.lazyInit().Locations }
148func (fd *File) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) }
149func (fd *File) ProtoType(protoreflect.FileDescriptor) {}
150func (fd *File) ProtoInternal(pragma.DoNotImplement) {}
Naveen Sampath04696f72022-06-13 15:19:14 +0530151
Abhay Kumarfe505f22025-11-10 14:16:31 +0000152// The next two are not part of the FileDescriptor interface. They are just used to reconstruct
153// the original FileDescriptor proto.
154func (fd *File) Edition() int32 { return int32(fd.L1.Edition) }
155func (fd *File) OptionImports() protoreflect.FileImports {
156 if f := fd.lazyInit().OptionImports; f != nil {
157 return f()
158 }
159 return emptyFiles
160}
161
Naveen Sampath04696f72022-06-13 15:19:14 +0530162func (fd *File) lazyInit() *FileL2 {
163 if atomic.LoadUint32(&fd.once) == 0 {
164 fd.lazyInitOnce()
165 }
166 return fd.L2
167}
168
169func (fd *File) lazyInitOnce() {
170 fd.mu.Lock()
171 if fd.L2 == nil {
172 fd.lazyRawInit() // recursively initializes all L2 structures
173 }
174 atomic.StoreUint32(&fd.once, 1)
175 fd.mu.Unlock()
176}
177
178// GoPackagePath is a pseudo-internal API for determining the Go package path
179// that this file descriptor is declared in.
180//
181// WARNING: This method is exempt from the compatibility promise and may be
182// removed in the future without warning.
183func (fd *File) GoPackagePath() string {
184 return fd.builder.GoPackagePath
185}
186
187type (
188 Enum struct {
189 Base
190 L1 EnumL1
191 L2 *EnumL2 // protected by fileDesc.once
192 }
193 EnumL1 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530194 EditionFeatures EditionFeatures
Abhay Kumarfe505f22025-11-10 14:16:31 +0000195 Visibility int32
196 eagerValues bool // controls whether EnumL2.Values is already populated
Naveen Sampath04696f72022-06-13 15:19:14 +0530197 }
198 EnumL2 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530199 Options func() protoreflect.ProtoMessage
Naveen Sampath04696f72022-06-13 15:19:14 +0530200 Values EnumValues
201 ReservedNames Names
202 ReservedRanges EnumRanges
203 }
204
205 EnumValue struct {
206 Base
207 L1 EnumValueL1
208 }
209 EnumValueL1 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530210 Options func() protoreflect.ProtoMessage
211 Number protoreflect.EnumNumber
Naveen Sampath04696f72022-06-13 15:19:14 +0530212 }
213)
214
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530215func (ed *Enum) Options() protoreflect.ProtoMessage {
Naveen Sampath04696f72022-06-13 15:19:14 +0530216 if f := ed.lazyInit().Options; f != nil {
217 return f()
218 }
219 return descopts.Enum
220}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530221func (ed *Enum) Values() protoreflect.EnumValueDescriptors {
Naveen Sampath04696f72022-06-13 15:19:14 +0530222 if ed.L1.eagerValues {
223 return &ed.L2.Values
224 }
225 return &ed.lazyInit().Values
226}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530227func (ed *Enum) ReservedNames() protoreflect.Names { return &ed.lazyInit().ReservedNames }
228func (ed *Enum) ReservedRanges() protoreflect.EnumRanges { return &ed.lazyInit().ReservedRanges }
229func (ed *Enum) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) }
230func (ed *Enum) ProtoType(protoreflect.EnumDescriptor) {}
Abhay Kumarfe505f22025-11-10 14:16:31 +0000231
232// This is not part of the EnumDescriptor interface. It is just used to reconstruct
233// the original FileDescriptor proto.
234func (ed *Enum) Visibility() int32 { return ed.L1.Visibility }
235
Naveen Sampath04696f72022-06-13 15:19:14 +0530236func (ed *Enum) lazyInit() *EnumL2 {
237 ed.L0.ParentFile.lazyInit() // implicitly initializes L2
238 return ed.L2
239}
Abhay Kumarfe505f22025-11-10 14:16:31 +0000240func (ed *Enum) IsClosed() bool {
241 return !ed.L1.EditionFeatures.IsOpenEnum
242}
Naveen Sampath04696f72022-06-13 15:19:14 +0530243
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530244func (ed *EnumValue) Options() protoreflect.ProtoMessage {
Naveen Sampath04696f72022-06-13 15:19:14 +0530245 if f := ed.L1.Options; f != nil {
246 return f()
247 }
248 return descopts.EnumValue
249}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530250func (ed *EnumValue) Number() protoreflect.EnumNumber { return ed.L1.Number }
251func (ed *EnumValue) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) }
252func (ed *EnumValue) ProtoType(protoreflect.EnumValueDescriptor) {}
Naveen Sampath04696f72022-06-13 15:19:14 +0530253
254type (
255 Message struct {
256 Base
257 L1 MessageL1
258 L2 *MessageL2 // protected by fileDesc.once
259 }
260 MessageL1 struct {
Abhay Kumarfe505f22025-11-10 14:16:31 +0000261 Enums Enums
262 Messages Messages
263 Extensions Extensions
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530264 EditionFeatures EditionFeatures
Abhay Kumarfe505f22025-11-10 14:16:31 +0000265 Visibility int32
266 IsMapEntry bool // promoted from google.protobuf.MessageOptions
267 IsMessageSet bool // promoted from google.protobuf.MessageOptions
Naveen Sampath04696f72022-06-13 15:19:14 +0530268 }
269 MessageL2 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530270 Options func() protoreflect.ProtoMessage
Naveen Sampath04696f72022-06-13 15:19:14 +0530271 Fields Fields
272 Oneofs Oneofs
273 ReservedNames Names
274 ReservedRanges FieldRanges
275 RequiredNumbers FieldNumbers // must be consistent with Fields.Cardinality
276 ExtensionRanges FieldRanges
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530277 ExtensionRangeOptions []func() protoreflect.ProtoMessage // must be same length as ExtensionRanges
Naveen Sampath04696f72022-06-13 15:19:14 +0530278 }
279
280 Field struct {
281 Base
282 L1 FieldL1
283 }
284 FieldL1 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530285 Options func() protoreflect.ProtoMessage
286 Number protoreflect.FieldNumber
287 Cardinality protoreflect.Cardinality // must be consistent with Message.RequiredNumbers
288 Kind protoreflect.Kind
Naveen Sampath04696f72022-06-13 15:19:14 +0530289 StringName stringName
290 IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto
Abhay Kumarfe505f22025-11-10 14:16:31 +0000291 IsLazy bool // promoted from google.protobuf.FieldOptions
Naveen Sampath04696f72022-06-13 15:19:14 +0530292 Default defaultValue
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530293 ContainingOneof protoreflect.OneofDescriptor // must be consistent with Message.Oneofs.Fields
294 Enum protoreflect.EnumDescriptor
295 Message protoreflect.MessageDescriptor
296
297 EditionFeatures EditionFeatures
Naveen Sampath04696f72022-06-13 15:19:14 +0530298 }
299
300 Oneof struct {
301 Base
302 L1 OneofL1
303 }
304 OneofL1 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530305 Options func() protoreflect.ProtoMessage
Naveen Sampath04696f72022-06-13 15:19:14 +0530306 Fields OneofFields // must be consistent with Message.Fields.ContainingOneof
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530307
308 EditionFeatures EditionFeatures
Naveen Sampath04696f72022-06-13 15:19:14 +0530309 }
310)
311
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530312func (md *Message) Options() protoreflect.ProtoMessage {
Naveen Sampath04696f72022-06-13 15:19:14 +0530313 if f := md.lazyInit().Options; f != nil {
314 return f()
315 }
316 return descopts.Message
317}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530318func (md *Message) IsMapEntry() bool { return md.L1.IsMapEntry }
319func (md *Message) Fields() protoreflect.FieldDescriptors { return &md.lazyInit().Fields }
320func (md *Message) Oneofs() protoreflect.OneofDescriptors { return &md.lazyInit().Oneofs }
321func (md *Message) ReservedNames() protoreflect.Names { return &md.lazyInit().ReservedNames }
322func (md *Message) ReservedRanges() protoreflect.FieldRanges { return &md.lazyInit().ReservedRanges }
323func (md *Message) RequiredNumbers() protoreflect.FieldNumbers { return &md.lazyInit().RequiredNumbers }
324func (md *Message) ExtensionRanges() protoreflect.FieldRanges { return &md.lazyInit().ExtensionRanges }
325func (md *Message) ExtensionRangeOptions(i int) protoreflect.ProtoMessage {
Naveen Sampath04696f72022-06-13 15:19:14 +0530326 if f := md.lazyInit().ExtensionRangeOptions[i]; f != nil {
327 return f()
328 }
329 return descopts.ExtensionRange
330}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530331func (md *Message) Enums() protoreflect.EnumDescriptors { return &md.L1.Enums }
332func (md *Message) Messages() protoreflect.MessageDescriptors { return &md.L1.Messages }
333func (md *Message) Extensions() protoreflect.ExtensionDescriptors { return &md.L1.Extensions }
334func (md *Message) ProtoType(protoreflect.MessageDescriptor) {}
335func (md *Message) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) }
Abhay Kumarfe505f22025-11-10 14:16:31 +0000336
337// This is not part of the MessageDescriptor interface. It is just used to reconstruct
338// the original FileDescriptor proto.
339func (md *Message) Visibility() int32 { return md.L1.Visibility }
340
Naveen Sampath04696f72022-06-13 15:19:14 +0530341func (md *Message) lazyInit() *MessageL2 {
342 md.L0.ParentFile.lazyInit() // implicitly initializes L2
343 return md.L2
344}
345
346// IsMessageSet is a pseudo-internal API for checking whether a message
347// should serialize in the proto1 message format.
348//
349// WARNING: This method is exempt from the compatibility promise and may be
350// removed in the future without warning.
351func (md *Message) IsMessageSet() bool {
352 return md.L1.IsMessageSet
353}
354
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530355func (fd *Field) Options() protoreflect.ProtoMessage {
Naveen Sampath04696f72022-06-13 15:19:14 +0530356 if f := fd.L1.Options; f != nil {
357 return f()
358 }
359 return descopts.Field
360}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530361func (fd *Field) Number() protoreflect.FieldNumber { return fd.L1.Number }
362func (fd *Field) Cardinality() protoreflect.Cardinality { return fd.L1.Cardinality }
363func (fd *Field) Kind() protoreflect.Kind {
364 return fd.L1.Kind
365}
366func (fd *Field) HasJSONName() bool { return fd.L1.StringName.hasJSON }
367func (fd *Field) JSONName() string { return fd.L1.StringName.getJSON(fd) }
368func (fd *Field) TextName() string { return fd.L1.StringName.getText(fd) }
Naveen Sampath04696f72022-06-13 15:19:14 +0530369func (fd *Field) HasPresence() bool {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530370 if fd.L1.Cardinality == protoreflect.Repeated {
371 return false
372 }
Abhay Kumarfe505f22025-11-10 14:16:31 +0000373 return fd.IsExtension() || fd.L1.EditionFeatures.IsFieldPresence || fd.L1.Message != nil || fd.L1.ContainingOneof != nil
Naveen Sampath04696f72022-06-13 15:19:14 +0530374}
375func (fd *Field) HasOptionalKeyword() bool {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530376 return (fd.L0.ParentFile.L1.Syntax == protoreflect.Proto2 && fd.L1.Cardinality == protoreflect.Optional && fd.L1.ContainingOneof == nil) || fd.L1.IsProto3Optional
Naveen Sampath04696f72022-06-13 15:19:14 +0530377}
378func (fd *Field) IsPacked() bool {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530379 if fd.L1.Cardinality != protoreflect.Repeated {
380 return false
381 }
382 switch fd.L1.Kind {
383 case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind:
384 return false
385 }
Abhay Kumarfe505f22025-11-10 14:16:31 +0000386 return fd.L1.EditionFeatures.IsPacked
Naveen Sampath04696f72022-06-13 15:19:14 +0530387}
388func (fd *Field) IsExtension() bool { return false }
Abhay Kumarfe505f22025-11-10 14:16:31 +0000389func (fd *Field) IsWeak() bool { return false }
390func (fd *Field) IsLazy() bool { return fd.L1.IsLazy }
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530391func (fd *Field) IsList() bool { return fd.Cardinality() == protoreflect.Repeated && !fd.IsMap() }
Naveen Sampath04696f72022-06-13 15:19:14 +0530392func (fd *Field) IsMap() bool { return fd.Message() != nil && fd.Message().IsMapEntry() }
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530393func (fd *Field) MapKey() protoreflect.FieldDescriptor {
Naveen Sampath04696f72022-06-13 15:19:14 +0530394 if !fd.IsMap() {
395 return nil
396 }
397 return fd.Message().Fields().ByNumber(genid.MapEntry_Key_field_number)
398}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530399func (fd *Field) MapValue() protoreflect.FieldDescriptor {
Naveen Sampath04696f72022-06-13 15:19:14 +0530400 if !fd.IsMap() {
401 return nil
402 }
403 return fd.Message().Fields().ByNumber(genid.MapEntry_Value_field_number)
404}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530405func (fd *Field) HasDefault() bool { return fd.L1.Default.has }
406func (fd *Field) Default() protoreflect.Value { return fd.L1.Default.get(fd) }
407func (fd *Field) DefaultEnumValue() protoreflect.EnumValueDescriptor { return fd.L1.Default.enum }
408func (fd *Field) ContainingOneof() protoreflect.OneofDescriptor { return fd.L1.ContainingOneof }
409func (fd *Field) ContainingMessage() protoreflect.MessageDescriptor {
410 return fd.L0.Parent.(protoreflect.MessageDescriptor)
Naveen Sampath04696f72022-06-13 15:19:14 +0530411}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530412func (fd *Field) Enum() protoreflect.EnumDescriptor {
Naveen Sampath04696f72022-06-13 15:19:14 +0530413 return fd.L1.Enum
414}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530415func (fd *Field) Message() protoreflect.MessageDescriptor {
Naveen Sampath04696f72022-06-13 15:19:14 +0530416 return fd.L1.Message
417}
Abhay Kumarfe505f22025-11-10 14:16:31 +0000418func (fd *Field) IsMapEntry() bool {
419 parent, ok := fd.L0.Parent.(protoreflect.MessageDescriptor)
420 return ok && parent.IsMapEntry()
421}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530422func (fd *Field) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, fd) }
423func (fd *Field) ProtoType(protoreflect.FieldDescriptor) {}
Naveen Sampath04696f72022-06-13 15:19:14 +0530424
425// EnforceUTF8 is a pseudo-internal API to determine whether to enforce UTF-8
426// validation for the string field. This exists for Google-internal use only
427// since proto3 did not enforce UTF-8 validity prior to the open-source release.
428// If this method does not exist, the default is to enforce valid UTF-8.
429//
430// WARNING: This method is exempt from the compatibility promise and may be
431// removed in the future without warning.
432func (fd *Field) EnforceUTF8() bool {
Abhay Kumarfe505f22025-11-10 14:16:31 +0000433 return fd.L1.EditionFeatures.IsUTF8Validated
Naveen Sampath04696f72022-06-13 15:19:14 +0530434}
435
436func (od *Oneof) IsSynthetic() bool {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530437 return od.L0.ParentFile.L1.Syntax == protoreflect.Proto3 && len(od.L1.Fields.List) == 1 && od.L1.Fields.List[0].HasOptionalKeyword()
Naveen Sampath04696f72022-06-13 15:19:14 +0530438}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530439func (od *Oneof) Options() protoreflect.ProtoMessage {
Naveen Sampath04696f72022-06-13 15:19:14 +0530440 if f := od.L1.Options; f != nil {
441 return f()
442 }
443 return descopts.Oneof
444}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530445func (od *Oneof) Fields() protoreflect.FieldDescriptors { return &od.L1.Fields }
446func (od *Oneof) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, od) }
447func (od *Oneof) ProtoType(protoreflect.OneofDescriptor) {}
Naveen Sampath04696f72022-06-13 15:19:14 +0530448
449type (
450 Extension struct {
451 Base
452 L1 ExtensionL1
453 L2 *ExtensionL2 // protected by fileDesc.once
454 }
455 ExtensionL1 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530456 Number protoreflect.FieldNumber
457 Extendee protoreflect.MessageDescriptor
458 Cardinality protoreflect.Cardinality
459 Kind protoreflect.Kind
Abhay Kumarfe505f22025-11-10 14:16:31 +0000460 IsLazy bool
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530461 EditionFeatures EditionFeatures
Naveen Sampath04696f72022-06-13 15:19:14 +0530462 }
463 ExtensionL2 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530464 Options func() protoreflect.ProtoMessage
Naveen Sampath04696f72022-06-13 15:19:14 +0530465 StringName stringName
466 IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto
Naveen Sampath04696f72022-06-13 15:19:14 +0530467 Default defaultValue
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530468 Enum protoreflect.EnumDescriptor
469 Message protoreflect.MessageDescriptor
Naveen Sampath04696f72022-06-13 15:19:14 +0530470 }
471)
472
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530473func (xd *Extension) Options() protoreflect.ProtoMessage {
Naveen Sampath04696f72022-06-13 15:19:14 +0530474 if f := xd.lazyInit().Options; f != nil {
475 return f()
476 }
477 return descopts.Field
478}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530479func (xd *Extension) Number() protoreflect.FieldNumber { return xd.L1.Number }
480func (xd *Extension) Cardinality() protoreflect.Cardinality { return xd.L1.Cardinality }
481func (xd *Extension) Kind() protoreflect.Kind { return xd.L1.Kind }
482func (xd *Extension) HasJSONName() bool { return xd.lazyInit().StringName.hasJSON }
483func (xd *Extension) JSONName() string { return xd.lazyInit().StringName.getJSON(xd) }
484func (xd *Extension) TextName() string { return xd.lazyInit().StringName.getText(xd) }
485func (xd *Extension) HasPresence() bool { return xd.L1.Cardinality != protoreflect.Repeated }
Naveen Sampath04696f72022-06-13 15:19:14 +0530486func (xd *Extension) HasOptionalKeyword() bool {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530487 return (xd.L0.ParentFile.L1.Syntax == protoreflect.Proto2 && xd.L1.Cardinality == protoreflect.Optional) || xd.lazyInit().IsProto3Optional
Naveen Sampath04696f72022-06-13 15:19:14 +0530488}
Abhay Kumarfe505f22025-11-10 14:16:31 +0000489func (xd *Extension) IsPacked() bool {
490 if xd.L1.Cardinality != protoreflect.Repeated {
491 return false
492 }
493 switch xd.L1.Kind {
494 case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind:
495 return false
496 }
497 return xd.L1.EditionFeatures.IsPacked
498}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530499func (xd *Extension) IsExtension() bool { return true }
500func (xd *Extension) IsWeak() bool { return false }
Abhay Kumarfe505f22025-11-10 14:16:31 +0000501func (xd *Extension) IsLazy() bool { return xd.L1.IsLazy }
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530502func (xd *Extension) IsList() bool { return xd.Cardinality() == protoreflect.Repeated }
503func (xd *Extension) IsMap() bool { return false }
504func (xd *Extension) MapKey() protoreflect.FieldDescriptor { return nil }
505func (xd *Extension) MapValue() protoreflect.FieldDescriptor { return nil }
506func (xd *Extension) HasDefault() bool { return xd.lazyInit().Default.has }
507func (xd *Extension) Default() protoreflect.Value { return xd.lazyInit().Default.get(xd) }
508func (xd *Extension) DefaultEnumValue() protoreflect.EnumValueDescriptor {
509 return xd.lazyInit().Default.enum
510}
511func (xd *Extension) ContainingOneof() protoreflect.OneofDescriptor { return nil }
512func (xd *Extension) ContainingMessage() protoreflect.MessageDescriptor { return xd.L1.Extendee }
513func (xd *Extension) Enum() protoreflect.EnumDescriptor { return xd.lazyInit().Enum }
514func (xd *Extension) Message() protoreflect.MessageDescriptor { return xd.lazyInit().Message }
515func (xd *Extension) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, xd) }
516func (xd *Extension) ProtoType(protoreflect.FieldDescriptor) {}
517func (xd *Extension) ProtoInternal(pragma.DoNotImplement) {}
Naveen Sampath04696f72022-06-13 15:19:14 +0530518func (xd *Extension) lazyInit() *ExtensionL2 {
519 xd.L0.ParentFile.lazyInit() // implicitly initializes L2
520 return xd.L2
521}
522
523type (
524 Service struct {
525 Base
526 L1 ServiceL1
527 L2 *ServiceL2 // protected by fileDesc.once
528 }
529 ServiceL1 struct{}
530 ServiceL2 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530531 Options func() protoreflect.ProtoMessage
Naveen Sampath04696f72022-06-13 15:19:14 +0530532 Methods Methods
533 }
534
535 Method struct {
536 Base
537 L1 MethodL1
538 }
539 MethodL1 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530540 Options func() protoreflect.ProtoMessage
541 Input protoreflect.MessageDescriptor
542 Output protoreflect.MessageDescriptor
Naveen Sampath04696f72022-06-13 15:19:14 +0530543 IsStreamingClient bool
544 IsStreamingServer bool
545 }
546)
547
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530548func (sd *Service) Options() protoreflect.ProtoMessage {
Naveen Sampath04696f72022-06-13 15:19:14 +0530549 if f := sd.lazyInit().Options; f != nil {
550 return f()
551 }
552 return descopts.Service
553}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530554func (sd *Service) Methods() protoreflect.MethodDescriptors { return &sd.lazyInit().Methods }
555func (sd *Service) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, sd) }
556func (sd *Service) ProtoType(protoreflect.ServiceDescriptor) {}
557func (sd *Service) ProtoInternal(pragma.DoNotImplement) {}
Naveen Sampath04696f72022-06-13 15:19:14 +0530558func (sd *Service) lazyInit() *ServiceL2 {
559 sd.L0.ParentFile.lazyInit() // implicitly initializes L2
560 return sd.L2
561}
562
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530563func (md *Method) Options() protoreflect.ProtoMessage {
Naveen Sampath04696f72022-06-13 15:19:14 +0530564 if f := md.L1.Options; f != nil {
565 return f()
566 }
567 return descopts.Method
568}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530569func (md *Method) Input() protoreflect.MessageDescriptor { return md.L1.Input }
570func (md *Method) Output() protoreflect.MessageDescriptor { return md.L1.Output }
571func (md *Method) IsStreamingClient() bool { return md.L1.IsStreamingClient }
572func (md *Method) IsStreamingServer() bool { return md.L1.IsStreamingServer }
573func (md *Method) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) }
574func (md *Method) ProtoType(protoreflect.MethodDescriptor) {}
575func (md *Method) ProtoInternal(pragma.DoNotImplement) {}
Naveen Sampath04696f72022-06-13 15:19:14 +0530576
577// Surrogate files are can be used to create standalone descriptors
578// where the syntax is only information derived from the parent file.
579var (
Abhay Kumarfe505f22025-11-10 14:16:31 +0000580 SurrogateProto2 = &File{L1: FileL1{Syntax: protoreflect.Proto2}, L2: &FileL2{}}
581 SurrogateProto3 = &File{L1: FileL1{Syntax: protoreflect.Proto3}, L2: &FileL2{}}
582 SurrogateEdition2023 = &File{L1: FileL1{Syntax: protoreflect.Editions, Edition: Edition2023}, L2: &FileL2{}}
Naveen Sampath04696f72022-06-13 15:19:14 +0530583)
584
585type (
586 Base struct {
587 L0 BaseL0
588 }
589 BaseL0 struct {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530590 FullName protoreflect.FullName // must be populated
591 ParentFile *File // must be populated
592 Parent protoreflect.Descriptor
Naveen Sampath04696f72022-06-13 15:19:14 +0530593 Index int
594 }
595)
596
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530597func (d *Base) Name() protoreflect.Name { return d.L0.FullName.Name() }
598func (d *Base) FullName() protoreflect.FullName { return d.L0.FullName }
599func (d *Base) ParentFile() protoreflect.FileDescriptor {
Naveen Sampath04696f72022-06-13 15:19:14 +0530600 if d.L0.ParentFile == SurrogateProto2 || d.L0.ParentFile == SurrogateProto3 {
601 return nil // surrogate files are not real parents
602 }
603 return d.L0.ParentFile
604}
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530605func (d *Base) Parent() protoreflect.Descriptor { return d.L0.Parent }
Naveen Sampath04696f72022-06-13 15:19:14 +0530606func (d *Base) Index() int { return d.L0.Index }
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530607func (d *Base) Syntax() protoreflect.Syntax { return d.L0.ParentFile.Syntax() }
Naveen Sampath04696f72022-06-13 15:19:14 +0530608func (d *Base) IsPlaceholder() bool { return false }
609func (d *Base) ProtoInternal(pragma.DoNotImplement) {}
610
611type stringName struct {
612 hasJSON bool
613 once sync.Once
614 nameJSON string
615 nameText string
616}
617
618// InitJSON initializes the name. It is exported for use by other internal packages.
619func (s *stringName) InitJSON(name string) {
620 s.hasJSON = true
621 s.nameJSON = name
622}
623
Abhay Kumarfe505f22025-11-10 14:16:31 +0000624// Returns true if this field is structured like the synthetic field of a proto2
625// group. This allows us to expand our treatment of delimited fields without
626// breaking proto2 files that have been upgraded to editions.
627func isGroupLike(fd protoreflect.FieldDescriptor) bool {
628 // Groups are always group types.
629 if fd.Kind() != protoreflect.GroupKind {
630 return false
631 }
632
633 // Group fields are always the lowercase type name.
634 if strings.ToLower(string(fd.Message().Name())) != string(fd.Name()) {
635 return false
636 }
637
638 // Groups could only be defined in the same file they're used.
639 if fd.Message().ParentFile() != fd.ParentFile() {
640 return false
641 }
642
643 // Group messages are always defined in the same scope as the field. File
644 // level extensions will compare NULL == NULL here, which is why the file
645 // comparison above is necessary to ensure both come from the same file.
646 if fd.IsExtension() {
647 return fd.Parent() == fd.Message().Parent()
648 }
649 return fd.ContainingMessage() == fd.Message().Parent()
650}
651
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530652func (s *stringName) lazyInit(fd protoreflect.FieldDescriptor) *stringName {
Naveen Sampath04696f72022-06-13 15:19:14 +0530653 s.once.Do(func() {
654 if fd.IsExtension() {
655 // For extensions, JSON and text are formatted the same way.
656 var name string
657 if messageset.IsMessageSetExtension(fd) {
658 name = string("[" + fd.FullName().Parent() + "]")
659 } else {
660 name = string("[" + fd.FullName() + "]")
661 }
662 s.nameJSON = name
663 s.nameText = name
664 } else {
665 // Format the JSON name.
666 if !s.hasJSON {
667 s.nameJSON = strs.JSONCamelCase(string(fd.Name()))
668 }
669
670 // Format the text name.
671 s.nameText = string(fd.Name())
Abhay Kumarfe505f22025-11-10 14:16:31 +0000672 if isGroupLike(fd) {
Naveen Sampath04696f72022-06-13 15:19:14 +0530673 s.nameText = string(fd.Message().Name())
674 }
675 }
676 })
677 return s
678}
679
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530680func (s *stringName) getJSON(fd protoreflect.FieldDescriptor) string { return s.lazyInit(fd).nameJSON }
681func (s *stringName) getText(fd protoreflect.FieldDescriptor) string { return s.lazyInit(fd).nameText }
Naveen Sampath04696f72022-06-13 15:19:14 +0530682
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530683func DefaultValue(v protoreflect.Value, ev protoreflect.EnumValueDescriptor) defaultValue {
Naveen Sampath04696f72022-06-13 15:19:14 +0530684 dv := defaultValue{has: v.IsValid(), val: v, enum: ev}
685 if b, ok := v.Interface().([]byte); ok {
686 // Store a copy of the default bytes, so that we can detect
687 // accidental mutations of the original value.
688 dv.bytes = append([]byte(nil), b...)
689 }
690 return dv
691}
692
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530693func unmarshalDefault(b []byte, k protoreflect.Kind, pf *File, ed protoreflect.EnumDescriptor) defaultValue {
694 var evs protoreflect.EnumValueDescriptors
695 if k == protoreflect.EnumKind {
Naveen Sampath04696f72022-06-13 15:19:14 +0530696 // If the enum is declared within the same file, be careful not to
697 // blindly call the Values method, lest we bind ourselves in a deadlock.
698 if e, ok := ed.(*Enum); ok && e.L0.ParentFile == pf {
699 evs = &e.L2.Values
700 } else {
701 evs = ed.Values()
702 }
703
704 // If we are unable to resolve the enum dependency, use a placeholder
705 // enum value since we will not be able to parse the default value.
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530706 if ed.IsPlaceholder() && protoreflect.Name(b).IsValid() {
707 v := protoreflect.ValueOfEnum(0)
708 ev := PlaceholderEnumValue(ed.FullName().Parent().Append(protoreflect.Name(b)))
Naveen Sampath04696f72022-06-13 15:19:14 +0530709 return DefaultValue(v, ev)
710 }
711 }
712
713 v, ev, err := defval.Unmarshal(string(b), k, evs, defval.Descriptor)
714 if err != nil {
715 panic(err)
716 }
717 return DefaultValue(v, ev)
718}
719
720type defaultValue struct {
721 has bool
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530722 val protoreflect.Value
723 enum protoreflect.EnumValueDescriptor
Naveen Sampath04696f72022-06-13 15:19:14 +0530724 bytes []byte
725}
726
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530727func (dv *defaultValue) get(fd protoreflect.FieldDescriptor) protoreflect.Value {
Naveen Sampath04696f72022-06-13 15:19:14 +0530728 // Return the zero value as the default if unpopulated.
729 if !dv.has {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530730 if fd.Cardinality() == protoreflect.Repeated {
731 return protoreflect.Value{}
Naveen Sampath04696f72022-06-13 15:19:14 +0530732 }
733 switch fd.Kind() {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530734 case protoreflect.BoolKind:
735 return protoreflect.ValueOfBool(false)
736 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
737 return protoreflect.ValueOfInt32(0)
738 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
739 return protoreflect.ValueOfInt64(0)
740 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
741 return protoreflect.ValueOfUint32(0)
742 case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
743 return protoreflect.ValueOfUint64(0)
744 case protoreflect.FloatKind:
745 return protoreflect.ValueOfFloat32(0)
746 case protoreflect.DoubleKind:
747 return protoreflect.ValueOfFloat64(0)
748 case protoreflect.StringKind:
749 return protoreflect.ValueOfString("")
750 case protoreflect.BytesKind:
751 return protoreflect.ValueOfBytes(nil)
752 case protoreflect.EnumKind:
Naveen Sampath04696f72022-06-13 15:19:14 +0530753 if evs := fd.Enum().Values(); evs.Len() > 0 {
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530754 return protoreflect.ValueOfEnum(evs.Get(0).Number())
Naveen Sampath04696f72022-06-13 15:19:14 +0530755 }
Akash Reddy Kankanala105581b2024-09-11 05:20:38 +0530756 return protoreflect.ValueOfEnum(0)
Naveen Sampath04696f72022-06-13 15:19:14 +0530757 }
758 }
759
760 if len(dv.bytes) > 0 && !bytes.Equal(dv.bytes, dv.val.Bytes()) {
761 // TODO: Avoid panic if we're running with the race detector
762 // and instead spawn a goroutine that periodically resets
763 // this value back to the original to induce a race.
764 panic(fmt.Sprintf("detected mutation on the default bytes for %v", fd.FullName()))
765 }
766 return dv.val
767}