mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-01 11:58:21 +00:00
1af1de0c15
Generate a list of descriptor fields from the descriptor.proto itself as an internal package. Use these fields for the internal implementation. Change-Id: Ib1ab0c5c6deb332ba6c8018ef55136b7e5974944 Reviewed-on: https://go-review.googlesource.com/c/164864 Reviewed-by: Herbie Ong <herbie@google.com>
358 lines
9.6 KiB
Go
358 lines
9.6 KiB
Go
// Copyright 2018 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package fileinit
|
|
|
|
import (
|
|
descfield "github.com/golang/protobuf/v2/internal/descfield"
|
|
wire "github.com/golang/protobuf/v2/internal/encoding/wire"
|
|
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
|
|
)
|
|
|
|
func newFileDesc(fb FileBuilder) *fileDesc {
|
|
file := &fileDesc{fileInit: fileInit{
|
|
RawDescriptor: fb.RawDescriptor,
|
|
GoTypes: fb.GoTypes,
|
|
DependencyIndexes: fb.DependencyIndexes,
|
|
}}
|
|
file.initDecls(len(fb.EnumOutputTypes), len(fb.MessageOutputTypes), len(fb.ExtensionOutputTypes))
|
|
file.unmarshalSeed(fb.RawDescriptor)
|
|
|
|
// Extended message dependencies are eagerly handled since registration
|
|
// needs this information at program init time.
|
|
for i := range file.allExtensions {
|
|
xd := &file.allExtensions[i]
|
|
xd.extendedType = file.popMessageDependency()
|
|
}
|
|
|
|
file.checkDecls()
|
|
return file
|
|
}
|
|
|
|
// initDecls pre-allocates slices for the exact number of enums, messages
|
|
// (excluding map entries), and extensions declared in the proto file.
|
|
// This is done to avoid regrowing the slice, which would change the address
|
|
// for any previously seen declaration.
|
|
//
|
|
// The alloc methods "allocates" slices by pulling from the capacity.
|
|
func (fd *fileDecls) initDecls(numEnums, numMessages, numExtensions int) {
|
|
*fd = fileDecls{
|
|
allEnums: make([]enumDesc, 0, numEnums),
|
|
allMessages: make([]messageDesc, 0, numMessages),
|
|
allExtensions: make([]extensionDesc, 0, numExtensions),
|
|
}
|
|
}
|
|
|
|
func (fd *fileDecls) allocEnums(n int) []enumDesc {
|
|
total := len(fd.allEnums)
|
|
es := fd.allEnums[total : total+n]
|
|
fd.allEnums = fd.allEnums[:total+n]
|
|
return es
|
|
}
|
|
func (fd *fileDecls) allocMessages(n int) []messageDesc {
|
|
total := len(fd.allMessages)
|
|
ms := fd.allMessages[total : total+n]
|
|
fd.allMessages = fd.allMessages[:total+n]
|
|
return ms
|
|
}
|
|
func (fd *fileDecls) allocExtensions(n int) []extensionDesc {
|
|
total := len(fd.allExtensions)
|
|
xs := fd.allExtensions[total : total+n]
|
|
fd.allExtensions = fd.allExtensions[:total+n]
|
|
return xs
|
|
}
|
|
|
|
// checkDecls performs a sanity check that the expected number of expected
|
|
// declarations matches the number that were found in the descriptor proto.
|
|
func (fd *fileDecls) checkDecls() {
|
|
if len(fd.allEnums) != cap(fd.allEnums) ||
|
|
len(fd.allMessages) != cap(fd.allMessages) ||
|
|
len(fd.allExtensions) != cap(fd.allExtensions) {
|
|
panic("mismatching cardinality")
|
|
}
|
|
}
|
|
|
|
func (fd *fileDesc) unmarshalSeed(b []byte) {
|
|
nb := getNameBuilder()
|
|
defer putNameBuilder(nb)
|
|
|
|
var prevField pref.FieldNumber
|
|
var numEnums, numMessages, numExtensions, numServices int
|
|
var posEnums, posMessages, posExtensions, posServices int
|
|
b0 := b
|
|
for len(b) > 0 {
|
|
num, typ, n := wire.ConsumeTag(b)
|
|
b = b[n:]
|
|
switch typ {
|
|
case wire.BytesType:
|
|
v, m := wire.ConsumeBytes(b)
|
|
b = b[m:]
|
|
switch num {
|
|
case descfield.FileDescriptorProto_Name:
|
|
fd.path = nb.MakeString(v)
|
|
case descfield.FileDescriptorProto_Package:
|
|
fd.protoPackage = pref.FullName(nb.MakeString(v))
|
|
case descfield.FileDescriptorProto_EnumType:
|
|
if prevField != descfield.FileDescriptorProto_EnumType {
|
|
if numEnums > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posEnums = len(b0) - len(b) - n - m
|
|
}
|
|
numEnums++
|
|
case descfield.FileDescriptorProto_MessageType:
|
|
if prevField != descfield.FileDescriptorProto_MessageType {
|
|
if numMessages > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posMessages = len(b0) - len(b) - n - m
|
|
}
|
|
numMessages++
|
|
case descfield.FileDescriptorProto_Extension:
|
|
if prevField != descfield.FileDescriptorProto_Extension {
|
|
if numExtensions > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posExtensions = len(b0) - len(b) - n - m
|
|
}
|
|
numExtensions++
|
|
case descfield.FileDescriptorProto_Service:
|
|
if prevField != descfield.FileDescriptorProto_Service {
|
|
if numServices > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posServices = len(b0) - len(b) - n - m
|
|
}
|
|
numServices++
|
|
}
|
|
prevField = num
|
|
default:
|
|
m := wire.ConsumeFieldValue(num, typ, b)
|
|
b = b[m:]
|
|
prevField = -1 // ignore known field numbers of unknown wire type
|
|
}
|
|
}
|
|
|
|
// Must allocate all declarations before parsing each descriptor type
|
|
// to ensure we handled all descriptors in "flattened ordering".
|
|
if numEnums > 0 {
|
|
fd.enums.list = fd.allocEnums(numEnums)
|
|
}
|
|
if numMessages > 0 {
|
|
fd.messages.list = fd.allocMessages(numMessages)
|
|
}
|
|
if numExtensions > 0 {
|
|
fd.extensions.list = fd.allocExtensions(numExtensions)
|
|
}
|
|
if numServices > 0 {
|
|
fd.services.list = make([]serviceDesc, numServices)
|
|
}
|
|
|
|
if numEnums > 0 {
|
|
b := b0[posEnums:]
|
|
for i := range fd.enums.list {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
fd.enums.list[i].unmarshalSeed(v, nb, fd, fd, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
if numMessages > 0 {
|
|
b := b0[posMessages:]
|
|
for i := range fd.messages.list {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
fd.messages.list[i].unmarshalSeed(v, nb, fd, fd, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
if numExtensions > 0 {
|
|
b := b0[posExtensions:]
|
|
for i := range fd.extensions.list {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
fd.extensions.list[i].unmarshalSeed(v, nb, fd, fd, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
if numServices > 0 {
|
|
b := b0[posServices:]
|
|
for i := range fd.services.list {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
fd.services.list[i].unmarshalSeed(v, nb, fd, fd, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
}
|
|
|
|
func (ed *enumDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
|
|
ed.parentFile = pf
|
|
ed.parent = pd
|
|
ed.index = i
|
|
|
|
for len(b) > 0 {
|
|
num, typ, n := wire.ConsumeTag(b)
|
|
b = b[n:]
|
|
switch typ {
|
|
case wire.BytesType:
|
|
v, m := wire.ConsumeBytes(b)
|
|
b = b[m:]
|
|
switch num {
|
|
case descfield.EnumDescriptorProto_Name:
|
|
ed.fullName = nb.AppendFullName(pd.FullName(), v)
|
|
}
|
|
default:
|
|
m := wire.ConsumeFieldValue(num, typ, b)
|
|
b = b[m:]
|
|
}
|
|
}
|
|
}
|
|
|
|
func (md *messageDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
|
|
md.parentFile = pf
|
|
md.parent = pd
|
|
md.index = i
|
|
|
|
var prevField pref.FieldNumber
|
|
var numEnums, numMessages, numExtensions int
|
|
var posEnums, posMessages, posExtensions int
|
|
b0 := b
|
|
for len(b) > 0 {
|
|
num, typ, n := wire.ConsumeTag(b)
|
|
b = b[n:]
|
|
switch typ {
|
|
case wire.BytesType:
|
|
v, m := wire.ConsumeBytes(b)
|
|
b = b[m:]
|
|
switch num {
|
|
case descfield.DescriptorProto_Name:
|
|
md.fullName = nb.AppendFullName(pd.FullName(), v)
|
|
case descfield.DescriptorProto_EnumType:
|
|
if prevField != descfield.DescriptorProto_EnumType {
|
|
if numEnums > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posEnums = len(b0) - len(b) - n - m
|
|
}
|
|
numEnums++
|
|
case descfield.DescriptorProto_NestedType:
|
|
if prevField != descfield.DescriptorProto_NestedType {
|
|
if numMessages > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posMessages = len(b0) - len(b) - n - m
|
|
}
|
|
numMessages++
|
|
case descfield.DescriptorProto_Extension:
|
|
if prevField != descfield.DescriptorProto_Extension {
|
|
if numExtensions > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posExtensions = len(b0) - len(b) - n - m
|
|
}
|
|
numExtensions++
|
|
}
|
|
prevField = num
|
|
default:
|
|
m := wire.ConsumeFieldValue(num, typ, b)
|
|
b = b[m:]
|
|
prevField = -1 // ignore known field numbers of unknown wire type
|
|
}
|
|
}
|
|
|
|
// Must allocate all declarations before parsing each descriptor type
|
|
// to ensure we handled all descriptors in "flattened ordering".
|
|
if numEnums > 0 {
|
|
md.enums.list = md.parentFile.allocEnums(numEnums)
|
|
}
|
|
if numMessages > 0 {
|
|
md.messages.list = md.parentFile.allocMessages(numMessages)
|
|
}
|
|
if numExtensions > 0 {
|
|
md.extensions.list = md.parentFile.allocExtensions(numExtensions)
|
|
}
|
|
|
|
if numEnums > 0 {
|
|
b := b0[posEnums:]
|
|
for i := range md.enums.list {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
md.enums.list[i].unmarshalSeed(v, nb, pf, md, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
if numMessages > 0 {
|
|
b := b0[posMessages:]
|
|
for i := range md.messages.list {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
md.messages.list[i].unmarshalSeed(v, nb, pf, md, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
if numExtensions > 0 {
|
|
b := b0[posExtensions:]
|
|
for i := range md.extensions.list {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
md.extensions.list[i].unmarshalSeed(v, nb, pf, md, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
}
|
|
|
|
func (xd *extensionDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
|
|
xd.parentFile = pf
|
|
xd.parent = pd
|
|
xd.index = i
|
|
|
|
for len(b) > 0 {
|
|
num, typ, n := wire.ConsumeTag(b)
|
|
b = b[n:]
|
|
switch typ {
|
|
case wire.VarintType:
|
|
v, m := wire.ConsumeVarint(b)
|
|
b = b[m:]
|
|
switch num {
|
|
case descfield.FieldDescriptorProto_Number:
|
|
xd.number = pref.FieldNumber(v)
|
|
}
|
|
case wire.BytesType:
|
|
v, m := wire.ConsumeBytes(b)
|
|
b = b[m:]
|
|
switch num {
|
|
case descfield.FieldDescriptorProto_Name:
|
|
xd.fullName = nb.AppendFullName(pd.FullName(), v)
|
|
}
|
|
default:
|
|
m := wire.ConsumeFieldValue(num, typ, b)
|
|
b = b[m:]
|
|
}
|
|
}
|
|
}
|
|
|
|
func (sd *serviceDesc) unmarshalSeed(b []byte, nb *nameBuilder, pf *fileDesc, pd pref.Descriptor, i int) {
|
|
sd.parentFile = pf
|
|
sd.parent = pd
|
|
sd.index = i
|
|
|
|
for len(b) > 0 {
|
|
num, typ, n := wire.ConsumeTag(b)
|
|
b = b[n:]
|
|
switch typ {
|
|
case wire.BytesType:
|
|
v, m := wire.ConsumeBytes(b)
|
|
b = b[m:]
|
|
switch num {
|
|
case descfield.ServiceDescriptorProto_Name:
|
|
sd.fullName = nb.AppendFullName(pd.FullName(), v)
|
|
}
|
|
default:
|
|
m := wire.ConsumeFieldValue(num, typ, b)
|
|
b = b[m:]
|
|
}
|
|
}
|
|
}
|