mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-30 12:32:36 +00:00
d888139e7b
The internal/fileinit package is split apart into two packages: * internal/filedesc constructs descriptors from the raw proto. It is very similar to the previous internal/fileinit package. * internal/filetype wraps descriptors with Go type information Overview: * The internal/fileinit package will be deleted in a future CL. It is kept around since the v1 repo currently depends on it. * The internal/prototype package is deleted. All former usages of it are now using internal/filedesc instead. Most significantly, the reflect/protodesc package was almost entirely re-written. * The internal/impl package drops support for messages that do not have a Descriptor method (pre-2016). This removes a significant amount of technical debt. filedesc.Builder to parse raw descriptors. * The internal/encoding/defval package now handles enum values by name. Change-Id: I3957bcc8588a70470fd6c7de1122216b80615ab7 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/182360 Reviewed-by: Damien Neil <dneil@google.com>
391 lines
10 KiB
Go
391 lines
10 KiB
Go
// Copyright 2019 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 filedesc
|
|
|
|
import (
|
|
"google.golang.org/protobuf/internal/encoding/wire"
|
|
"google.golang.org/protobuf/internal/fieldnum"
|
|
pref "google.golang.org/protobuf/reflect/protoreflect"
|
|
)
|
|
|
|
// fileRaw is a data struct used when initializing a file descriptor from
|
|
// a raw FileDescriptorProto.
|
|
type fileRaw struct {
|
|
builder DescBuilder
|
|
allEnums []Enum
|
|
allMessages []Message
|
|
allExtensions []Extension
|
|
allServices []Service
|
|
}
|
|
|
|
func newRawFile(db DescBuilder) *File {
|
|
fd := &File{fileRaw: fileRaw{builder: db}}
|
|
fd.initDecls(db.NumEnums, db.NumMessages, db.NumExtensions, db.NumServices)
|
|
fd.unmarshalSeed(db.RawDescriptor)
|
|
|
|
// Extended message targets are eagerly resolved since registration
|
|
// needs this information at program init time.
|
|
for i := range fd.allExtensions {
|
|
xd := &fd.allExtensions[i]
|
|
xd.L1.Extendee = fd.resolveMessageDependency(xd.L1.Extendee, listExtTargets, int32(i))
|
|
}
|
|
|
|
fd.checkDecls()
|
|
return fd
|
|
}
|
|
|
|
// initDecls pre-allocates slices for the exact number of enums, messages
|
|
// (including map entries), extensions, and services 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 *File) initDecls(numEnums, numMessages, numExtensions, numServices int32) {
|
|
fd.allEnums = make([]Enum, 0, numEnums)
|
|
fd.allMessages = make([]Message, 0, numMessages)
|
|
fd.allExtensions = make([]Extension, 0, numExtensions)
|
|
fd.allServices = make([]Service, 0, numServices)
|
|
}
|
|
|
|
func (fd *File) allocEnums(n int) []Enum {
|
|
total := len(fd.allEnums)
|
|
es := fd.allEnums[total : total+n]
|
|
fd.allEnums = fd.allEnums[:total+n]
|
|
return es
|
|
}
|
|
func (fd *File) allocMessages(n int) []Message {
|
|
total := len(fd.allMessages)
|
|
ms := fd.allMessages[total : total+n]
|
|
fd.allMessages = fd.allMessages[:total+n]
|
|
return ms
|
|
}
|
|
func (fd *File) allocExtensions(n int) []Extension {
|
|
total := len(fd.allExtensions)
|
|
xs := fd.allExtensions[total : total+n]
|
|
fd.allExtensions = fd.allExtensions[:total+n]
|
|
return xs
|
|
}
|
|
func (fd *File) allocServices(n int) []Service {
|
|
total := len(fd.allServices)
|
|
xs := fd.allServices[total : total+n]
|
|
fd.allServices = fd.allServices[: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 *File) checkDecls() {
|
|
switch {
|
|
case len(fd.allEnums) != cap(fd.allEnums):
|
|
case len(fd.allMessages) != cap(fd.allMessages):
|
|
case len(fd.allExtensions) != cap(fd.allExtensions):
|
|
case len(fd.allServices) != cap(fd.allServices):
|
|
default:
|
|
return
|
|
}
|
|
panic("mismatching cardinality")
|
|
}
|
|
|
|
func (fd *File) 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 fieldnum.FileDescriptorProto_Syntax:
|
|
switch string(v) {
|
|
case "proto2":
|
|
fd.L1.Syntax = pref.Proto2
|
|
case "proto3":
|
|
fd.L1.Syntax = pref.Proto3
|
|
default:
|
|
panic("invalid syntax")
|
|
}
|
|
case fieldnum.FileDescriptorProto_Name:
|
|
fd.L1.Path = nb.MakeString(v)
|
|
case fieldnum.FileDescriptorProto_Package:
|
|
fd.L1.Package = pref.FullName(nb.MakeString(v))
|
|
case fieldnum.FileDescriptorProto_EnumType:
|
|
if prevField != fieldnum.FileDescriptorProto_EnumType {
|
|
if numEnums > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posEnums = len(b0) - len(b) - n - m
|
|
}
|
|
numEnums++
|
|
case fieldnum.FileDescriptorProto_MessageType:
|
|
if prevField != fieldnum.FileDescriptorProto_MessageType {
|
|
if numMessages > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posMessages = len(b0) - len(b) - n - m
|
|
}
|
|
numMessages++
|
|
case fieldnum.FileDescriptorProto_Extension:
|
|
if prevField != fieldnum.FileDescriptorProto_Extension {
|
|
if numExtensions > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posExtensions = len(b0) - len(b) - n - m
|
|
}
|
|
numExtensions++
|
|
case fieldnum.FileDescriptorProto_Service:
|
|
if prevField != fieldnum.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
|
|
}
|
|
}
|
|
|
|
// If syntax is missing, it is assumed to be proto2.
|
|
if fd.L1.Syntax == 0 {
|
|
fd.L1.Syntax = pref.Proto2
|
|
}
|
|
|
|
// Must allocate all declarations before parsing each descriptor type
|
|
// to ensure we handled all descriptors in "flattened ordering".
|
|
if numEnums > 0 {
|
|
fd.L1.Enums.List = fd.allocEnums(numEnums)
|
|
}
|
|
if numMessages > 0 {
|
|
fd.L1.Messages.List = fd.allocMessages(numMessages)
|
|
}
|
|
if numExtensions > 0 {
|
|
fd.L1.Extensions.List = fd.allocExtensions(numExtensions)
|
|
}
|
|
if numServices > 0 {
|
|
fd.L1.Services.List = fd.allocServices(numServices)
|
|
}
|
|
|
|
if numEnums > 0 {
|
|
b := b0[posEnums:]
|
|
for i := range fd.L1.Enums.List {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
fd.L1.Enums.List[i].unmarshalSeed(v, nb, fd, fd, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
if numMessages > 0 {
|
|
b := b0[posMessages:]
|
|
for i := range fd.L1.Messages.List {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
fd.L1.Messages.List[i].unmarshalSeed(v, nb, fd, fd, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
if numExtensions > 0 {
|
|
b := b0[posExtensions:]
|
|
for i := range fd.L1.Extensions.List {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
fd.L1.Extensions.List[i].unmarshalSeed(v, nb, fd, fd, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
if numServices > 0 {
|
|
b := b0[posServices:]
|
|
for i := range fd.L1.Services.List {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
fd.L1.Services.List[i].unmarshalSeed(v, nb, fd, fd, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
}
|
|
|
|
func (ed *Enum) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
|
|
ed.L0.ParentFile = pf
|
|
ed.L0.Parent = pd
|
|
ed.L0.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 fieldnum.EnumDescriptorProto_Name:
|
|
ed.L0.FullName = nb.AppendFullName(pd.FullName(), v)
|
|
}
|
|
default:
|
|
m := wire.ConsumeFieldValue(num, typ, b)
|
|
b = b[m:]
|
|
}
|
|
}
|
|
}
|
|
|
|
func (md *Message) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
|
|
md.L0.ParentFile = pf
|
|
md.L0.Parent = pd
|
|
md.L0.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 fieldnum.DescriptorProto_Name:
|
|
md.L0.FullName = nb.AppendFullName(pd.FullName(), v)
|
|
case fieldnum.DescriptorProto_EnumType:
|
|
if prevField != fieldnum.DescriptorProto_EnumType {
|
|
if numEnums > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posEnums = len(b0) - len(b) - n - m
|
|
}
|
|
numEnums++
|
|
case fieldnum.DescriptorProto_NestedType:
|
|
if prevField != fieldnum.DescriptorProto_NestedType {
|
|
if numMessages > 0 {
|
|
panic("non-contiguous repeated field")
|
|
}
|
|
posMessages = len(b0) - len(b) - n - m
|
|
}
|
|
numMessages++
|
|
case fieldnum.DescriptorProto_Extension:
|
|
if prevField != fieldnum.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.L1.Enums.List = pf.allocEnums(numEnums)
|
|
}
|
|
if numMessages > 0 {
|
|
md.L1.Messages.List = pf.allocMessages(numMessages)
|
|
}
|
|
if numExtensions > 0 {
|
|
md.L1.Extensions.List = pf.allocExtensions(numExtensions)
|
|
}
|
|
|
|
if numEnums > 0 {
|
|
b := b0[posEnums:]
|
|
for i := range md.L1.Enums.List {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
md.L1.Enums.List[i].unmarshalSeed(v, nb, pf, md, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
if numMessages > 0 {
|
|
b := b0[posMessages:]
|
|
for i := range md.L1.Messages.List {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
md.L1.Messages.List[i].unmarshalSeed(v, nb, pf, md, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
if numExtensions > 0 {
|
|
b := b0[posExtensions:]
|
|
for i := range md.L1.Extensions.List {
|
|
_, n := wire.ConsumeVarint(b)
|
|
v, m := wire.ConsumeBytes(b[n:])
|
|
md.L1.Extensions.List[i].unmarshalSeed(v, nb, pf, md, i)
|
|
b = b[n+m:]
|
|
}
|
|
}
|
|
}
|
|
|
|
func (xd *Extension) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
|
|
xd.L0.ParentFile = pf
|
|
xd.L0.Parent = pd
|
|
xd.L0.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 fieldnum.FieldDescriptorProto_Number:
|
|
xd.L1.Number = pref.FieldNumber(v)
|
|
case fieldnum.FieldDescriptorProto_Type:
|
|
xd.L1.Kind = pref.Kind(v)
|
|
}
|
|
case wire.BytesType:
|
|
v, m := wire.ConsumeBytes(b)
|
|
b = b[m:]
|
|
switch num {
|
|
case fieldnum.FieldDescriptorProto_Name:
|
|
xd.L0.FullName = nb.AppendFullName(pd.FullName(), v)
|
|
case fieldnum.FieldDescriptorProto_Extendee:
|
|
xd.L1.Extendee = PlaceholderMessage(nb.MakeFullName(v))
|
|
}
|
|
default:
|
|
m := wire.ConsumeFieldValue(num, typ, b)
|
|
b = b[m:]
|
|
}
|
|
}
|
|
}
|
|
|
|
func (sd *Service) unmarshalSeed(b []byte, nb *nameBuilder, pf *File, pd pref.Descriptor, i int) {
|
|
sd.L0.ParentFile = pf
|
|
sd.L0.Parent = pd
|
|
sd.L0.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 fieldnum.ServiceDescriptorProto_Name:
|
|
sd.L0.FullName = nb.AppendFullName(pd.FullName(), v)
|
|
}
|
|
default:
|
|
m := wire.ConsumeFieldValue(num, typ, b)
|
|
b = b[m:]
|
|
}
|
|
}
|
|
}
|