blob: 66e1fee5224327e2da0538e11445584cf9742281 [file] [log] [blame]
khenaidoo106c61a2021-08-11 18:05:46 -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 "sync"
9
10 "google.golang.org/protobuf/encoding/protowire"
11 "google.golang.org/protobuf/internal/genid"
12 "google.golang.org/protobuf/internal/strs"
13 pref "google.golang.org/protobuf/reflect/protoreflect"
14)
15
16// fileRaw is a data struct used when initializing a file descriptor from
17// a raw FileDescriptorProto.
18type fileRaw struct {
19 builder Builder
20 allEnums []Enum
21 allMessages []Message
22 allExtensions []Extension
23 allServices []Service
24}
25
26func newRawFile(db Builder) *File {
27 fd := &File{fileRaw: fileRaw{builder: db}}
28 fd.initDecls(db.NumEnums, db.NumMessages, db.NumExtensions, db.NumServices)
29 fd.unmarshalSeed(db.RawDescriptor)
30
31 // Extended message targets are eagerly resolved since registration
32 // needs this information at program init time.
33 for i := range fd.allExtensions {
34 xd := &fd.allExtensions[i]
35 xd.L1.Extendee = fd.resolveMessageDependency(xd.L1.Extendee, listExtTargets, int32(i))
36 }
37
38 fd.checkDecls()
39 return fd
40}
41
42// initDecls pre-allocates slices for the exact number of enums, messages
43// (including map entries), extensions, and services declared in the proto file.
44// This is done to avoid regrowing the slice, which would change the address
45// for any previously seen declaration.
46//
47// The alloc methods "allocates" slices by pulling from the capacity.
48func (fd *File) initDecls(numEnums, numMessages, numExtensions, numServices int32) {
49 fd.allEnums = make([]Enum, 0, numEnums)
50 fd.allMessages = make([]Message, 0, numMessages)
51 fd.allExtensions = make([]Extension, 0, numExtensions)
52 fd.allServices = make([]Service, 0, numServices)
53}
54
55func (fd *File) allocEnums(n int) []Enum {
56 total := len(fd.allEnums)
57 es := fd.allEnums[total : total+n]
58 fd.allEnums = fd.allEnums[:total+n]
59 return es
60}
61func (fd *File) allocMessages(n int) []Message {
62 total := len(fd.allMessages)
63 ms := fd.allMessages[total : total+n]
64 fd.allMessages = fd.allMessages[:total+n]
65 return ms
66}
67func (fd *File) allocExtensions(n int) []Extension {
68 total := len(fd.allExtensions)
69 xs := fd.allExtensions[total : total+n]
70 fd.allExtensions = fd.allExtensions[:total+n]
71 return xs
72}
73func (fd *File) allocServices(n int) []Service {
74 total := len(fd.allServices)
75 xs := fd.allServices[total : total+n]
76 fd.allServices = fd.allServices[:total+n]
77 return xs
78}
79
80// checkDecls performs a sanity check that the expected number of expected
81// declarations matches the number that were found in the descriptor proto.
82func (fd *File) checkDecls() {
83 switch {
84 case len(fd.allEnums) != cap(fd.allEnums):
85 case len(fd.allMessages) != cap(fd.allMessages):
86 case len(fd.allExtensions) != cap(fd.allExtensions):
87 case len(fd.allServices) != cap(fd.allServices):
88 default:
89 return
90 }
91 panic("mismatching cardinality")
92}
93
94func (fd *File) unmarshalSeed(b []byte) {
95 sb := getBuilder()
96 defer putBuilder(sb)
97
98 var prevField pref.FieldNumber
99 var numEnums, numMessages, numExtensions, numServices int
100 var posEnums, posMessages, posExtensions, posServices int
101 b0 := b
102 for len(b) > 0 {
103 num, typ, n := protowire.ConsumeTag(b)
104 b = b[n:]
105 switch typ {
106 case protowire.BytesType:
107 v, m := protowire.ConsumeBytes(b)
108 b = b[m:]
109 switch num {
110 case genid.FileDescriptorProto_Syntax_field_number:
111 switch string(v) {
112 case "proto2":
113 fd.L1.Syntax = pref.Proto2
114 case "proto3":
115 fd.L1.Syntax = pref.Proto3
116 default:
117 panic("invalid syntax")
118 }
119 case genid.FileDescriptorProto_Name_field_number:
120 fd.L1.Path = sb.MakeString(v)
121 case genid.FileDescriptorProto_Package_field_number:
122 fd.L1.Package = pref.FullName(sb.MakeString(v))
123 case genid.FileDescriptorProto_EnumType_field_number:
124 if prevField != genid.FileDescriptorProto_EnumType_field_number {
125 if numEnums > 0 {
126 panic("non-contiguous repeated field")
127 }
128 posEnums = len(b0) - len(b) - n - m
129 }
130 numEnums++
131 case genid.FileDescriptorProto_MessageType_field_number:
132 if prevField != genid.FileDescriptorProto_MessageType_field_number {
133 if numMessages > 0 {
134 panic("non-contiguous repeated field")
135 }
136 posMessages = len(b0) - len(b) - n - m
137 }
138 numMessages++
139 case genid.FileDescriptorProto_Extension_field_number:
140 if prevField != genid.FileDescriptorProto_Extension_field_number {
141 if numExtensions > 0 {
142 panic("non-contiguous repeated field")
143 }
144 posExtensions = len(b0) - len(b) - n - m
145 }
146 numExtensions++
147 case genid.FileDescriptorProto_Service_field_number:
148 if prevField != genid.FileDescriptorProto_Service_field_number {
149 if numServices > 0 {
150 panic("non-contiguous repeated field")
151 }
152 posServices = len(b0) - len(b) - n - m
153 }
154 numServices++
155 }
156 prevField = num
157 default:
158 m := protowire.ConsumeFieldValue(num, typ, b)
159 b = b[m:]
160 prevField = -1 // ignore known field numbers of unknown wire type
161 }
162 }
163
164 // If syntax is missing, it is assumed to be proto2.
165 if fd.L1.Syntax == 0 {
166 fd.L1.Syntax = pref.Proto2
167 }
168
169 // Must allocate all declarations before parsing each descriptor type
170 // to ensure we handled all descriptors in "flattened ordering".
171 if numEnums > 0 {
172 fd.L1.Enums.List = fd.allocEnums(numEnums)
173 }
174 if numMessages > 0 {
175 fd.L1.Messages.List = fd.allocMessages(numMessages)
176 }
177 if numExtensions > 0 {
178 fd.L1.Extensions.List = fd.allocExtensions(numExtensions)
179 }
180 if numServices > 0 {
181 fd.L1.Services.List = fd.allocServices(numServices)
182 }
183
184 if numEnums > 0 {
185 b := b0[posEnums:]
186 for i := range fd.L1.Enums.List {
187 _, n := protowire.ConsumeVarint(b)
188 v, m := protowire.ConsumeBytes(b[n:])
189 fd.L1.Enums.List[i].unmarshalSeed(v, sb, fd, fd, i)
190 b = b[n+m:]
191 }
192 }
193 if numMessages > 0 {
194 b := b0[posMessages:]
195 for i := range fd.L1.Messages.List {
196 _, n := protowire.ConsumeVarint(b)
197 v, m := protowire.ConsumeBytes(b[n:])
198 fd.L1.Messages.List[i].unmarshalSeed(v, sb, fd, fd, i)
199 b = b[n+m:]
200 }
201 }
202 if numExtensions > 0 {
203 b := b0[posExtensions:]
204 for i := range fd.L1.Extensions.List {
205 _, n := protowire.ConsumeVarint(b)
206 v, m := protowire.ConsumeBytes(b[n:])
207 fd.L1.Extensions.List[i].unmarshalSeed(v, sb, fd, fd, i)
208 b = b[n+m:]
209 }
210 }
211 if numServices > 0 {
212 b := b0[posServices:]
213 for i := range fd.L1.Services.List {
214 _, n := protowire.ConsumeVarint(b)
215 v, m := protowire.ConsumeBytes(b[n:])
216 fd.L1.Services.List[i].unmarshalSeed(v, sb, fd, fd, i)
217 b = b[n+m:]
218 }
219 }
220}
221
222func (ed *Enum) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
223 ed.L0.ParentFile = pf
224 ed.L0.Parent = pd
225 ed.L0.Index = i
226
227 var numValues int
228 for b := b; len(b) > 0; {
229 num, typ, n := protowire.ConsumeTag(b)
230 b = b[n:]
231 switch typ {
232 case protowire.BytesType:
233 v, m := protowire.ConsumeBytes(b)
234 b = b[m:]
235 switch num {
236 case genid.EnumDescriptorProto_Name_field_number:
237 ed.L0.FullName = appendFullName(sb, pd.FullName(), v)
238 case genid.EnumDescriptorProto_Value_field_number:
239 numValues++
240 }
241 default:
242 m := protowire.ConsumeFieldValue(num, typ, b)
243 b = b[m:]
244 }
245 }
246
247 // Only construct enum value descriptors for top-level enums since
248 // they are needed for registration.
249 if pd != pf {
250 return
251 }
252 ed.L1.eagerValues = true
253 ed.L2 = new(EnumL2)
254 ed.L2.Values.List = make([]EnumValue, numValues)
255 for i := 0; len(b) > 0; {
256 num, typ, n := protowire.ConsumeTag(b)
257 b = b[n:]
258 switch typ {
259 case protowire.BytesType:
260 v, m := protowire.ConsumeBytes(b)
261 b = b[m:]
262 switch num {
263 case genid.EnumDescriptorProto_Value_field_number:
264 ed.L2.Values.List[i].unmarshalFull(v, sb, pf, ed, i)
265 i++
266 }
267 default:
268 m := protowire.ConsumeFieldValue(num, typ, b)
269 b = b[m:]
270 }
271 }
272}
273
274func (md *Message) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
275 md.L0.ParentFile = pf
276 md.L0.Parent = pd
277 md.L0.Index = i
278
279 var prevField pref.FieldNumber
280 var numEnums, numMessages, numExtensions int
281 var posEnums, posMessages, posExtensions int
282 b0 := b
283 for len(b) > 0 {
284 num, typ, n := protowire.ConsumeTag(b)
285 b = b[n:]
286 switch typ {
287 case protowire.BytesType:
288 v, m := protowire.ConsumeBytes(b)
289 b = b[m:]
290 switch num {
291 case genid.DescriptorProto_Name_field_number:
292 md.L0.FullName = appendFullName(sb, pd.FullName(), v)
293 case genid.DescriptorProto_EnumType_field_number:
294 if prevField != genid.DescriptorProto_EnumType_field_number {
295 if numEnums > 0 {
296 panic("non-contiguous repeated field")
297 }
298 posEnums = len(b0) - len(b) - n - m
299 }
300 numEnums++
301 case genid.DescriptorProto_NestedType_field_number:
302 if prevField != genid.DescriptorProto_NestedType_field_number {
303 if numMessages > 0 {
304 panic("non-contiguous repeated field")
305 }
306 posMessages = len(b0) - len(b) - n - m
307 }
308 numMessages++
309 case genid.DescriptorProto_Extension_field_number:
310 if prevField != genid.DescriptorProto_Extension_field_number {
311 if numExtensions > 0 {
312 panic("non-contiguous repeated field")
313 }
314 posExtensions = len(b0) - len(b) - n - m
315 }
316 numExtensions++
317 case genid.DescriptorProto_Options_field_number:
318 md.unmarshalSeedOptions(v)
319 }
320 prevField = num
321 default:
322 m := protowire.ConsumeFieldValue(num, typ, b)
323 b = b[m:]
324 prevField = -1 // ignore known field numbers of unknown wire type
325 }
326 }
327
328 // Must allocate all declarations before parsing each descriptor type
329 // to ensure we handled all descriptors in "flattened ordering".
330 if numEnums > 0 {
331 md.L1.Enums.List = pf.allocEnums(numEnums)
332 }
333 if numMessages > 0 {
334 md.L1.Messages.List = pf.allocMessages(numMessages)
335 }
336 if numExtensions > 0 {
337 md.L1.Extensions.List = pf.allocExtensions(numExtensions)
338 }
339
340 if numEnums > 0 {
341 b := b0[posEnums:]
342 for i := range md.L1.Enums.List {
343 _, n := protowire.ConsumeVarint(b)
344 v, m := protowire.ConsumeBytes(b[n:])
345 md.L1.Enums.List[i].unmarshalSeed(v, sb, pf, md, i)
346 b = b[n+m:]
347 }
348 }
349 if numMessages > 0 {
350 b := b0[posMessages:]
351 for i := range md.L1.Messages.List {
352 _, n := protowire.ConsumeVarint(b)
353 v, m := protowire.ConsumeBytes(b[n:])
354 md.L1.Messages.List[i].unmarshalSeed(v, sb, pf, md, i)
355 b = b[n+m:]
356 }
357 }
358 if numExtensions > 0 {
359 b := b0[posExtensions:]
360 for i := range md.L1.Extensions.List {
361 _, n := protowire.ConsumeVarint(b)
362 v, m := protowire.ConsumeBytes(b[n:])
363 md.L1.Extensions.List[i].unmarshalSeed(v, sb, pf, md, i)
364 b = b[n+m:]
365 }
366 }
367}
368
369func (md *Message) unmarshalSeedOptions(b []byte) {
370 for len(b) > 0 {
371 num, typ, n := protowire.ConsumeTag(b)
372 b = b[n:]
373 switch typ {
374 case protowire.VarintType:
375 v, m := protowire.ConsumeVarint(b)
376 b = b[m:]
377 switch num {
378 case genid.MessageOptions_MapEntry_field_number:
379 md.L1.IsMapEntry = protowire.DecodeBool(v)
380 case genid.MessageOptions_MessageSetWireFormat_field_number:
381 md.L1.IsMessageSet = protowire.DecodeBool(v)
382 }
383 default:
384 m := protowire.ConsumeFieldValue(num, typ, b)
385 b = b[m:]
386 }
387 }
388}
389
390func (xd *Extension) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
391 xd.L0.ParentFile = pf
392 xd.L0.Parent = pd
393 xd.L0.Index = i
394
395 for len(b) > 0 {
396 num, typ, n := protowire.ConsumeTag(b)
397 b = b[n:]
398 switch typ {
399 case protowire.VarintType:
400 v, m := protowire.ConsumeVarint(b)
401 b = b[m:]
402 switch num {
403 case genid.FieldDescriptorProto_Number_field_number:
404 xd.L1.Number = pref.FieldNumber(v)
405 case genid.FieldDescriptorProto_Label_field_number:
406 xd.L1.Cardinality = pref.Cardinality(v)
407 case genid.FieldDescriptorProto_Type_field_number:
408 xd.L1.Kind = pref.Kind(v)
409 }
410 case protowire.BytesType:
411 v, m := protowire.ConsumeBytes(b)
412 b = b[m:]
413 switch num {
414 case genid.FieldDescriptorProto_Name_field_number:
415 xd.L0.FullName = appendFullName(sb, pd.FullName(), v)
416 case genid.FieldDescriptorProto_Extendee_field_number:
417 xd.L1.Extendee = PlaceholderMessage(makeFullName(sb, v))
418 }
419 default:
420 m := protowire.ConsumeFieldValue(num, typ, b)
421 b = b[m:]
422 }
423 }
424}
425
426func (sd *Service) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd pref.Descriptor, i int) {
427 sd.L0.ParentFile = pf
428 sd.L0.Parent = pd
429 sd.L0.Index = i
430
431 for len(b) > 0 {
432 num, typ, n := protowire.ConsumeTag(b)
433 b = b[n:]
434 switch typ {
435 case protowire.BytesType:
436 v, m := protowire.ConsumeBytes(b)
437 b = b[m:]
438 switch num {
439 case genid.ServiceDescriptorProto_Name_field_number:
440 sd.L0.FullName = appendFullName(sb, pd.FullName(), v)
441 }
442 default:
443 m := protowire.ConsumeFieldValue(num, typ, b)
444 b = b[m:]
445 }
446 }
447}
448
449var nameBuilderPool = sync.Pool{
450 New: func() interface{} { return new(strs.Builder) },
451}
452
453func getBuilder() *strs.Builder {
454 return nameBuilderPool.Get().(*strs.Builder)
455}
456func putBuilder(b *strs.Builder) {
457 nameBuilderPool.Put(b)
458}
459
460// makeFullName converts b to a protoreflect.FullName,
461// where b must start with a leading dot.
462func makeFullName(sb *strs.Builder, b []byte) pref.FullName {
463 if len(b) == 0 || b[0] != '.' {
464 panic("name reference must be fully qualified")
465 }
466 return pref.FullName(sb.MakeString(b[1:]))
467}
468
469func appendFullName(sb *strs.Builder, prefix pref.FullName, suffix []byte) pref.FullName {
470 return sb.AppendFullName(prefix, pref.Name(strs.UnsafeString(suffix)))
471}