mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-04-10 06:44:15 +00:00
internal/legacy: remove dependency on descriptor.proto
We jump through many hoops to avoid generated protos depending on internal/legacy. Break the cycle in the other direction: Remove the dependency on descriptor.proto from internal/legacy by using a hand-written parser for the few descriptor fields we need. Still to do: Remove the descriptor.proto dependency from internal/encoding/tag. Change-Id: I5fd99a2170470ba8530eb2679b6dde899821bf3e Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/171457 Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
This commit is contained in:
parent
4ec39c7663
commit
987d570c08
@ -13,8 +13,6 @@ import (
|
|||||||
ptype "github.com/golang/protobuf/v2/internal/prototype"
|
ptype "github.com/golang/protobuf/v2/internal/prototype"
|
||||||
pvalue "github.com/golang/protobuf/v2/internal/value"
|
pvalue "github.com/golang/protobuf/v2/internal/value"
|
||||||
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
|
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
|
||||||
|
|
||||||
descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// wrapEnum wraps v as a protoreflect.Enum,
|
// wrapEnum wraps v as a protoreflect.Enum,
|
||||||
@ -107,7 +105,7 @@ func LoadEnumDesc(t reflect.Type) pref.EnumDescriptor {
|
|||||||
}
|
}
|
||||||
if ed, ok := ev.(enumV1); ok {
|
if ed, ok := ev.(enumV1); ok {
|
||||||
b, idxs := ed.EnumDescriptor()
|
b, idxs := ed.EnumDescriptor()
|
||||||
fd := LoadFileDesc(b)
|
fd := loadFileDesc(b)
|
||||||
|
|
||||||
// Derive syntax.
|
// Derive syntax.
|
||||||
switch fd.GetSyntax() {
|
switch fd.GetSyntax() {
|
||||||
@ -118,7 +116,7 @@ func LoadEnumDesc(t reflect.Type) pref.EnumDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Derive the full name and correct enum descriptor.
|
// Derive the full name and correct enum descriptor.
|
||||||
var ed *descriptorpb.EnumDescriptorProto
|
var ed *enumDescriptorProto
|
||||||
e.FullName = pref.FullName(fd.GetPackage())
|
e.FullName = pref.FullName(fd.GetPackage())
|
||||||
if len(idxs) == 1 {
|
if len(idxs) == 1 {
|
||||||
ed = fd.EnumType[idxs[0]]
|
ed = fd.EnumType[idxs[0]]
|
||||||
@ -135,7 +133,7 @@ func LoadEnumDesc(t reflect.Type) pref.EnumDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Derive the enum values.
|
// Derive the enum values.
|
||||||
for _, vd := range ed.GetValue() {
|
for _, vd := range ed.Value {
|
||||||
e.Values = append(e.Values, ptype.EnumValue{
|
e.Values = append(e.Values, ptype.EnumValue{
|
||||||
Name: pref.Name(vd.GetName()),
|
Name: pref.Name(vd.GetName()),
|
||||||
Number: pref.EnumNumber(vd.GetNumber()),
|
Number: pref.EnumNumber(vd.GetNumber()),
|
||||||
|
@ -112,7 +112,7 @@ func extensionDescFromType(t pref.ExtensionType) *piface.ExtensionDescV1 {
|
|||||||
}
|
}
|
||||||
if ed, ok := ev.(enumV1); ok && protoPkg == "" {
|
if ed, ok := ev.(enumV1); ok && protoPkg == "" {
|
||||||
b, _ := ed.EnumDescriptor()
|
b, _ := ed.EnumDescriptor()
|
||||||
protoPkg = LoadFileDesc(b).GetPackage()
|
protoPkg = loadFileDesc(b).GetPackage()
|
||||||
}
|
}
|
||||||
|
|
||||||
if protoPkg != "" {
|
if protoPkg != "" {
|
||||||
|
@ -10,9 +10,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/golang/protobuf/v2/proto"
|
|
||||||
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
|
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
|
||||||
descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Every enum and message type generated by protoc-gen-go since commit 2fc053c5
|
// Every enum and message type generated by protoc-gen-go since commit 2fc053c5
|
||||||
@ -34,22 +32,19 @@ type (
|
|||||||
|
|
||||||
var fileDescCache sync.Map // map[*byte]*descriptorpb.FileDescriptorProto
|
var fileDescCache sync.Map // map[*byte]*descriptorpb.FileDescriptorProto
|
||||||
|
|
||||||
// LoadFileDesc unmarshals b as a compressed FileDescriptorProto message.
|
// loadFileDesc unmarshals b as a compressed FileDescriptorProto message.
|
||||||
//
|
//
|
||||||
// This assumes that b is immutable and that b does not refer to part of a
|
// This assumes that b is immutable and that b does not refer to part of a
|
||||||
// concatenated series of GZIP files (which would require shenanigans that
|
// concatenated series of GZIP files (which would require shenanigans that
|
||||||
// rely on the concatenation properties of both protobufs and GZIP).
|
// rely on the concatenation properties of both protobufs and GZIP).
|
||||||
// File descriptors generated by protoc-gen-go do not rely on that property.
|
// File descriptors generated by protoc-gen-go do not rely on that property.
|
||||||
//
|
func loadFileDesc(b []byte) *fileDescriptorProto {
|
||||||
// This is exported for testing purposes.
|
|
||||||
func LoadFileDesc(b []byte) *descriptorpb.FileDescriptorProto {
|
|
||||||
// Fast-path: check whether we already have a cached file descriptor.
|
// Fast-path: check whether we already have a cached file descriptor.
|
||||||
if fd, ok := fileDescCache.Load(&b[0]); ok {
|
if fd, ok := fileDescCache.Load(&b[0]); ok {
|
||||||
return fd.(*descriptorpb.FileDescriptorProto)
|
return fd.(*fileDescriptorProto)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slow-path: decompress and unmarshal the file descriptor proto.
|
// Slow-path: decompress and unmarshal the file descriptor proto.
|
||||||
fd := new(descriptorpb.FileDescriptorProto)
|
|
||||||
zr, err := gzip.NewReader(bytes.NewReader(b))
|
zr, err := gzip.NewReader(bytes.NewReader(b))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -58,12 +53,9 @@ func LoadFileDesc(b []byte) *descriptorpb.FileDescriptorProto {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
err = proto.UnmarshalOptions{DiscardUnknown: true}.Unmarshal(b, fd)
|
fd := parseFileDescProto(b)
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if fd, ok := fileDescCache.LoadOrStore(&b[0], fd); ok {
|
if fd, ok := fileDescCache.LoadOrStore(&b[0], fd); ok {
|
||||||
return fd.(*descriptorpb.FileDescriptorProto)
|
return fd.(*fileDescriptorProto)
|
||||||
}
|
}
|
||||||
return fd
|
return fd
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,18 @@
|
|||||||
package legacy_test
|
package legacy_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
|
"io/ioutil"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
legacy "github.com/golang/protobuf/v2/internal/legacy"
|
legacy "github.com/golang/protobuf/v2/internal/legacy"
|
||||||
pragma "github.com/golang/protobuf/v2/internal/pragma"
|
pragma "github.com/golang/protobuf/v2/internal/pragma"
|
||||||
|
"github.com/golang/protobuf/v2/proto"
|
||||||
pdesc "github.com/golang/protobuf/v2/reflect/protodesc"
|
pdesc "github.com/golang/protobuf/v2/reflect/protodesc"
|
||||||
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
|
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
|
||||||
|
descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
|
||||||
cmp "github.com/google/go-cmp/cmp"
|
cmp "github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
proto2_20160225 "github.com/golang/protobuf/v2/internal/testprotos/legacy/proto2.v0.0.0-20160225-2fc053c5"
|
proto2_20160225 "github.com/golang/protobuf/v2/internal/testprotos/legacy/proto2.v0.0.0-20160225-2fc053c5"
|
||||||
@ -29,7 +34,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func mustLoadFileDesc(b []byte, _ []int) pref.FileDescriptor {
|
func mustLoadFileDesc(b []byte, _ []int) pref.FileDescriptor {
|
||||||
fd, err := pdesc.NewFile(legacy.LoadFileDesc(b), nil)
|
zr, err := gzip.NewReader(bytes.NewReader(b))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
b, err = ioutil.ReadAll(zr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
p := new(descriptorpb.FileDescriptorProto)
|
||||||
|
err = proto.UnmarshalOptions{DiscardUnknown: true}.Unmarshal(b, p)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fd, err := pdesc.NewFile(p, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ func (ms *messageDescSet) processMessage(t reflect.Type) pref.MessageDescriptor
|
|||||||
}
|
}
|
||||||
if md, ok := mv.(messageV1); ok {
|
if md, ok := mv.(messageV1); ok {
|
||||||
b, idxs := md.Descriptor()
|
b, idxs := md.Descriptor()
|
||||||
fd := LoadFileDesc(b)
|
fd := loadFileDesc(b)
|
||||||
|
|
||||||
// Derive syntax.
|
// Derive syntax.
|
||||||
switch fd.GetSyntax() {
|
switch fd.GetSyntax() {
|
||||||
|
169
internal/legacy/parse.go
Normal file
169
internal/legacy/parse.go
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
// 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 legacy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/golang/protobuf/v2/internal/encoding/wire"
|
||||||
|
"github.com/golang/protobuf/v2/internal/fieldnum"
|
||||||
|
)
|
||||||
|
|
||||||
|
// To avoid a dependency from legacy to descriptor.proto, use a hand-written parser
|
||||||
|
// for the bits of the descriptor we need.
|
||||||
|
//
|
||||||
|
// TODO: Consider unifying this with the parser in fileinit.
|
||||||
|
|
||||||
|
type fileDescriptorProto struct {
|
||||||
|
Syntax string
|
||||||
|
Package string
|
||||||
|
EnumType []*enumDescriptorProto
|
||||||
|
MessageType []*descriptorProto
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fd fileDescriptorProto) GetSyntax() string { return fd.Syntax }
|
||||||
|
func (fd fileDescriptorProto) GetPackage() string { return fd.Package }
|
||||||
|
|
||||||
|
func parseFileDescProto(b []byte) *fileDescriptorProto {
|
||||||
|
fd := &fileDescriptorProto{}
|
||||||
|
for len(b) > 0 {
|
||||||
|
num, typ, n := wire.ConsumeTag(b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
switch typ {
|
||||||
|
case wire.BytesType:
|
||||||
|
v, n := wire.ConsumeBytes(b)
|
||||||
|
b = b[n:]
|
||||||
|
switch num {
|
||||||
|
case fieldnum.FileDescriptorProto_Syntax:
|
||||||
|
fd.Syntax = string(v)
|
||||||
|
case fieldnum.FileDescriptorProto_Package:
|
||||||
|
fd.Package = string(v)
|
||||||
|
case fieldnum.FileDescriptorProto_EnumType:
|
||||||
|
fd.EnumType = append(fd.EnumType, parseEnumDescProto(v))
|
||||||
|
case fieldnum.FileDescriptorProto_MessageType:
|
||||||
|
fd.MessageType = append(fd.MessageType, parseDescProto(v))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
n := wire.ConsumeFieldValue(num, typ, b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fd
|
||||||
|
}
|
||||||
|
|
||||||
|
type descriptorProto struct {
|
||||||
|
Name string
|
||||||
|
NestedType []*descriptorProto
|
||||||
|
EnumType []*enumDescriptorProto
|
||||||
|
}
|
||||||
|
|
||||||
|
func (md descriptorProto) GetName() string { return md.Name }
|
||||||
|
|
||||||
|
func parseDescProto(b []byte) *descriptorProto {
|
||||||
|
md := &descriptorProto{}
|
||||||
|
for len(b) > 0 {
|
||||||
|
num, typ, n := wire.ConsumeTag(b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
switch typ {
|
||||||
|
case wire.BytesType:
|
||||||
|
v, n := wire.ConsumeBytes(b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
switch num {
|
||||||
|
case fieldnum.DescriptorProto_Name:
|
||||||
|
md.Name = string(v)
|
||||||
|
case fieldnum.DescriptorProto_NestedType:
|
||||||
|
md.NestedType = append(md.NestedType, parseDescProto(v))
|
||||||
|
case fieldnum.DescriptorProto_EnumType:
|
||||||
|
md.EnumType = append(md.EnumType, parseEnumDescProto(v))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
n := wire.ConsumeFieldValue(num, typ, b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return md
|
||||||
|
}
|
||||||
|
|
||||||
|
type enumDescriptorProto struct {
|
||||||
|
Name string
|
||||||
|
Value []*enumValueDescriptorProto
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ed enumDescriptorProto) GetName() string { return ed.Name }
|
||||||
|
|
||||||
|
func parseEnumDescProto(b []byte) *enumDescriptorProto {
|
||||||
|
ed := &enumDescriptorProto{}
|
||||||
|
for len(b) > 0 {
|
||||||
|
num, typ, n := wire.ConsumeTag(b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
switch typ {
|
||||||
|
case wire.BytesType:
|
||||||
|
v, n := wire.ConsumeBytes(b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
switch num {
|
||||||
|
case fieldnum.EnumDescriptorProto_Name:
|
||||||
|
ed.Name = string(v)
|
||||||
|
case fieldnum.EnumDescriptorProto_Value:
|
||||||
|
ed.Value = append(ed.Value, parseEnumValueDescProto(v))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
n := wire.ConsumeFieldValue(num, typ, b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ed
|
||||||
|
}
|
||||||
|
|
||||||
|
type enumValueDescriptorProto struct {
|
||||||
|
Name string
|
||||||
|
Number int32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ed enumValueDescriptorProto) GetName() string { return ed.Name }
|
||||||
|
func (ed enumValueDescriptorProto) GetNumber() int32 { return ed.Number }
|
||||||
|
|
||||||
|
func parseEnumValueDescProto(b []byte) *enumValueDescriptorProto {
|
||||||
|
vd := &enumValueDescriptorProto{}
|
||||||
|
for len(b) > 0 {
|
||||||
|
num, typ, n := wire.ConsumeTag(b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
switch typ {
|
||||||
|
case wire.VarintType:
|
||||||
|
v, n := wire.ConsumeVarint(b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
switch num {
|
||||||
|
case fieldnum.EnumValueDescriptorProto_Number:
|
||||||
|
vd.Number = int32(v)
|
||||||
|
}
|
||||||
|
case wire.BytesType:
|
||||||
|
v, n := wire.ConsumeBytes(b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
switch num {
|
||||||
|
case fieldnum.EnumDescriptorProto_Name:
|
||||||
|
vd.Name = string(v)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
n := wire.ConsumeFieldValue(num, typ, b)
|
||||||
|
parseCheck(n)
|
||||||
|
b = b[n:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vd
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseCheck(n int) {
|
||||||
|
if n < 0 {
|
||||||
|
panic(wire.ParseError(n))
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user