blob: d1310a4013e04eb95dae4ea390129e5f791812d1 [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{
15 RawDescriptor: fb.RawDescriptor,
16 GoTypes: fb.GoTypes,
17 DependencyIndexes: fb.DependencyIndexes,
18 }}
19 file.initDecls(len(fb.EnumOutputTypes), len(fb.MessageOutputTypes), len(fb.ExtensionOutputTypes))
20 file.unmarshalSeed(fb.RawDescriptor)
21
Joe Tsai4532dd72019-03-19 17:04:06 -070022 // Determine which message descriptors represent map entries based on the
23 // lack of an associated Go type.
24 messageDecls := file.GoTypes[len(file.allEnums):]
25 for i := range file.allMessages {
26 file.allMessages[i].isMapEntry = messageDecls[i] == nil
27 }
28
Damien Neil8012b442019-01-18 09:32:24 -080029 // Extended message dependencies are eagerly handled since registration
30 // needs this information at program init time.
31 for i := range file.allExtensions {
32 xd := &file.allExtensions[i]
33 xd.extendedType = file.popMessageDependency()
34 }
35
36 file.checkDecls()
37 return file
38}
39
40// initDecls pre-allocates slices for the exact number of enums, messages
Joe Tsai4532dd72019-03-19 17:04:06 -070041// (including map entries), and extensions declared in the proto file.
Damien Neil8012b442019-01-18 09:32:24 -080042// This is done to avoid regrowing the slice, which would change the address
43// for any previously seen declaration.
44//
45// The alloc methods "allocates" slices by pulling from the capacity.
46func (fd *fileDecls) initDecls(numEnums, numMessages, numExtensions int) {
47 *fd = fileDecls{
48 allEnums: make([]enumDesc, 0, numEnums),
49 allMessages: make([]messageDesc, 0, numMessages),
50 allExtensions: make([]extensionDesc, 0, numExtensions),
51 }
52}
53
54func (fd *fileDecls) allocEnums(n int) []enumDesc {
55 total := len(fd.allEnums)
56 es := fd.allEnums[total : total+n]
57 fd.allEnums = fd.allEnums[:total+n]
58 return es
59}
60func (fd *fileDecls) allocMessages(n int) []messageDesc {
61 total := len(fd.allMessages)
62 ms := fd.allMessages[total : total+n]
63 fd.allMessages = fd.allMessages[:total+n]
64 return ms
65}
66func (fd *fileDecls) allocExtensions(n int) []extensionDesc {
67 total := len(fd.allExtensions)
68 xs := fd.allExtensions[total : total+n]
69 fd.allExtensions = fd.allExtensions[:total+n]
70 return xs
71}
72
73// checkDecls performs a sanity check that the expected number of expected
74// declarations matches the number that were found in the descriptor proto.
75func (fd *fileDecls) checkDecls() {
76 if len(fd.allEnums) != cap(fd.allEnums) ||
77 len(fd.allMessages) != cap(fd.allMessages) ||
78 len(fd.allExtensions) != cap(fd.allExtensions) {
79 panic("mismatching cardinality")
80 }
81}
82
83func (fd *fileDesc) unmarshalSeed(b []byte) {
84 nb := getNameBuilder()
85 defer putNameBuilder(nb)
86
87 var prevField pref.FieldNumber
88 var numEnums, numMessages, numExtensions, numServices int
89 var posEnums, posMessages, posExtensions, posServices int
90 b0 := b
91 for len(b) > 0 {
92 num, typ, n := wire.ConsumeTag(b)
93 b = b[n:]
94 switch typ {
95 case wire.BytesType:
96 v, m := wire.ConsumeBytes(b)
97 b = b[m:]
98 switch num {
Joe Tsaica46d8c2019-03-20 16:51:09 -070099 case fieldnum.FileDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800100 fd.path = nb.MakeString(v)
Joe Tsaica46d8c2019-03-20 16:51:09 -0700101 case fieldnum.FileDescriptorProto_Package:
Damien Neil8012b442019-01-18 09:32:24 -0800102 fd.protoPackage = pref.FullName(nb.MakeString(v))
Joe Tsaica46d8c2019-03-20 16:51:09 -0700103 case fieldnum.FileDescriptorProto_EnumType:
104 if prevField != fieldnum.FileDescriptorProto_EnumType {
Damien Neil8012b442019-01-18 09:32:24 -0800105 if numEnums > 0 {
106 panic("non-contiguous repeated field")
107 }
108 posEnums = len(b0) - len(b) - n - m
109 }
110 numEnums++
Joe Tsaica46d8c2019-03-20 16:51:09 -0700111 case fieldnum.FileDescriptorProto_MessageType:
112 if prevField != fieldnum.FileDescriptorProto_MessageType {
Damien Neil8012b442019-01-18 09:32:24 -0800113 if numMessages > 0 {
114 panic("non-contiguous repeated field")
115 }
116 posMessages = len(b0) - len(b) - n - m
117 }
118 numMessages++
Joe Tsaica46d8c2019-03-20 16:51:09 -0700119 case fieldnum.FileDescriptorProto_Extension:
120 if prevField != fieldnum.FileDescriptorProto_Extension {
Damien Neil8012b442019-01-18 09:32:24 -0800121 if numExtensions > 0 {
122 panic("non-contiguous repeated field")
123 }
124 posExtensions = len(b0) - len(b) - n - m
125 }
126 numExtensions++
Joe Tsaica46d8c2019-03-20 16:51:09 -0700127 case fieldnum.FileDescriptorProto_Service:
128 if prevField != fieldnum.FileDescriptorProto_Service {
Damien Neil8012b442019-01-18 09:32:24 -0800129 if numServices > 0 {
130 panic("non-contiguous repeated field")
131 }
132 posServices = len(b0) - len(b) - n - m
133 }
134 numServices++
135 }
136 prevField = num
137 default:
138 m := wire.ConsumeFieldValue(num, typ, b)
139 b = b[m:]
140 prevField = -1 // ignore known field numbers of unknown wire type
141 }
142 }
143
144 // Must allocate all declarations before parsing each descriptor type
145 // to ensure we handled all descriptors in "flattened ordering".
146 if numEnums > 0 {
147 fd.enums.list = fd.allocEnums(numEnums)
148 }
149 if numMessages > 0 {
150 fd.messages.list = fd.allocMessages(numMessages)
151 }
152 if numExtensions > 0 {
153 fd.extensions.list = fd.allocExtensions(numExtensions)
154 }
155 if numServices > 0 {
156 fd.services.list = make([]serviceDesc, numServices)
157 }
158
159 if numEnums > 0 {
160 b := b0[posEnums:]
161 for i := range fd.enums.list {
162 _, n := wire.ConsumeVarint(b)
163 v, m := wire.ConsumeBytes(b[n:])
164 fd.enums.list[i].unmarshalSeed(v, nb, fd, fd, i)
165 b = b[n+m:]
166 }
167 }
168 if numMessages > 0 {
169 b := b0[posMessages:]
170 for i := range fd.messages.list {
171 _, n := wire.ConsumeVarint(b)
172 v, m := wire.ConsumeBytes(b[n:])
173 fd.messages.list[i].unmarshalSeed(v, nb, fd, fd, i)
174 b = b[n+m:]
175 }
176 }
177 if numExtensions > 0 {
178 b := b0[posExtensions:]
179 for i := range fd.extensions.list {
180 _, n := wire.ConsumeVarint(b)
181 v, m := wire.ConsumeBytes(b[n:])
182 fd.extensions.list[i].unmarshalSeed(v, nb, fd, fd, i)
183 b = b[n+m:]
184 }
185 }
186 if numServices > 0 {
187 b := b0[posServices:]
188 for i := range fd.services.list {
189 _, n := wire.ConsumeVarint(b)
190 v, m := wire.ConsumeBytes(b[n:])
191 fd.services.list[i].unmarshalSeed(v, nb, fd, fd, i)
192 b = b[n+m:]
193 }
194 }
195}
196
197func (ed *enumDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
198 ed.parentFile = pf
199 ed.parent = pd
200 ed.index = i
201
202 for len(b) > 0 {
203 num, typ, n := wire.ConsumeTag(b)
204 b = b[n:]
205 switch typ {
206 case wire.BytesType:
207 v, m := wire.ConsumeBytes(b)
208 b = b[m:]
209 switch num {
Joe Tsaica46d8c2019-03-20 16:51:09 -0700210 case fieldnum.EnumDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800211 ed.fullName = nb.AppendFullName(pd.FullName(), v)
212 }
213 default:
214 m := wire.ConsumeFieldValue(num, typ, b)
215 b = b[m:]
216 }
217 }
218}
219
220func (md *messageDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
221 md.parentFile = pf
222 md.parent = pd
223 md.index = i
224
225 var prevField pref.FieldNumber
226 var numEnums, numMessages, numExtensions int
227 var posEnums, posMessages, posExtensions int
228 b0 := b
229 for len(b) > 0 {
230 num, typ, n := wire.ConsumeTag(b)
231 b = b[n:]
232 switch typ {
233 case wire.BytesType:
234 v, m := wire.ConsumeBytes(b)
235 b = b[m:]
236 switch num {
Joe Tsaica46d8c2019-03-20 16:51:09 -0700237 case fieldnum.DescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800238 md.fullName = nb.AppendFullName(pd.FullName(), v)
Joe Tsaica46d8c2019-03-20 16:51:09 -0700239 case fieldnum.DescriptorProto_EnumType:
240 if prevField != fieldnum.DescriptorProto_EnumType {
Damien Neil8012b442019-01-18 09:32:24 -0800241 if numEnums > 0 {
242 panic("non-contiguous repeated field")
243 }
244 posEnums = len(b0) - len(b) - n - m
245 }
246 numEnums++
Joe Tsaica46d8c2019-03-20 16:51:09 -0700247 case fieldnum.DescriptorProto_NestedType:
248 if prevField != fieldnum.DescriptorProto_NestedType {
Damien Neil8012b442019-01-18 09:32:24 -0800249 if numMessages > 0 {
250 panic("non-contiguous repeated field")
251 }
252 posMessages = len(b0) - len(b) - n - m
253 }
254 numMessages++
Joe Tsaica46d8c2019-03-20 16:51:09 -0700255 case fieldnum.DescriptorProto_Extension:
256 if prevField != fieldnum.DescriptorProto_Extension {
Damien Neil8012b442019-01-18 09:32:24 -0800257 if numExtensions > 0 {
258 panic("non-contiguous repeated field")
259 }
260 posExtensions = len(b0) - len(b) - n - m
261 }
262 numExtensions++
263 }
264 prevField = num
265 default:
266 m := wire.ConsumeFieldValue(num, typ, b)
267 b = b[m:]
268 prevField = -1 // ignore known field numbers of unknown wire type
269 }
270 }
271
272 // Must allocate all declarations before parsing each descriptor type
273 // to ensure we handled all descriptors in "flattened ordering".
274 if numEnums > 0 {
275 md.enums.list = md.parentFile.allocEnums(numEnums)
276 }
277 if numMessages > 0 {
278 md.messages.list = md.parentFile.allocMessages(numMessages)
279 }
280 if numExtensions > 0 {
281 md.extensions.list = md.parentFile.allocExtensions(numExtensions)
282 }
283
284 if numEnums > 0 {
285 b := b0[posEnums:]
286 for i := range md.enums.list {
287 _, n := wire.ConsumeVarint(b)
288 v, m := wire.ConsumeBytes(b[n:])
Joe Tsai4532dd72019-03-19 17:04:06 -0700289 md.enums.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i)
Damien Neil8012b442019-01-18 09:32:24 -0800290 b = b[n+m:]
291 }
292 }
293 if numMessages > 0 {
294 b := b0[posMessages:]
295 for i := range md.messages.list {
296 _, n := wire.ConsumeVarint(b)
297 v, m := wire.ConsumeBytes(b[n:])
Joe Tsai4532dd72019-03-19 17:04:06 -0700298 md.messages.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i)
Damien Neil8012b442019-01-18 09:32:24 -0800299 b = b[n+m:]
300 }
301 }
302 if numExtensions > 0 {
303 b := b0[posExtensions:]
304 for i := range md.extensions.list {
305 _, n := wire.ConsumeVarint(b)
306 v, m := wire.ConsumeBytes(b[n:])
Joe Tsai4532dd72019-03-19 17:04:06 -0700307 md.extensions.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i)
Damien Neil8012b442019-01-18 09:32:24 -0800308 b = b[n+m:]
309 }
310 }
311}
312
313func (xd *extensionDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
314 xd.parentFile = pf
315 xd.parent = pd
316 xd.index = i
317
318 for len(b) > 0 {
319 num, typ, n := wire.ConsumeTag(b)
320 b = b[n:]
321 switch typ {
322 case wire.VarintType:
323 v, m := wire.ConsumeVarint(b)
324 b = b[m:]
325 switch num {
Joe Tsaica46d8c2019-03-20 16:51:09 -0700326 case fieldnum.FieldDescriptorProto_Number:
Damien Neil8012b442019-01-18 09:32:24 -0800327 xd.number = pref.FieldNumber(v)
328 }
329 case wire.BytesType:
330 v, m := wire.ConsumeBytes(b)
331 b = b[m:]
332 switch num {
Joe Tsaica46d8c2019-03-20 16:51:09 -0700333 case fieldnum.FieldDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800334 xd.fullName = nb.AppendFullName(pd.FullName(), v)
335 }
336 default:
337 m := wire.ConsumeFieldValue(num, typ, b)
338 b = b[m:]
339 }
340 }
341}
342
343func (sd *serviceDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
344 sd.parentFile = pf
345 sd.parent = pd
346 sd.index = i
347
348 for len(b) > 0 {
349 num, typ, n := wire.ConsumeTag(b)
350 b = b[n:]
351 switch typ {
352 case wire.BytesType:
353 v, m := wire.ConsumeBytes(b)
354 b = b[m:]
355 switch num {
Joe Tsaica46d8c2019-03-20 16:51:09 -0700356 case fieldnum.ServiceDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800357 sd.fullName = nb.AppendFullName(pd.FullName(), v)
358 }
359 default:
360 m := wire.ConsumeFieldValue(num, typ, b)
361 b = b[m:]
362 }
363 }
364}