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 | |
Joe Tsai | 4532dd7 | 2019-03-19 17:04:06 -0700 | [diff] [blame^] | 22 | // 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 Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 29 | // 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 Tsai | 4532dd7 | 2019-03-19 17:04:06 -0700 | [diff] [blame^] | 41 | // (including map entries), and extensions declared in the proto file. |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 42 | // 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. |
| 46 | func (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 | |
| 54 | func (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 | } |
| 60 | func (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 | } |
| 66 | func (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. |
| 75 | func (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 | |
| 83 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 99 | case fieldnum.FileDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 100 | fd.path = nb.MakeString(v) |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 101 | case fieldnum.FileDescriptorProto_Package: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 102 | fd.protoPackage = pref.FullName(nb.MakeString(v)) |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 103 | case fieldnum.FileDescriptorProto_EnumType: |
| 104 | if prevField != fieldnum.FileDescriptorProto_EnumType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 105 | if numEnums > 0 { |
| 106 | panic("non-contiguous repeated field") |
| 107 | } |
| 108 | posEnums = len(b0) - len(b) - n - m |
| 109 | } |
| 110 | numEnums++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 111 | case fieldnum.FileDescriptorProto_MessageType: |
| 112 | if prevField != fieldnum.FileDescriptorProto_MessageType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 113 | if numMessages > 0 { |
| 114 | panic("non-contiguous repeated field") |
| 115 | } |
| 116 | posMessages = len(b0) - len(b) - n - m |
| 117 | } |
| 118 | numMessages++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 119 | case fieldnum.FileDescriptorProto_Extension: |
| 120 | if prevField != fieldnum.FileDescriptorProto_Extension { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 121 | if numExtensions > 0 { |
| 122 | panic("non-contiguous repeated field") |
| 123 | } |
| 124 | posExtensions = len(b0) - len(b) - n - m |
| 125 | } |
| 126 | numExtensions++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 127 | case fieldnum.FileDescriptorProto_Service: |
| 128 | if prevField != fieldnum.FileDescriptorProto_Service { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 129 | 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 | |
| 197 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 210 | case fieldnum.EnumDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 211 | 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 | |
| 220 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 237 | case fieldnum.DescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 238 | md.fullName = nb.AppendFullName(pd.FullName(), v) |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 239 | case fieldnum.DescriptorProto_EnumType: |
| 240 | if prevField != fieldnum.DescriptorProto_EnumType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 241 | if numEnums > 0 { |
| 242 | panic("non-contiguous repeated field") |
| 243 | } |
| 244 | posEnums = len(b0) - len(b) - n - m |
| 245 | } |
| 246 | numEnums++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 247 | case fieldnum.DescriptorProto_NestedType: |
| 248 | if prevField != fieldnum.DescriptorProto_NestedType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 249 | if numMessages > 0 { |
| 250 | panic("non-contiguous repeated field") |
| 251 | } |
| 252 | posMessages = len(b0) - len(b) - n - m |
| 253 | } |
| 254 | numMessages++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 255 | case fieldnum.DescriptorProto_Extension: |
| 256 | if prevField != fieldnum.DescriptorProto_Extension { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 257 | 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 Tsai | 4532dd7 | 2019-03-19 17:04:06 -0700 | [diff] [blame^] | 289 | md.enums.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i) |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 290 | 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 Tsai | 4532dd7 | 2019-03-19 17:04:06 -0700 | [diff] [blame^] | 298 | md.messages.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i) |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 299 | 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 Tsai | 4532dd7 | 2019-03-19 17:04:06 -0700 | [diff] [blame^] | 307 | md.extensions.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i) |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 308 | b = b[n+m:] |
| 309 | } |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 326 | case fieldnum.FieldDescriptorProto_Number: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 327 | xd.number = pref.FieldNumber(v) |
| 328 | } |
| 329 | case wire.BytesType: |
| 330 | v, m := wire.ConsumeBytes(b) |
| 331 | b = b[m:] |
| 332 | switch num { |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 333 | case fieldnum.FieldDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 334 | 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 | |
| 343 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 356 | case fieldnum.ServiceDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 357 | sd.fullName = nb.AppendFullName(pd.FullName(), v) |
| 358 | } |
| 359 | default: |
| 360 | m := wire.ConsumeFieldValue(num, typ, b) |
| 361 | b = b[m:] |
| 362 | } |
| 363 | } |
| 364 | } |