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