desc_init.go raw
1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package protodesc
6
7 import (
8 "google.golang.org/protobuf/internal/errors"
9 "google.golang.org/protobuf/internal/filedesc"
10 "google.golang.org/protobuf/internal/strs"
11 "google.golang.org/protobuf/proto"
12 "google.golang.org/protobuf/reflect/protoreflect"
13
14 "google.golang.org/protobuf/types/descriptorpb"
15 )
16
17 type descsByName map[protoreflect.FullName]protoreflect.Descriptor
18
19 func (r descsByName) initEnumDeclarations(eds []*descriptorpb.EnumDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (es []filedesc.Enum, err error) {
20 es = make([]filedesc.Enum, len(eds)) // allocate up-front to ensure stable pointers
21 for i, ed := range eds {
22 e := &es[i]
23 e.L2 = new(filedesc.EnumL2)
24 if e.L0, err = r.makeBase(e, parent, ed.GetName(), i, sb); err != nil {
25 return nil, err
26 }
27 if opts := ed.GetOptions(); opts != nil {
28 opts = proto.Clone(opts).(*descriptorpb.EnumOptions)
29 e.L2.Options = func() protoreflect.ProtoMessage { return opts }
30 }
31 e.L1.EditionFeatures = mergeEditionFeatures(parent, ed.GetOptions().GetFeatures())
32 e.L1.Visibility = int32(ed.GetVisibility())
33 for _, s := range ed.GetReservedName() {
34 e.L2.ReservedNames.List = append(e.L2.ReservedNames.List, protoreflect.Name(s))
35 }
36 for _, rr := range ed.GetReservedRange() {
37 e.L2.ReservedRanges.List = append(e.L2.ReservedRanges.List, [2]protoreflect.EnumNumber{
38 protoreflect.EnumNumber(rr.GetStart()),
39 protoreflect.EnumNumber(rr.GetEnd()),
40 })
41 }
42 if e.L2.Values.List, err = r.initEnumValuesFromDescriptorProto(ed.GetValue(), e, sb); err != nil {
43 return nil, err
44 }
45 }
46 return es, nil
47 }
48
49 func (r descsByName) initEnumValuesFromDescriptorProto(vds []*descriptorpb.EnumValueDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (vs []filedesc.EnumValue, err error) {
50 vs = make([]filedesc.EnumValue, len(vds)) // allocate up-front to ensure stable pointers
51 for i, vd := range vds {
52 v := &vs[i]
53 if v.L0, err = r.makeBase(v, parent, vd.GetName(), i, sb); err != nil {
54 return nil, err
55 }
56 if opts := vd.GetOptions(); opts != nil {
57 opts = proto.Clone(opts).(*descriptorpb.EnumValueOptions)
58 v.L1.Options = func() protoreflect.ProtoMessage { return opts }
59 }
60 v.L1.Number = protoreflect.EnumNumber(vd.GetNumber())
61 }
62 return vs, nil
63 }
64
65 func (r descsByName) initMessagesDeclarations(mds []*descriptorpb.DescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ms []filedesc.Message, err error) {
66 ms = make([]filedesc.Message, len(mds)) // allocate up-front to ensure stable pointers
67 for i, md := range mds {
68 m := &ms[i]
69 m.L2 = new(filedesc.MessageL2)
70 if m.L0, err = r.makeBase(m, parent, md.GetName(), i, sb); err != nil {
71 return nil, err
72 }
73 m.L1.EditionFeatures = mergeEditionFeatures(parent, md.GetOptions().GetFeatures())
74 m.L1.Visibility = int32(md.GetVisibility())
75 if opts := md.GetOptions(); opts != nil {
76 opts = proto.Clone(opts).(*descriptorpb.MessageOptions)
77 m.L2.Options = func() protoreflect.ProtoMessage { return opts }
78 m.L1.IsMapEntry = opts.GetMapEntry()
79 m.L1.IsMessageSet = opts.GetMessageSetWireFormat()
80 }
81 for _, s := range md.GetReservedName() {
82 m.L2.ReservedNames.List = append(m.L2.ReservedNames.List, protoreflect.Name(s))
83 }
84 for _, rr := range md.GetReservedRange() {
85 m.L2.ReservedRanges.List = append(m.L2.ReservedRanges.List, [2]protoreflect.FieldNumber{
86 protoreflect.FieldNumber(rr.GetStart()),
87 protoreflect.FieldNumber(rr.GetEnd()),
88 })
89 }
90 for _, xr := range md.GetExtensionRange() {
91 m.L2.ExtensionRanges.List = append(m.L2.ExtensionRanges.List, [2]protoreflect.FieldNumber{
92 protoreflect.FieldNumber(xr.GetStart()),
93 protoreflect.FieldNumber(xr.GetEnd()),
94 })
95 var optsFunc func() protoreflect.ProtoMessage
96 if opts := xr.GetOptions(); opts != nil {
97 opts = proto.Clone(opts).(*descriptorpb.ExtensionRangeOptions)
98 optsFunc = func() protoreflect.ProtoMessage { return opts }
99 }
100 m.L2.ExtensionRangeOptions = append(m.L2.ExtensionRangeOptions, optsFunc)
101 }
102 if m.L2.Fields.List, err = r.initFieldsFromDescriptorProto(md.GetField(), m, sb); err != nil {
103 return nil, err
104 }
105 if m.L2.Oneofs.List, err = r.initOneofsFromDescriptorProto(md.GetOneofDecl(), m, sb); err != nil {
106 return nil, err
107 }
108 if m.L1.Enums.List, err = r.initEnumDeclarations(md.GetEnumType(), m, sb); err != nil {
109 return nil, err
110 }
111 if m.L1.Messages.List, err = r.initMessagesDeclarations(md.GetNestedType(), m, sb); err != nil {
112 return nil, err
113 }
114 if m.L1.Extensions.List, err = r.initExtensionDeclarations(md.GetExtension(), m, sb); err != nil {
115 return nil, err
116 }
117 }
118 return ms, nil
119 }
120
121 // canBePacked returns whether the field can use packed encoding:
122 // https://protobuf.dev/programming-guides/encoding/#packed
123 func canBePacked(fd *descriptorpb.FieldDescriptorProto) bool {
124 if fd.GetLabel() != descriptorpb.FieldDescriptorProto_LABEL_REPEATED {
125 return false // not a repeated field
126 }
127
128 switch protoreflect.Kind(fd.GetType()) {
129 case protoreflect.MessageKind, protoreflect.GroupKind:
130 return false // not a scalar type field
131
132 case protoreflect.StringKind, protoreflect.BytesKind:
133 // string and bytes can explicitly not be declared as packed,
134 // see https://protobuf.dev/programming-guides/encoding/#packed
135 return false
136
137 default:
138 return true
139 }
140 }
141
142 func (r descsByName) initFieldsFromDescriptorProto(fds []*descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (fs []filedesc.Field, err error) {
143 fs = make([]filedesc.Field, len(fds)) // allocate up-front to ensure stable pointers
144 for i, fd := range fds {
145 f := &fs[i]
146 if f.L0, err = r.makeBase(f, parent, fd.GetName(), i, sb); err != nil {
147 return nil, err
148 }
149 f.L1.EditionFeatures = mergeEditionFeatures(parent, fd.GetOptions().GetFeatures())
150 f.L1.IsProto3Optional = fd.GetProto3Optional()
151 if opts := fd.GetOptions(); opts != nil {
152 opts = proto.Clone(opts).(*descriptorpb.FieldOptions)
153 f.L1.Options = func() protoreflect.ProtoMessage { return opts }
154 f.L1.IsLazy = opts.GetLazy()
155 if opts.Packed != nil {
156 f.L1.EditionFeatures.IsPacked = opts.GetPacked()
157 }
158 }
159 f.L1.Number = protoreflect.FieldNumber(fd.GetNumber())
160 f.L1.Cardinality = protoreflect.Cardinality(fd.GetLabel())
161 if fd.Type != nil {
162 f.L1.Kind = protoreflect.Kind(fd.GetType())
163 }
164 if fd.JsonName != nil {
165 f.L1.StringName.InitJSON(fd.GetJsonName())
166 }
167
168 if f.L1.EditionFeatures.IsLegacyRequired {
169 f.L1.Cardinality = protoreflect.Required
170 }
171
172 if f.L1.Kind == protoreflect.MessageKind && f.L1.EditionFeatures.IsDelimitedEncoded {
173 f.L1.Kind = protoreflect.GroupKind
174 }
175 }
176 return fs, nil
177 }
178
179 func (r descsByName) initOneofsFromDescriptorProto(ods []*descriptorpb.OneofDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (os []filedesc.Oneof, err error) {
180 os = make([]filedesc.Oneof, len(ods)) // allocate up-front to ensure stable pointers
181 for i, od := range ods {
182 o := &os[i]
183 if o.L0, err = r.makeBase(o, parent, od.GetName(), i, sb); err != nil {
184 return nil, err
185 }
186 o.L1.EditionFeatures = mergeEditionFeatures(parent, od.GetOptions().GetFeatures())
187 if opts := od.GetOptions(); opts != nil {
188 opts = proto.Clone(opts).(*descriptorpb.OneofOptions)
189 o.L1.Options = func() protoreflect.ProtoMessage { return opts }
190 }
191 }
192 return os, nil
193 }
194
195 func (r descsByName) initExtensionDeclarations(xds []*descriptorpb.FieldDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (xs []filedesc.Extension, err error) {
196 xs = make([]filedesc.Extension, len(xds)) // allocate up-front to ensure stable pointers
197 for i, xd := range xds {
198 x := &xs[i]
199 x.L2 = new(filedesc.ExtensionL2)
200 if x.L0, err = r.makeBase(x, parent, xd.GetName(), i, sb); err != nil {
201 return nil, err
202 }
203 x.L1.EditionFeatures = mergeEditionFeatures(parent, xd.GetOptions().GetFeatures())
204 if opts := xd.GetOptions(); opts != nil {
205 opts = proto.Clone(opts).(*descriptorpb.FieldOptions)
206 x.L2.Options = func() protoreflect.ProtoMessage { return opts }
207 if opts.Packed != nil {
208 x.L1.EditionFeatures.IsPacked = opts.GetPacked()
209 }
210 }
211 x.L1.Number = protoreflect.FieldNumber(xd.GetNumber())
212 x.L1.Cardinality = protoreflect.Cardinality(xd.GetLabel())
213 if xd.Type != nil {
214 x.L1.Kind = protoreflect.Kind(xd.GetType())
215 }
216 if xd.JsonName != nil {
217 x.L2.StringName.InitJSON(xd.GetJsonName())
218 }
219 if x.L1.Kind == protoreflect.MessageKind && x.L1.EditionFeatures.IsDelimitedEncoded {
220 x.L1.Kind = protoreflect.GroupKind
221 }
222 }
223 return xs, nil
224 }
225
226 func (r descsByName) initServiceDeclarations(sds []*descriptorpb.ServiceDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ss []filedesc.Service, err error) {
227 ss = make([]filedesc.Service, len(sds)) // allocate up-front to ensure stable pointers
228 for i, sd := range sds {
229 s := &ss[i]
230 s.L2 = new(filedesc.ServiceL2)
231 if s.L0, err = r.makeBase(s, parent, sd.GetName(), i, sb); err != nil {
232 return nil, err
233 }
234 if opts := sd.GetOptions(); opts != nil {
235 opts = proto.Clone(opts).(*descriptorpb.ServiceOptions)
236 s.L2.Options = func() protoreflect.ProtoMessage { return opts }
237 }
238 if s.L2.Methods.List, err = r.initMethodsFromDescriptorProto(sd.GetMethod(), s, sb); err != nil {
239 return nil, err
240 }
241 }
242 return ss, nil
243 }
244
245 func (r descsByName) initMethodsFromDescriptorProto(mds []*descriptorpb.MethodDescriptorProto, parent protoreflect.Descriptor, sb *strs.Builder) (ms []filedesc.Method, err error) {
246 ms = make([]filedesc.Method, len(mds)) // allocate up-front to ensure stable pointers
247 for i, md := range mds {
248 m := &ms[i]
249 if m.L0, err = r.makeBase(m, parent, md.GetName(), i, sb); err != nil {
250 return nil, err
251 }
252 if opts := md.GetOptions(); opts != nil {
253 opts = proto.Clone(opts).(*descriptorpb.MethodOptions)
254 m.L1.Options = func() protoreflect.ProtoMessage { return opts }
255 }
256 m.L1.IsStreamingClient = md.GetClientStreaming()
257 m.L1.IsStreamingServer = md.GetServerStreaming()
258 }
259 return ms, nil
260 }
261
262 func (r descsByName) makeBase(child, parent protoreflect.Descriptor, name string, idx int, sb *strs.Builder) (filedesc.BaseL0, error) {
263 if !protoreflect.Name(name).IsValid() {
264 return filedesc.BaseL0{}, errors.New("descriptor %q has an invalid nested name: %q", parent.FullName(), name)
265 }
266
267 // Derive the full name of the child.
268 // Note that enum values are a sibling to the enum parent in the namespace.
269 var fullName protoreflect.FullName
270 if _, ok := parent.(protoreflect.EnumDescriptor); ok {
271 fullName = sb.AppendFullName(parent.FullName().Parent(), protoreflect.Name(name))
272 } else {
273 fullName = sb.AppendFullName(parent.FullName(), protoreflect.Name(name))
274 }
275 if _, ok := r[fullName]; ok {
276 return filedesc.BaseL0{}, errors.New("descriptor %q already declared", fullName)
277 }
278 r[fullName] = child
279
280 // TODO: Verify that the full name does not already exist in the resolver?
281 // This is not as critical since most usages of NewFile will register
282 // the created file back into the registry, which will perform this check.
283
284 return filedesc.BaseL0{
285 FullName: fullName,
286 ParentFile: parent.ParentFile().(*filedesc.File),
287 Parent: parent,
288 Index: idx,
289 }, nil
290 }
291