blob: 03abf8f5499fdb2f661b76aa9538127e3850ac30 [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
224 for len(b) > 0 {
225 num, typ, n := wire.ConsumeTag(b)
226 b = b[n:]
227 switch typ {
228 case wire.BytesType:
229 v, m := wire.ConsumeBytes(b)
230 b = b[m:]
231 switch num {
232 case fieldnum.EnumDescriptorProto_Name:
233 ed.L0.FullName = nb.AppendFullName(pd.FullName(), v)
234 }
235 default:
236 m := wire.ConsumeFieldValue(num, typ, b)
237 b = b[m:]
238 }
239 }
240}
241
242func (md *Message) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
243 md.L0.ParentFile = pf
244 md.L0.Parent = pd
245 md.L0.Index = i
246
247 var prevField pref.FieldNumber
248 var numEnums, numMessages, numExtensions int
249 var posEnums, posMessages, posExtensions int
250 b0 := b
251 for len(b) > 0 {
252 num, typ, n := wire.ConsumeTag(b)
253 b = b[n:]
254 switch typ {
255 case wire.BytesType:
256 v, m := wire.ConsumeBytes(b)
257 b = b[m:]
258 switch num {
259 case fieldnum.DescriptorProto_Name:
260 md.L0.FullName = nb.AppendFullName(pd.FullName(), v)
261 case fieldnum.DescriptorProto_EnumType:
262 if prevField != fieldnum.DescriptorProto_EnumType {
263 if numEnums > 0 {
264 panic("non-contiguous repeated field")
265 }
266 posEnums = len(b0) - len(b) - n - m
267 }
268 numEnums++
269 case fieldnum.DescriptorProto_NestedType:
270 if prevField != fieldnum.DescriptorProto_NestedType {
271 if numMessages > 0 {
272 panic("non-contiguous repeated field")
273 }
274 posMessages = len(b0) - len(b) - n - m
275 }
276 numMessages++
277 case fieldnum.DescriptorProto_Extension:
278 if prevField != fieldnum.DescriptorProto_Extension {
279 if numExtensions > 0 {
280 panic("non-contiguous repeated field")
281 }
282 posExtensions = len(b0) - len(b) - n - m
283 }
284 numExtensions++
285 }
286 prevField = num
287 default:
288 m := wire.ConsumeFieldValue(num, typ, b)
289 b = b[m:]
290 prevField = -1 // ignore known field numbers of unknown wire type
291 }
292 }
293
294 // Must allocate all declarations before parsing each descriptor type
295 // to ensure we handled all descriptors in "flattened ordering".
296 if numEnums > 0 {
297 md.L1.Enums.List = pf.allocEnums(numEnums)
298 }
299 if numMessages > 0 {
300 md.L1.Messages.List = pf.allocMessages(numMessages)
301 }
302 if numExtensions > 0 {
303 md.L1.Extensions.List = pf.allocExtensions(numExtensions)
304 }
305
306 if numEnums > 0 {
307 b := b0[posEnums:]
308 for i := range md.L1.Enums.List {
309 _, n := wire.ConsumeVarint(b)
310 v, m := wire.ConsumeBytes(b[n:])
311 md.L1.Enums.List[i].unmarshalSeed(v, nb, pf, md, i)
312 b = b[n+m:]
313 }
314 }
315 if numMessages > 0 {
316 b := b0[posMessages:]
317 for i := range md.L1.Messages.List {
318 _, n := wire.ConsumeVarint(b)
319 v, m := wire.ConsumeBytes(b[n:])
320 md.L1.Messages.List[i].unmarshalSeed(v, nb, pf, md, i)
321 b = b[n+m:]
322 }
323 }
324 if numExtensions > 0 {
325 b := b0[posExtensions:]
326 for i := range md.L1.Extensions.List {
327 _, n := wire.ConsumeVarint(b)
328 v, m := wire.ConsumeBytes(b[n:])
329 md.L1.Extensions.List[i].unmarshalSeed(v, nb, pf, md, i)
330 b = b[n+m:]
331 }
332 }
333}
334
335func (xd *Extension) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
336 xd.L0.ParentFile = pf
337 xd.L0.Parent = pd
338 xd.L0.Index = i
339
340 for len(b) > 0 {
341 num, typ, n := wire.ConsumeTag(b)
342 b = b[n:]
343 switch typ {
344 case wire.VarintType:
345 v, m := wire.ConsumeVarint(b)
346 b = b[m:]
347 switch num {
348 case fieldnum.FieldDescriptorProto_Number:
349 xd.L1.Number = pref.FieldNumber(v)
350 case fieldnum.FieldDescriptorProto_Type:
351 xd.L1.Kind = pref.Kind(v)
352 }
353 case wire.BytesType:
354 v, m := wire.ConsumeBytes(b)
355 b = b[m:]
356 switch num {
357 case fieldnum.FieldDescriptorProto_Name:
358 xd.L0.FullName = nb.AppendFullName(pd.FullName(), v)
359 case fieldnum.FieldDescriptorProto_Extendee:
360 xd.L1.Extendee = PlaceholderMessage(nb.MakeFullName(v))
361 }
362 default:
363 m := wire.ConsumeFieldValue(num, typ, b)
364 b = b[m:]
365 }
366 }
367}
368
369func (sd *Service) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
370 sd.L0.ParentFile = pf
371 sd.L0.Parent = pd
372 sd.L0.Index = i
373
374 for len(b) > 0 {
375 num, typ, n := wire.ConsumeTag(b)
376 b = b[n:]
377 switch typ {
378 case wire.BytesType:
379 v, m := wire.ConsumeBytes(b)
380 b = b[m:]
381 switch num {
382 case fieldnum.ServiceDescriptorProto_Name:
383 sd.L0.FullName = nb.AppendFullName(pd.FullName(), v)
384 }
385 default:
386 m := wire.ConsumeFieldValue(num, typ, b)
387 b = b[m:]
388 }
389 }
390}