blob: 688aabe434efc1c4f20e9d8d08fa639b7f0454e4 [file] [log] [blame]
khenaidoo7d3c5582021-08-11 18:09:44 -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"
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053010 "strings"
khenaidoo7d3c5582021-08-11 18:09:44 -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"
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053021 "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
khenaidoo7d3c5582021-08-11 18:09:44 -040036)
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
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +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.
khenaidoo7d3c5582021-08-11 18:09:44 -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 {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053062 Syntax protoreflect.Syntax
63 Edition Edition // Only used if Syntax == Editions
khenaidoo7d3c5582021-08-11 18:09:44 -040064 Path string
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053065 Package protoreflect.FullName
khenaidoo7d3c5582021-08-11 18:09:44 -040066
67 Enums Enums
68 Messages Messages
69 Extensions Extensions
70 Services Services
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053071
72 EditionFeatures EditionFeatures
khenaidoo7d3c5582021-08-11 18:09:44 -040073 }
74 FileL2 struct {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053075 Options func() protoreflect.ProtoMessage
khenaidoo7d3c5582021-08-11 18:09:44 -040076 Imports FileImports
77 Locations SourceLocations
78 }
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053079
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 }
khenaidoo7d3c5582021-08-11 18:09:44 -0400123)
124
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530125func (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 }
khenaidoo7d3c5582021-08-11 18:09:44 -0400134func (fd *File) IsPlaceholder() bool { return false }
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530135func (fd *File) Options() protoreflect.ProtoMessage {
khenaidoo7d3c5582021-08-11 18:09:44 -0400136 if f := fd.lazyInit().Options; f != nil {
137 return f()
138 }
139 return descopts.File
140}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530141func (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) {}
khenaidoo7d3c5582021-08-11 18:09:44 -0400152
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
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530186
187 EditionFeatures EditionFeatures
khenaidoo7d3c5582021-08-11 18:09:44 -0400188 }
189 EnumL2 struct {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530190 Options func() protoreflect.ProtoMessage
khenaidoo7d3c5582021-08-11 18:09:44 -0400191 Values EnumValues
192 ReservedNames Names
193 ReservedRanges EnumRanges
194 }
195
196 EnumValue struct {
197 Base
198 L1 EnumValueL1
199 }
200 EnumValueL1 struct {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530201 Options func() protoreflect.ProtoMessage
202 Number protoreflect.EnumNumber
khenaidoo7d3c5582021-08-11 18:09:44 -0400203 }
204)
205
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530206func (ed *Enum) Options() protoreflect.ProtoMessage {
khenaidoo7d3c5582021-08-11 18:09:44 -0400207 if f := ed.lazyInit().Options; f != nil {
208 return f()
209 }
210 return descopts.Enum
211}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530212func (ed *Enum) Values() protoreflect.EnumValueDescriptors {
khenaidoo7d3c5582021-08-11 18:09:44 -0400213 if ed.L1.eagerValues {
214 return &ed.L2.Values
215 }
216 return &ed.lazyInit().Values
217}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530218func (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) {}
khenaidoo7d3c5582021-08-11 18:09:44 -0400222func (ed *Enum) lazyInit() *EnumL2 {
223 ed.L0.ParentFile.lazyInit() // implicitly initializes L2
224 return ed.L2
225}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530226func (ed *Enum) IsClosed() bool {
227 return !ed.L1.EditionFeatures.IsOpenEnum
228}
khenaidoo7d3c5582021-08-11 18:09:44 -0400229
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530230func (ed *EnumValue) Options() protoreflect.ProtoMessage {
khenaidoo7d3c5582021-08-11 18:09:44 -0400231 if f := ed.L1.Options; f != nil {
232 return f()
233 }
234 return descopts.EnumValue
235}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530236func (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) {}
khenaidoo7d3c5582021-08-11 18:09:44 -0400239
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
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530252
253 EditionFeatures EditionFeatures
khenaidoo7d3c5582021-08-11 18:09:44 -0400254 }
255 MessageL2 struct {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530256 Options func() protoreflect.ProtoMessage
khenaidoo7d3c5582021-08-11 18:09:44 -0400257 Fields Fields
258 Oneofs Oneofs
259 ReservedNames Names
260 ReservedRanges FieldRanges
261 RequiredNumbers FieldNumbers // must be consistent with Fields.Cardinality
262 ExtensionRanges FieldRanges
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530263 ExtensionRangeOptions []func() protoreflect.ProtoMessage // must be same length as ExtensionRanges
khenaidoo7d3c5582021-08-11 18:09:44 -0400264 }
265
266 Field struct {
267 Base
268 L1 FieldL1
269 }
270 FieldL1 struct {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530271 Options func() protoreflect.ProtoMessage
272 Number protoreflect.FieldNumber
273 Cardinality protoreflect.Cardinality // must be consistent with Message.RequiredNumbers
274 Kind protoreflect.Kind
khenaidoo7d3c5582021-08-11 18:09:44 -0400275 StringName stringName
276 IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530277 IsLazy bool // promoted from google.protobuf.FieldOptions
khenaidoo7d3c5582021-08-11 18:09:44 -0400278 Default defaultValue
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530279 ContainingOneof protoreflect.OneofDescriptor // must be consistent with Message.Oneofs.Fields
280 Enum protoreflect.EnumDescriptor
281 Message protoreflect.MessageDescriptor
282
283 EditionFeatures EditionFeatures
khenaidoo7d3c5582021-08-11 18:09:44 -0400284 }
285
286 Oneof struct {
287 Base
288 L1 OneofL1
289 }
290 OneofL1 struct {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530291 Options func() protoreflect.ProtoMessage
khenaidoo7d3c5582021-08-11 18:09:44 -0400292 Fields OneofFields // must be consistent with Message.Fields.ContainingOneof
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530293
294 EditionFeatures EditionFeatures
khenaidoo7d3c5582021-08-11 18:09:44 -0400295 }
296)
297
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530298func (md *Message) Options() protoreflect.ProtoMessage {
khenaidoo7d3c5582021-08-11 18:09:44 -0400299 if f := md.lazyInit().Options; f != nil {
300 return f()
301 }
302 return descopts.Message
303}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530304func (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 {
khenaidoo7d3c5582021-08-11 18:09:44 -0400312 if f := md.lazyInit().ExtensionRangeOptions[i]; f != nil {
313 return f()
314 }
315 return descopts.ExtensionRange
316}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530317func (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) }
khenaidoo7d3c5582021-08-11 18:09:44 -0400322func (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
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530336func (fd *Field) Options() protoreflect.ProtoMessage {
khenaidoo7d3c5582021-08-11 18:09:44 -0400337 if f := fd.L1.Options; f != nil {
338 return f()
339 }
340 return descopts.Field
341}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530342func (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) }
khenaidoo7d3c5582021-08-11 18:09:44 -0400350func (fd *Field) HasPresence() bool {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530351 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
khenaidoo7d3c5582021-08-11 18:09:44 -0400355}
356func (fd *Field) HasOptionalKeyword() bool {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530357 return (fd.L0.ParentFile.L1.Syntax == protoreflect.Proto2 && fd.L1.Cardinality == protoreflect.Optional && fd.L1.ContainingOneof == nil) || fd.L1.IsProto3Optional
khenaidoo7d3c5582021-08-11 18:09:44 -0400358}
359func (fd *Field) IsPacked() bool {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530360 if fd.L1.Cardinality != protoreflect.Repeated {
361 return false
khenaidoo7d3c5582021-08-11 18:09:44 -0400362 }
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530363 switch fd.L1.Kind {
364 case protoreflect.StringKind, protoreflect.BytesKind, protoreflect.MessageKind, protoreflect.GroupKind:
365 return false
366 }
367 return fd.L1.EditionFeatures.IsPacked
khenaidoo7d3c5582021-08-11 18:09:44 -0400368}
369func (fd *Field) IsExtension() bool { return false }
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530370func (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() }
khenaidoo7d3c5582021-08-11 18:09:44 -0400373func (fd *Field) IsMap() bool { return fd.Message() != nil && fd.Message().IsMapEntry() }
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530374func (fd *Field) MapKey() protoreflect.FieldDescriptor {
khenaidoo7d3c5582021-08-11 18:09:44 -0400375 if !fd.IsMap() {
376 return nil
377 }
378 return fd.Message().Fields().ByNumber(genid.MapEntry_Key_field_number)
379}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530380func (fd *Field) MapValue() protoreflect.FieldDescriptor {
khenaidoo7d3c5582021-08-11 18:09:44 -0400381 if !fd.IsMap() {
382 return nil
383 }
384 return fd.Message().Fields().ByNumber(genid.MapEntry_Value_field_number)
385}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530386func (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)
khenaidoo7d3c5582021-08-11 18:09:44 -0400392}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530393func (fd *Field) Enum() protoreflect.EnumDescriptor {
khenaidoo7d3c5582021-08-11 18:09:44 -0400394 return fd.L1.Enum
395}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530396func (fd *Field) Message() protoreflect.MessageDescriptor {
khenaidoo7d3c5582021-08-11 18:09:44 -0400397 return fd.L1.Message
398}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530399func (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) {}
khenaidoo7d3c5582021-08-11 18:09:44 -0400405
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 {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530414 return fd.L1.EditionFeatures.IsUTF8Validated
khenaidoo7d3c5582021-08-11 18:09:44 -0400415}
416
417func (od *Oneof) IsSynthetic() bool {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530418 return od.L0.ParentFile.L1.Syntax == protoreflect.Proto3 && len(od.L1.Fields.List) == 1 && od.L1.Fields.List[0].HasOptionalKeyword()
khenaidoo7d3c5582021-08-11 18:09:44 -0400419}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530420func (od *Oneof) Options() protoreflect.ProtoMessage {
khenaidoo7d3c5582021-08-11 18:09:44 -0400421 if f := od.L1.Options; f != nil {
422 return f()
423 }
424 return descopts.Oneof
425}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530426func (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) {}
khenaidoo7d3c5582021-08-11 18:09:44 -0400429
430type (
431 Extension struct {
432 Base
433 L1 ExtensionL1
434 L2 *ExtensionL2 // protected by fileDesc.once
435 }
436 ExtensionL1 struct {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530437 Number protoreflect.FieldNumber
438 Extendee protoreflect.MessageDescriptor
439 Cardinality protoreflect.Cardinality
440 Kind protoreflect.Kind
441 IsLazy bool
442 EditionFeatures EditionFeatures
khenaidoo7d3c5582021-08-11 18:09:44 -0400443 }
444 ExtensionL2 struct {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530445 Options func() protoreflect.ProtoMessage
khenaidoo7d3c5582021-08-11 18:09:44 -0400446 StringName stringName
447 IsProto3Optional bool // promoted from google.protobuf.FieldDescriptorProto
khenaidoo7d3c5582021-08-11 18:09:44 -0400448 Default defaultValue
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530449 Enum protoreflect.EnumDescriptor
450 Message protoreflect.MessageDescriptor
khenaidoo7d3c5582021-08-11 18:09:44 -0400451 }
452)
453
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530454func (xd *Extension) Options() protoreflect.ProtoMessage {
khenaidoo7d3c5582021-08-11 18:09:44 -0400455 if f := xd.lazyInit().Options; f != nil {
456 return f()
457 }
458 return descopts.Field
459}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530460func (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 }
khenaidoo7d3c5582021-08-11 18:09:44 -0400467func (xd *Extension) HasOptionalKeyword() bool {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530468 return (xd.L0.ParentFile.L1.Syntax == protoreflect.Proto2 && xd.L1.Cardinality == protoreflect.Optional) || xd.lazyInit().IsProto3Optional
khenaidoo7d3c5582021-08-11 18:09:44 -0400469}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530470func (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) {}
khenaidoo7d3c5582021-08-11 18:09:44 -0400499func (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 {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530512 Options func() protoreflect.ProtoMessage
khenaidoo7d3c5582021-08-11 18:09:44 -0400513 Methods Methods
514 }
515
516 Method struct {
517 Base
518 L1 MethodL1
519 }
520 MethodL1 struct {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530521 Options func() protoreflect.ProtoMessage
522 Input protoreflect.MessageDescriptor
523 Output protoreflect.MessageDescriptor
khenaidoo7d3c5582021-08-11 18:09:44 -0400524 IsStreamingClient bool
525 IsStreamingServer bool
526 }
527)
528
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530529func (sd *Service) Options() protoreflect.ProtoMessage {
khenaidoo7d3c5582021-08-11 18:09:44 -0400530 if f := sd.lazyInit().Options; f != nil {
531 return f()
532 }
533 return descopts.Service
534}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530535func (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) {}
khenaidoo7d3c5582021-08-11 18:09:44 -0400539func (sd *Service) lazyInit() *ServiceL2 {
540 sd.L0.ParentFile.lazyInit() // implicitly initializes L2
541 return sd.L2
542}
543
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530544func (md *Method) Options() protoreflect.ProtoMessage {
khenaidoo7d3c5582021-08-11 18:09:44 -0400545 if f := md.L1.Options; f != nil {
546 return f()
547 }
548 return descopts.Method
549}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530550func (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) {}
khenaidoo7d3c5582021-08-11 18:09:44 -0400557
558// Surrogate files are can be used to create standalone descriptors
559// where the syntax is only information derived from the parent file.
560var (
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530561 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{}}
khenaidoo7d3c5582021-08-11 18:09:44 -0400564)
565
566type (
567 Base struct {
568 L0 BaseL0
569 }
570 BaseL0 struct {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530571 FullName protoreflect.FullName // must be populated
572 ParentFile *File // must be populated
573 Parent protoreflect.Descriptor
khenaidoo7d3c5582021-08-11 18:09:44 -0400574 Index int
575 }
576)
577
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530578func (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 {
khenaidoo7d3c5582021-08-11 18:09:44 -0400581 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}
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530586func (d *Base) Parent() protoreflect.Descriptor { return d.L0.Parent }
khenaidoo7d3c5582021-08-11 18:09:44 -0400587func (d *Base) Index() int { return d.L0.Index }
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530588func (d *Base) Syntax() protoreflect.Syntax { return d.L0.ParentFile.Syntax() }
khenaidoo7d3c5582021-08-11 18:09:44 -0400589func (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
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530605// 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 {
khenaidoo7d3c5582021-08-11 18:09:44 -0400634 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())
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530653 if isGroupLike(fd) {
khenaidoo7d3c5582021-08-11 18:09:44 -0400654 s.nameText = string(fd.Message().Name())
655 }
656 }
657 })
658 return s
659}
660
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530661func (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 }
khenaidoo7d3c5582021-08-11 18:09:44 -0400663
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530664func DefaultValue(v protoreflect.Value, ev protoreflect.EnumValueDescriptor) defaultValue {
khenaidoo7d3c5582021-08-11 18:09:44 -0400665 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
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530674func unmarshalDefault(b []byte, k protoreflect.Kind, pf *File, ed protoreflect.EnumDescriptor) defaultValue {
675 var evs protoreflect.EnumValueDescriptors
676 if k == protoreflect.EnumKind {
khenaidoo7d3c5582021-08-11 18:09:44 -0400677 // 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.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530687 if ed.IsPlaceholder() && protoreflect.Name(b).IsValid() {
688 v := protoreflect.ValueOfEnum(0)
689 ev := PlaceholderEnumValue(ed.FullName().Parent().Append(protoreflect.Name(b)))
khenaidoo7d3c5582021-08-11 18:09:44 -0400690 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
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530703 val protoreflect.Value
704 enum protoreflect.EnumValueDescriptor
khenaidoo7d3c5582021-08-11 18:09:44 -0400705 bytes []byte
706}
707
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530708func (dv *defaultValue) get(fd protoreflect.FieldDescriptor) protoreflect.Value {
khenaidoo7d3c5582021-08-11 18:09:44 -0400709 // Return the zero value as the default if unpopulated.
710 if !dv.has {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530711 if fd.Cardinality() == protoreflect.Repeated {
712 return protoreflect.Value{}
khenaidoo7d3c5582021-08-11 18:09:44 -0400713 }
714 switch fd.Kind() {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530715 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:
khenaidoo7d3c5582021-08-11 18:09:44 -0400734 if evs := fd.Enum().Values(); evs.Len() > 0 {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530735 return protoreflect.ValueOfEnum(evs.Get(0).Number())
khenaidoo7d3c5582021-08-11 18:09:44 -0400736 }
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530737 return protoreflect.ValueOfEnum(0)
khenaidoo7d3c5582021-08-11 18:09:44 -0400738 }
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}