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{ |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 15 | GoTypes: fb.GoTypes, |
| 16 | DependencyIndexes: fb.DependencyIndexes, |
Joe Tsai | e089c0f | 2019-04-16 01:46:14 -0700 | [diff] [blame] | 17 | }, rawDesc: fb.RawDescriptor} |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 18 | 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 Tsai | 4532dd7 | 2019-03-19 17:04:06 -0700 | [diff] [blame] | 33 | // (including map entries), and extensions declared in the proto file. |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 34 | // 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. |
| 38 | func (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 | |
| 46 | func (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 | } |
| 52 | func (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 | } |
| 58 | func (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. |
| 67 | func (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 | |
| 75 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 91 | case fieldnum.FileDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 92 | fd.path = nb.MakeString(v) |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 93 | case fieldnum.FileDescriptorProto_Package: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 94 | fd.protoPackage = pref.FullName(nb.MakeString(v)) |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 95 | case fieldnum.FileDescriptorProto_EnumType: |
| 96 | if prevField != fieldnum.FileDescriptorProto_EnumType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 97 | if numEnums > 0 { |
| 98 | panic("non-contiguous repeated field") |
| 99 | } |
| 100 | posEnums = len(b0) - len(b) - n - m |
| 101 | } |
| 102 | numEnums++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 103 | case fieldnum.FileDescriptorProto_MessageType: |
| 104 | if prevField != fieldnum.FileDescriptorProto_MessageType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 105 | if numMessages > 0 { |
| 106 | panic("non-contiguous repeated field") |
| 107 | } |
| 108 | posMessages = len(b0) - len(b) - n - m |
| 109 | } |
| 110 | numMessages++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 111 | case fieldnum.FileDescriptorProto_Extension: |
| 112 | if prevField != fieldnum.FileDescriptorProto_Extension { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 113 | if numExtensions > 0 { |
| 114 | panic("non-contiguous repeated field") |
| 115 | } |
| 116 | posExtensions = len(b0) - len(b) - n - m |
| 117 | } |
| 118 | numExtensions++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 119 | case fieldnum.FileDescriptorProto_Service: |
| 120 | if prevField != fieldnum.FileDescriptorProto_Service { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 121 | 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 | |
| 189 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 202 | case fieldnum.EnumDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 203 | 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 | |
| 212 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 229 | case fieldnum.DescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 230 | md.fullName = nb.AppendFullName(pd.FullName(), v) |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 231 | case fieldnum.DescriptorProto_EnumType: |
| 232 | if prevField != fieldnum.DescriptorProto_EnumType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 233 | if numEnums > 0 { |
| 234 | panic("non-contiguous repeated field") |
| 235 | } |
| 236 | posEnums = len(b0) - len(b) - n - m |
| 237 | } |
| 238 | numEnums++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 239 | case fieldnum.DescriptorProto_NestedType: |
| 240 | if prevField != fieldnum.DescriptorProto_NestedType { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 241 | if numMessages > 0 { |
| 242 | panic("non-contiguous repeated field") |
| 243 | } |
| 244 | posMessages = len(b0) - len(b) - n - m |
| 245 | } |
| 246 | numMessages++ |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 247 | case fieldnum.DescriptorProto_Extension: |
| 248 | if prevField != fieldnum.DescriptorProto_Extension { |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 249 | 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 Tsai | 4532dd7 | 2019-03-19 17:04:06 -0700 | [diff] [blame] | 281 | md.enums.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i) |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 282 | 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 Tsai | 4532dd7 | 2019-03-19 17:04:06 -0700 | [diff] [blame] | 290 | md.messages.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i) |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 291 | 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 Tsai | 4532dd7 | 2019-03-19 17:04:06 -0700 | [diff] [blame] | 299 | md.extensions.list[i].unmarshalSeed(v, nb, pf, md.asDesc(), i) |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 300 | b = b[n+m:] |
| 301 | } |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 318 | case fieldnum.FieldDescriptorProto_Number: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 319 | xd.number = pref.FieldNumber(v) |
| 320 | } |
| 321 | case wire.BytesType: |
| 322 | v, m := wire.ConsumeBytes(b) |
| 323 | b = b[m:] |
| 324 | switch num { |
Joe Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 325 | case fieldnum.FieldDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 326 | 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 | |
| 335 | func (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 Tsai | ca46d8c | 2019-03-20 16:51:09 -0700 | [diff] [blame] | 348 | case fieldnum.ServiceDescriptorProto_Name: |
Damien Neil | 8012b44 | 2019-01-18 09:32:24 -0800 | [diff] [blame] | 349 | sd.fullName = nb.AppendFullName(pd.FullName(), v) |
| 350 | } |
| 351 | default: |
| 352 | m := wire.ConsumeFieldValue(num, typ, b) |
| 353 | b = b[m:] |
| 354 | } |
| 355 | } |
| 356 | } |