blob: 4955f4d9f4b38c0bfe00ef29278176e8c4fddf92 [file] [log] [blame]
Damien Neil8012b442019-01-18 09:32:24 -08001// Copyright 2018 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 fileinit
6
7import (
8 wire "github.com/golang/protobuf/v2/internal/encoding/wire"
9 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
10)
11
12func newFileDesc(fb FileBuilder) *fileDesc {
13 file := &fileDesc{fileInit: fileInit{
14 RawDescriptor: fb.RawDescriptor,
15 GoTypes: fb.GoTypes,
16 DependencyIndexes: fb.DependencyIndexes,
17 }}
18 file.initDecls(len(fb.EnumOutputTypes), len(fb.MessageOutputTypes), len(fb.ExtensionOutputTypes))
19 file.unmarshalSeed(fb.RawDescriptor)
20
21 // Extended message dependencies are eagerly handled since registration
22 // needs this information at program init time.
23 for i := range file.allExtensions {
24 xd := &file.allExtensions[i]
25 xd.extendedType = file.popMessageDependency()
26 }
27
28 file.checkDecls()
29 return file
30}
31
32// initDecls pre-allocates slices for the exact number of enums, messages
33// (excluding map entries), and extensions declared in the proto file.
34// This is done to avoid regrowing the slice, which would change the address
35// for any previously seen declaration.
36//
37// The alloc methods "allocates" slices by pulling from the capacity.
38func (fd *fileDecls) initDecls(numEnums, numMessages, numExtensions int) {
39 *fd = fileDecls{
40 allEnums: make([]enumDesc, 0, numEnums),
41 allMessages: make([]messageDesc, 0, numMessages),
42 allExtensions: make([]extensionDesc, 0, numExtensions),
43 }
44}
45
46func (fd *fileDecls) allocEnums(n int) []enumDesc {
47 total := len(fd.allEnums)
48 es := fd.allEnums[total : total+n]
49 fd.allEnums = fd.allEnums[:total+n]
50 return es
51}
52func (fd *fileDecls) allocMessages(n int) []messageDesc {
53 total := len(fd.allMessages)
54 ms := fd.allMessages[total : total+n]
55 fd.allMessages = fd.allMessages[:total+n]
56 return ms
57}
58func (fd *fileDecls) allocExtensions(n int) []extensionDesc {
59 total := len(fd.allExtensions)
60 xs := fd.allExtensions[total : total+n]
61 fd.allExtensions = fd.allExtensions[:total+n]
62 return xs
63}
64
65// checkDecls performs a sanity check that the expected number of expected
66// declarations matches the number that were found in the descriptor proto.
67func (fd *fileDecls) checkDecls() {
68 if len(fd.allEnums) != cap(fd.allEnums) ||
69 len(fd.allMessages) != cap(fd.allMessages) ||
70 len(fd.allExtensions) != cap(fd.allExtensions) {
71 panic("mismatching cardinality")
72 }
73}
74
75func (fd *fileDesc) unmarshalSeed(b []byte) {
76 nb := getNameBuilder()
77 defer putNameBuilder(nb)
78
79 var prevField pref.FieldNumber
80 var numEnums, numMessages, numExtensions, numServices int
81 var posEnums, posMessages, posExtensions, posServices int
82 b0 := b
83 for len(b) > 0 {
84 num, typ, n := wire.ConsumeTag(b)
85 b = b[n:]
86 switch typ {
87 case wire.BytesType:
88 v, m := wire.ConsumeBytes(b)
89 b = b[m:]
90 switch num {
91 case fileDesc_Name:
92 fd.path = nb.MakeString(v)
93 case fileDesc_Package:
94 fd.protoPackage = pref.FullName(nb.MakeString(v))
95 case fileDesc_Enums:
96 if prevField != fileDesc_Enums {
97 if numEnums > 0 {
98 panic("non-contiguous repeated field")
99 }
100 posEnums = len(b0) - len(b) - n - m
101 }
102 numEnums++
103 case fileDesc_Messages:
104 if prevField != fileDesc_Messages {
105 if numMessages > 0 {
106 panic("non-contiguous repeated field")
107 }
108 posMessages = len(b0) - len(b) - n - m
109 }
110 numMessages++
111 case fileDesc_Extensions:
112 if prevField != fileDesc_Extensions {
113 if numExtensions > 0 {
114 panic("non-contiguous repeated field")
115 }
116 posExtensions = len(b0) - len(b) - n - m
117 }
118 numExtensions++
119 case fileDesc_Services:
120 if prevField != fileDesc_Services {
121 if numServices > 0 {
122 panic("non-contiguous repeated field")
123 }
124 posServices = len(b0) - len(b) - n - m
125 }
126 numServices++
127 }
128 prevField = num
129 default:
130 m := wire.ConsumeFieldValue(num, typ, b)
131 b = b[m:]
132 prevField = -1 // ignore known field numbers of unknown wire type
133 }
134 }
135
136 // Must allocate all declarations before parsing each descriptor type
137 // to ensure we handled all descriptors in "flattened ordering".
138 if numEnums > 0 {
139 fd.enums.list = fd.allocEnums(numEnums)
140 }
141 if numMessages > 0 {
142 fd.messages.list = fd.allocMessages(numMessages)
143 }
144 if numExtensions > 0 {
145 fd.extensions.list = fd.allocExtensions(numExtensions)
146 }
147 if numServices > 0 {
148 fd.services.list = make([]serviceDesc, numServices)
149 }
150
151 if numEnums > 0 {
152 b := b0[posEnums:]
153 for i := range fd.enums.list {
154 _, n := wire.ConsumeVarint(b)
155 v, m := wire.ConsumeBytes(b[n:])
156 fd.enums.list[i].unmarshalSeed(v, nb, fd, fd, i)
157 b = b[n+m:]
158 }
159 }
160 if numMessages > 0 {
161 b := b0[posMessages:]
162 for i := range fd.messages.list {
163 _, n := wire.ConsumeVarint(b)
164 v, m := wire.ConsumeBytes(b[n:])
165 fd.messages.list[i].unmarshalSeed(v, nb, fd, fd, i)
166 b = b[n+m:]
167 }
168 }
169 if numExtensions > 0 {
170 b := b0[posExtensions:]
171 for i := range fd.extensions.list {
172 _, n := wire.ConsumeVarint(b)
173 v, m := wire.ConsumeBytes(b[n:])
174 fd.extensions.list[i].unmarshalSeed(v, nb, fd, fd, i)
175 b = b[n+m:]
176 }
177 }
178 if numServices > 0 {
179 b := b0[posServices:]
180 for i := range fd.services.list {
181 _, n := wire.ConsumeVarint(b)
182 v, m := wire.ConsumeBytes(b[n:])
183 fd.services.list[i].unmarshalSeed(v, nb, fd, fd, i)
184 b = b[n+m:]
185 }
186 }
187}
188
189func (ed *enumDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
190 ed.parentFile = pf
191 ed.parent = pd
192 ed.index = i
193
194 for len(b) > 0 {
195 num, typ, n := wire.ConsumeTag(b)
196 b = b[n:]
197 switch typ {
198 case wire.BytesType:
199 v, m := wire.ConsumeBytes(b)
200 b = b[m:]
201 switch num {
202 case enumDesc_Name:
203 ed.fullName = nb.AppendFullName(pd.FullName(), v)
204 }
205 default:
206 m := wire.ConsumeFieldValue(num, typ, b)
207 b = b[m:]
208 }
209 }
210}
211
212func (md *messageDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
213 md.parentFile = pf
214 md.parent = pd
215 md.index = i
216
217 var prevField pref.FieldNumber
218 var numEnums, numMessages, numExtensions int
219 var posEnums, posMessages, posExtensions int
220 b0 := b
221 for len(b) > 0 {
222 num, typ, n := wire.ConsumeTag(b)
223 b = b[n:]
224 switch typ {
225 case wire.BytesType:
226 v, m := wire.ConsumeBytes(b)
227 b = b[m:]
228 switch num {
229 case messageDesc_Name:
230 md.fullName = nb.AppendFullName(pd.FullName(), v)
231 case messageDesc_Enums:
232 if prevField != messageDesc_Enums {
233 if numEnums > 0 {
234 panic("non-contiguous repeated field")
235 }
236 posEnums = len(b0) - len(b) - n - m
237 }
238 numEnums++
239 case messageDesc_Messages:
240 if prevField != messageDesc_Messages {
241 if numMessages > 0 {
242 panic("non-contiguous repeated field")
243 }
244 posMessages = len(b0) - len(b) - n - m
245 }
246 numMessages++
247 case messageDesc_Extensions:
248 if prevField != messageDesc_Extensions {
249 if numExtensions > 0 {
250 panic("non-contiguous repeated field")
251 }
252 posExtensions = len(b0) - len(b) - n - m
253 }
254 numExtensions++
255 }
256 prevField = num
257 default:
258 m := wire.ConsumeFieldValue(num, typ, b)
259 b = b[m:]
260 prevField = -1 // ignore known field numbers of unknown wire type
261 }
262 }
263
264 // Must allocate all declarations before parsing each descriptor type
265 // to ensure we handled all descriptors in "flattened ordering".
266 if numEnums > 0 {
267 md.enums.list = md.parentFile.allocEnums(numEnums)
268 }
269 if numMessages > 0 {
270 md.messages.list = md.parentFile.allocMessages(numMessages)
271 }
272 if numExtensions > 0 {
273 md.extensions.list = md.parentFile.allocExtensions(numExtensions)
274 }
275
276 if numEnums > 0 {
277 b := b0[posEnums:]
278 for i := range md.enums.list {
279 _, n := wire.ConsumeVarint(b)
280 v, m := wire.ConsumeBytes(b[n:])
281 md.enums.list[i].unmarshalSeed(v, nb, pf, md, i)
282 b = b[n+m:]
283 }
284 }
285 if numMessages > 0 {
286 b := b0[posMessages:]
287 for i := range md.messages.list {
288 _, n := wire.ConsumeVarint(b)
289 v, m := wire.ConsumeBytes(b[n:])
290 md.messages.list[i].unmarshalSeed(v, nb, pf, md, i)
291 b = b[n+m:]
292 }
293 }
294 if numExtensions > 0 {
295 b := b0[posExtensions:]
296 for i := range md.extensions.list {
297 _, n := wire.ConsumeVarint(b)
298 v, m := wire.ConsumeBytes(b[n:])
299 md.extensions.list[i].unmarshalSeed(v, nb, pf, md, i)
300 b = b[n+m:]
301 }
302 }
303}
304
305func (xd *extensionDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
306 xd.parentFile = pf
307 xd.parent = pd
308 xd.index = i
309
310 for len(b) > 0 {
311 num, typ, n := wire.ConsumeTag(b)
312 b = b[n:]
313 switch typ {
314 case wire.VarintType:
315 v, m := wire.ConsumeVarint(b)
316 b = b[m:]
317 switch num {
318 case fieldDesc_Number:
319 xd.number = pref.FieldNumber(v)
320 }
321 case wire.BytesType:
322 v, m := wire.ConsumeBytes(b)
323 b = b[m:]
324 switch num {
325 case fieldDesc_Name:
326 xd.fullName = nb.AppendFullName(pd.FullName(), v)
327 }
328 default:
329 m := wire.ConsumeFieldValue(num, typ, b)
330 b = b[m:]
331 }
332 }
333}
334
335func (sd *serviceDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
336 sd.parentFile = pf
337 sd.parent = pd
338 sd.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.BytesType:
345 v, m := wire.ConsumeBytes(b)
346 b = b[m:]
347 switch num {
348 case serviceDesc_Name:
349 sd.fullName = nb.AppendFullName(pd.FullName(), v)
350 }
351 default:
352 m := wire.ConsumeFieldValue(num, typ, b)
353 b = b[m:]
354 }
355 }
356}