Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 1 | // 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 | |
| 5 | package fileinit |
| 6 | |
| 7 | import ( |
| 8 | wire "github.com/golang/protobuf/v2/internal/encoding/wire" |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 9 | fieldnum "github.com/golang/protobuf/v2/internal/fieldnum" |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 10 | pref "github.com/golang/protobuf/v2/reflect/protoreflect" |
| 11 | ) |
| 12 | |
| 13 | func 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. |
| 39 | func (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 | |
| 47 | func (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 | } |
| 53 | func (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 | } |
| 59 | func (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. |
| 68 | func (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 | |
| 76 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 92 | case fieldnum.FileDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 93 | fd.path = nb.MakeString(v) |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 94 | case fieldnum.FileDescriptorProto_Package: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 95 | fd.protoPackage = pref.FullName(nb.MakeString(v)) |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 96 | case fieldnum.FileDescriptorProto_EnumType: |
| 97 | if prevField != fieldnum.FileDescriptorProto_EnumType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 98 | if numEnums > 0 { |
| 99 | panic("non-contiguous repeated field") |
| 100 | } |
| 101 | posEnums = len(b0) - len(b) - n - m |
| 102 | } |
| 103 | numEnums++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 104 | case fieldnum.FileDescriptorProto_MessageType: |
| 105 | if prevField != fieldnum.FileDescriptorProto_MessageType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 106 | if numMessages > 0 { |
| 107 | panic("non-contiguous repeated field") |
| 108 | } |
| 109 | posMessages = len(b0) - len(b) - n - m |
| 110 | } |
| 111 | numMessages++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 112 | case fieldnum.FileDescriptorProto_Extension: |
| 113 | if prevField != fieldnum.FileDescriptorProto_Extension { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 114 | if numExtensions > 0 { |
| 115 | panic("non-contiguous repeated field") |
| 116 | } |
| 117 | posExtensions = len(b0) - len(b) - n - m |
| 118 | } |
| 119 | numExtensions++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 120 | case fieldnum.FileDescriptorProto_Service: |
| 121 | if prevField != fieldnum.FileDescriptorProto_Service { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 122 | 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 | |
| 190 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 203 | case fieldnum.EnumDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 204 | 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 | |
| 213 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 230 | case fieldnum.DescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 231 | md.fullName = nb.AppendFullName(pd.FullName(), v) |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 232 | case fieldnum.DescriptorProto_EnumType: |
| 233 | if prevField != fieldnum.DescriptorProto_EnumType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 234 | if numEnums > 0 { |
| 235 | panic("non-contiguous repeated field") |
| 236 | } |
| 237 | posEnums = len(b0) - len(b) - n - m |
| 238 | } |
| 239 | numEnums++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 240 | case fieldnum.DescriptorProto_NestedType: |
| 241 | if prevField != fieldnum.DescriptorProto_NestedType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 242 | if numMessages > 0 { |
| 243 | panic("non-contiguous repeated field") |
| 244 | } |
| 245 | posMessages = len(b0) - len(b) - n - m |
| 246 | } |
| 247 | numMessages++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 248 | case fieldnum.DescriptorProto_Extension: |
| 249 | if prevField != fieldnum.DescriptorProto_Extension { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 250 | 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 | |
| 306 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 319 | case fieldnum.FieldDescriptorProto_Number: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 320 | xd.number = pref.FieldNumber(v) |
| 321 | } |
| 322 | case wire.BytesType: |
| 323 | v, m := wire.ConsumeBytes(b) |
| 324 | b = b[m:] |
| 325 | switch num { |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 326 | case fieldnum.FieldDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 327 | 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 | |
| 336 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 349 | case fieldnum.ServiceDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 350 | sd.fullName = nb.AppendFullName(pd.FullName(), v) |
| 351 | } |
| 352 | default: |
| 353 | m := wire.ConsumeFieldValue(num, typ, b) |
| 354 | b = b[m:] |
| 355 | } |
| 356 | } |
| 357 | } |