blob: bd706fc012f804364446b6863e1588795eb211ac [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 (
Joe Tsai1af1de02019-03-01 16:12:32 -08008 descfield "github.com/golang/protobuf/v2/internal/descfield"
Damien Neil8012b442019-01-18 09:32:24 -08009 wire "github.com/golang/protobuf/v2/internal/encoding/wire"
10 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
22 // Extended message dependencies are eagerly handled since registration
23 // needs this information at program init time.
24 for i := range file.allExtensions {
25 xd := &file.allExtensions[i]
26 xd.extendedType = file.popMessageDependency()
27 }
28
29 file.checkDecls()
30 return file
31}
32
33// initDecls pre-allocates slices for the exact number of enums, messages
34// (excluding map entries), and extensions declared in the proto file.
35// This is done to avoid regrowing the slice, which would change the address
36// for any previously seen declaration.
37//
38// The alloc methods "allocates" slices by pulling from the capacity.
39func (fd *fileDecls) initDecls(numEnums, numMessages, numExtensions int) {
40 *fd = fileDecls{
41 allEnums: make([]enumDesc, 0, numEnums),
42 allMessages: make([]messageDesc, 0, numMessages),
43 allExtensions: make([]extensionDesc, 0, numExtensions),
44 }
45}
46
47func (fd *fileDecls) allocEnums(n int) []enumDesc {
48 total := len(fd.allEnums)
49 es := fd.allEnums[total : total+n]
50 fd.allEnums = fd.allEnums[:total+n]
51 return es
52}
53func (fd *fileDecls) allocMessages(n int) []messageDesc {
54 total := len(fd.allMessages)
55 ms := fd.allMessages[total : total+n]
56 fd.allMessages = fd.allMessages[:total+n]
57 return ms
58}
59func (fd *fileDecls) allocExtensions(n int) []extensionDesc {
60 total := len(fd.allExtensions)
61 xs := fd.allExtensions[total : total+n]
62 fd.allExtensions = fd.allExtensions[:total+n]
63 return xs
64}
65
66// checkDecls performs a sanity check that the expected number of expected
67// declarations matches the number that were found in the descriptor proto.
68func (fd *fileDecls) checkDecls() {
69 if len(fd.allEnums) != cap(fd.allEnums) ||
70 len(fd.allMessages) != cap(fd.allMessages) ||
71 len(fd.allExtensions) != cap(fd.allExtensions) {
72 panic("mismatching cardinality")
73 }
74}
75
76func (fd *fileDesc) unmarshalSeed(b []byte) {
77 nb := getNameBuilder()
78 defer putNameBuilder(nb)
79
80 var prevField pref.FieldNumber
81 var numEnums, numMessages, numExtensions, numServices int
82 var posEnums, posMessages, posExtensions, posServices int
83 b0 := b
84 for len(b) > 0 {
85 num, typ, n := wire.ConsumeTag(b)
86 b = b[n:]
87 switch typ {
88 case wire.BytesType:
89 v, m := wire.ConsumeBytes(b)
90 b = b[m:]
91 switch num {
Joe Tsai1af1de02019-03-01 16:12:32 -080092 case descfield.FileDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -080093 fd.path = nb.MakeString(v)
Joe Tsai1af1de02019-03-01 16:12:32 -080094 case descfield.FileDescriptorProto_Package:
Damien Neil8012b442019-01-18 09:32:24 -080095 fd.protoPackage = pref.FullName(nb.MakeString(v))
Joe Tsai1af1de02019-03-01 16:12:32 -080096 case descfield.FileDescriptorProto_EnumType:
97 if prevField != descfield.FileDescriptorProto_EnumType {
Damien Neil8012b442019-01-18 09:32:24 -080098 if numEnums > 0 {
99 panic("non-contiguous repeated field")
100 }
101 posEnums = len(b0) - len(b) - n - m
102 }
103 numEnums++
Joe Tsai1af1de02019-03-01 16:12:32 -0800104 case descfield.FileDescriptorProto_MessageType:
105 if prevField != descfield.FileDescriptorProto_MessageType {
Damien Neil8012b442019-01-18 09:32:24 -0800106 if numMessages > 0 {
107 panic("non-contiguous repeated field")
108 }
109 posMessages = len(b0) - len(b) - n - m
110 }
111 numMessages++
Joe Tsai1af1de02019-03-01 16:12:32 -0800112 case descfield.FileDescriptorProto_Extension:
113 if prevField != descfield.FileDescriptorProto_Extension {
Damien Neil8012b442019-01-18 09:32:24 -0800114 if numExtensions > 0 {
115 panic("non-contiguous repeated field")
116 }
117 posExtensions = len(b0) - len(b) - n - m
118 }
119 numExtensions++
Joe Tsai1af1de02019-03-01 16:12:32 -0800120 case descfield.FileDescriptorProto_Service:
121 if prevField != descfield.FileDescriptorProto_Service {
Damien Neil8012b442019-01-18 09:32:24 -0800122 if numServices > 0 {
123 panic("non-contiguous repeated field")
124 }
125 posServices = len(b0) - len(b) - n - m
126 }
127 numServices++
128 }
129 prevField = num
130 default:
131 m := wire.ConsumeFieldValue(num, typ, b)
132 b = b[m:]
133 prevField = -1 // ignore known field numbers of unknown wire type
134 }
135 }
136
137 // Must allocate all declarations before parsing each descriptor type
138 // to ensure we handled all descriptors in "flattened ordering".
139 if numEnums > 0 {
140 fd.enums.list = fd.allocEnums(numEnums)
141 }
142 if numMessages > 0 {
143 fd.messages.list = fd.allocMessages(numMessages)
144 }
145 if numExtensions > 0 {
146 fd.extensions.list = fd.allocExtensions(numExtensions)
147 }
148 if numServices > 0 {
149 fd.services.list = make([]serviceDesc, numServices)
150 }
151
152 if numEnums > 0 {
153 b := b0[posEnums:]
154 for i := range fd.enums.list {
155 _, n := wire.ConsumeVarint(b)
156 v, m := wire.ConsumeBytes(b[n:])
157 fd.enums.list[i].unmarshalSeed(v, nb, fd, fd, i)
158 b = b[n+m:]
159 }
160 }
161 if numMessages > 0 {
162 b := b0[posMessages:]
163 for i := range fd.messages.list {
164 _, n := wire.ConsumeVarint(b)
165 v, m := wire.ConsumeBytes(b[n:])
166 fd.messages.list[i].unmarshalSeed(v, nb, fd, fd, i)
167 b = b[n+m:]
168 }
169 }
170 if numExtensions > 0 {
171 b := b0[posExtensions:]
172 for i := range fd.extensions.list {
173 _, n := wire.ConsumeVarint(b)
174 v, m := wire.ConsumeBytes(b[n:])
175 fd.extensions.list[i].unmarshalSeed(v, nb, fd, fd, i)
176 b = b[n+m:]
177 }
178 }
179 if numServices > 0 {
180 b := b0[posServices:]
181 for i := range fd.services.list {
182 _, n := wire.ConsumeVarint(b)
183 v, m := wire.ConsumeBytes(b[n:])
184 fd.services.list[i].unmarshalSeed(v, nb, fd, fd, i)
185 b = b[n+m:]
186 }
187 }
188}
189
190func (ed *enumDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
191 ed.parentFile = pf
192 ed.parent = pd
193 ed.index = i
194
195 for len(b) > 0 {
196 num, typ, n := wire.ConsumeTag(b)
197 b = b[n:]
198 switch typ {
199 case wire.BytesType:
200 v, m := wire.ConsumeBytes(b)
201 b = b[m:]
202 switch num {
Joe Tsai1af1de02019-03-01 16:12:32 -0800203 case descfield.EnumDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800204 ed.fullName = nb.AppendFullName(pd.FullName(), v)
205 }
206 default:
207 m := wire.ConsumeFieldValue(num, typ, b)
208 b = b[m:]
209 }
210 }
211}
212
213func (md *messageDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
214 md.parentFile = pf
215 md.parent = pd
216 md.index = i
217
218 var prevField pref.FieldNumber
219 var numEnums, numMessages, numExtensions int
220 var posEnums, posMessages, posExtensions int
221 b0 := b
222 for len(b) > 0 {
223 num, typ, n := wire.ConsumeTag(b)
224 b = b[n:]
225 switch typ {
226 case wire.BytesType:
227 v, m := wire.ConsumeBytes(b)
228 b = b[m:]
229 switch num {
Joe Tsai1af1de02019-03-01 16:12:32 -0800230 case descfield.DescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800231 md.fullName = nb.AppendFullName(pd.FullName(), v)
Joe Tsai1af1de02019-03-01 16:12:32 -0800232 case descfield.DescriptorProto_EnumType:
233 if prevField != descfield.DescriptorProto_EnumType {
Damien Neil8012b442019-01-18 09:32:24 -0800234 if numEnums > 0 {
235 panic("non-contiguous repeated field")
236 }
237 posEnums = len(b0) - len(b) - n - m
238 }
239 numEnums++
Joe Tsai1af1de02019-03-01 16:12:32 -0800240 case descfield.DescriptorProto_NestedType:
241 if prevField != descfield.DescriptorProto_NestedType {
Damien Neil8012b442019-01-18 09:32:24 -0800242 if numMessages > 0 {
243 panic("non-contiguous repeated field")
244 }
245 posMessages = len(b0) - len(b) - n - m
246 }
247 numMessages++
Joe Tsai1af1de02019-03-01 16:12:32 -0800248 case descfield.DescriptorProto_Extension:
249 if prevField != descfield.DescriptorProto_Extension {
Damien Neil8012b442019-01-18 09:32:24 -0800250 if numExtensions > 0 {
251 panic("non-contiguous repeated field")
252 }
253 posExtensions = len(b0) - len(b) - n - m
254 }
255 numExtensions++
256 }
257 prevField = num
258 default:
259 m := wire.ConsumeFieldValue(num, typ, b)
260 b = b[m:]
261 prevField = -1 // ignore known field numbers of unknown wire type
262 }
263 }
264
265 // Must allocate all declarations before parsing each descriptor type
266 // to ensure we handled all descriptors in "flattened ordering".
267 if numEnums > 0 {
268 md.enums.list = md.parentFile.allocEnums(numEnums)
269 }
270 if numMessages > 0 {
271 md.messages.list = md.parentFile.allocMessages(numMessages)
272 }
273 if numExtensions > 0 {
274 md.extensions.list = md.parentFile.allocExtensions(numExtensions)
275 }
276
277 if numEnums > 0 {
278 b := b0[posEnums:]
279 for i := range md.enums.list {
280 _, n := wire.ConsumeVarint(b)
281 v, m := wire.ConsumeBytes(b[n:])
282 md.enums.list[i].unmarshalSeed(v, nb, pf, md, i)
283 b = b[n+m:]
284 }
285 }
286 if numMessages > 0 {
287 b := b0[posMessages:]
288 for i := range md.messages.list {
289 _, n := wire.ConsumeVarint(b)
290 v, m := wire.ConsumeBytes(b[n:])
291 md.messages.list[i].unmarshalSeed(v, nb, pf, md, i)
292 b = b[n+m:]
293 }
294 }
295 if numExtensions > 0 {
296 b := b0[posExtensions:]
297 for i := range md.extensions.list {
298 _, n := wire.ConsumeVarint(b)
299 v, m := wire.ConsumeBytes(b[n:])
300 md.extensions.list[i].unmarshalSeed(v, nb, pf, md, i)
301 b = b[n+m:]
302 }
303 }
304}
305
306func (xd *extensionDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
307 xd.parentFile = pf
308 xd.parent = pd
309 xd.index = i
310
311 for len(b) > 0 {
312 num, typ, n := wire.ConsumeTag(b)
313 b = b[n:]
314 switch typ {
315 case wire.VarintType:
316 v, m := wire.ConsumeVarint(b)
317 b = b[m:]
318 switch num {
Joe Tsai1af1de02019-03-01 16:12:32 -0800319 case descfield.FieldDescriptorProto_Number:
Damien Neil8012b442019-01-18 09:32:24 -0800320 xd.number = pref.FieldNumber(v)
321 }
322 case wire.BytesType:
323 v, m := wire.ConsumeBytes(b)
324 b = b[m:]
325 switch num {
Joe Tsai1af1de02019-03-01 16:12:32 -0800326 case descfield.FieldDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800327 xd.fullName = nb.AppendFullName(pd.FullName(), v)
328 }
329 default:
330 m := wire.ConsumeFieldValue(num, typ, b)
331 b = b[m:]
332 }
333 }
334}
335
336func (sd *serviceDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
337 sd.parentFile = pf
338 sd.parent = pd
339 sd.index = i
340
341 for len(b) > 0 {
342 num, typ, n := wire.ConsumeTag(b)
343 b = b[n:]
344 switch typ {
345 case wire.BytesType:
346 v, m := wire.ConsumeBytes(b)
347 b = b[m:]
348 switch num {
Joe Tsai1af1de02019-03-01 16:12:32 -0800349 case descfield.ServiceDescriptorProto_Name:
Damien Neil8012b442019-01-18 09:32:24 -0800350 sd.fullName = nb.AppendFullName(pd.FullName(), v)
351 }
352 default:
353 m := wire.ConsumeFieldValue(num, typ, b)
354 b = b[m:]
355 }
356 }
357}