blob: 29d05311d616708904c3f4644347e4f2d72eb3b3 [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"
Joe Tsaica46d8c2019-03-20 16:51:09 -07009 fieldnum "github.com/golang/protobuf/v2/internal/fieldnum"
Damien Neil8012b442019-01-18 09:32:24 -080010 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
11)
12
13func newFileDesc(fb FileBuilder) *fileDesc {
14 file := &fileDesc{fileInit: fileInit{
Damien Neil8012b442019-01-18 09:32:24 -080015 GoTypes: fb.GoTypes,
16 DependencyIndexes: fb.DependencyIndexes,
Joe Tsaie089c0f2019-04-16 01:46:14 -070017 }, rawDesc: fb.RawDescriptor}
Damien Neil8012b442019-01-18 09:32:24 -080018 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
Joe Tsai4532dd72019-03-19 17:04:06 -070033// (including map entries), and extensions declared in the proto file.
Damien Neil8012b442019-01-18 09:32:24 -080034// 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 {
Joe Tsaica46d8c2019-03-20 16:51:09 -070091 case fieldnum.FileDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -080092 fd.path = nb.MakeString(v)
Joe Tsaica46d8c2019-03-20 16:51:09 -070093 case fieldnum.FileDescriptorProto_Package:
Damien Neil8012b442019-01-18 09:32:24 -080094 fd.protoPackage = pref.FullName(nb.MakeString(v))
Joe Tsaica46d8c2019-03-20 16:51:09 -070095 case fieldnum.FileDescriptorProto_EnumType:
96 if prevField != fieldnum.FileDescriptorProto_EnumType {
Damien Neil8012b442019-01-18 09:32:24 -080097 if numEnums > 0 {
98 panic("non-contiguous repeated field")
99 }
100 posEnums = len(b0) - len(b) - n - m
101 }
102 numEnums++
Joe Tsaica46d8c2019-03-20 16:51:09 -0700103 case fieldnum.FileDescriptorProto_MessageType:
104 if prevField != fieldnum.FileDescriptorProto_MessageType {
Damien Neil8012b442019-01-18 09:32:24 -0800105 if numMessages > 0 {
106 panic("non-contiguous repeated field")
107 }
108 posMessages = len(b0) - len(b) - n - m
109 }
110 numMessages++
Joe Tsaica46d8c2019-03-20 16:51:09 -0700111 case fieldnum.FileDescriptorProto_Extension:
112 if prevField != fieldnum.FileDescriptorProto_Extension {
Damien Neil8012b442019-01-18 09:32:24 -0800113 if numExtensions > 0 {
114 panic("non-contiguous repeated field")
115 }
116 posExtensions = len(b0) - len(b) - n - m
117 }
118 numExtensions++
Joe Tsaica46d8c2019-03-20 16:51:09 -0700119 case fieldnum.FileDescriptorProto_Service:
120 if prevField != fieldnum.FileDescriptorProto_Service {
Damien Neil8012b442019-01-18 09:32:24 -0800121 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 {
Joe Tsaica46d8c2019-03-20 16:51:09 -0700202 case fieldnum.EnumDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800203 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 {
Joe Tsaica46d8c2019-03-20 16:51:09 -0700229 case fieldnum.DescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800230 md.fullName = nb.AppendFullName(pd.FullName(), v)
Joe Tsaica46d8c2019-03-20 16:51:09 -0700231 case fieldnum.DescriptorProto_EnumType:
232 if prevField != fieldnum.DescriptorProto_EnumType {
Damien Neil8012b442019-01-18 09:32:24 -0800233 if numEnums > 0 {
234 panic("non-contiguous repeated field")
235 }
236 posEnums = len(b0) - len(b) - n - m
237 }
238 numEnums++
Joe Tsaica46d8c2019-03-20 16:51:09 -0700239 case fieldnum.DescriptorProto_NestedType:
240 if prevField != fieldnum.DescriptorProto_NestedType {
Damien Neil8012b442019-01-18 09:32:24 -0800241 if numMessages > 0 {
242 panic("non-contiguous repeated field")
243 }
244 posMessages = len(b0) - len(b) - n - m
245 }
246 numMessages++
Joe Tsaica46d8c2019-03-20 16:51:09 -0700247 case fieldnum.DescriptorProto_Extension:
248 if prevField != fieldnum.DescriptorProto_Extension {
Damien Neil8012b442019-01-18 09:32:24 -0800249 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:])
Joe Tsai4532dd72019-03-19 17:04:06 -0700281 md.enums.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i)
Damien Neil8012b442019-01-18 09:32:24 -0800282 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:])
Joe Tsai4532dd72019-03-19 17:04:06 -0700290 md.messages.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i)
Damien Neil8012b442019-01-18 09:32:24 -0800291 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:])
Joe Tsai4532dd72019-03-19 17:04:06 -0700299 md.extensions.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i)
Damien Neil8012b442019-01-18 09:32:24 -0800300 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 {
Joe Tsaica46d8c2019-03-20 16:51:09 -0700318 case fieldnum.FieldDescriptorProto_Number:
Damien Neil8012b442019-01-18 09:32:24 -0800319 xd.number = pref.FieldNumber(v)
320 }
321 case wire.BytesType:
322 v, m := wire.ConsumeBytes(b)
323 b = b[m:]
324 switch num {
Joe Tsaica46d8c2019-03-20 16:51:09 -0700325 case fieldnum.FieldDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800326 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 {
Joe Tsaica46d8c2019-03-20 16:51:09 -0700348 case fieldnum.ServiceDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800349 sd.fullName = nb.AppendFullName(pd.FullName(), v)
350 }
351 default:
352 m := wire.ConsumeFieldValue(num, typ, b)
353 b = b[m:]
354 }
355 }
356}