mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-26 09:35:33 +00:00
4fddebafc0
As a goal, v2 should not depend on v1. As another step towards that end, we move all the types that used to be in the v1 protoapi package over to v2. For now, we place MessageV1, ExtensionRangeV1, and ExtensionDescV1 in runtime/protoiface since these are types that generated messages will probably have to reference forever. An alternative location could be reflect/protoreflect, but it seems unfortunate to have to dirty the namespace of that package with these types. We move ExtensionFieldV1, ExtensionFieldsV1, and ExtensionFieldsOf to internal/impl, since these are related to the implementation of a generated message. Since moving these types from v1 to v2 implies that the v1 protoapi package is useless, we update all usages of v1 protoapi in the v2 repository to point to the relevant v2 type or functionality. CL/168538 is the corresponding change to alter v1. There will be a temporary build failure as it is not possible to submit CL/168519 and CL/168538 atomically. Change-Id: Ide4025c1b6af5b7f0696f4b65b988b4d10a50f0b Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/168519 Reviewed-by: Herbie Ong <herbie@google.com>
397 lines
9.9 KiB
Go
397 lines
9.9 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 impl
|
|
|
|
import (
|
|
"reflect"
|
|
"sync"
|
|
|
|
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
|
|
piface "github.com/golang/protobuf/v2/runtime/protoiface"
|
|
)
|
|
|
|
func makeLegacyExtensionFieldsFunc(t reflect.Type) func(p *messageDataType) pref.KnownFields {
|
|
f := makeLegacyExtensionMapFunc(t)
|
|
if f == nil {
|
|
return nil
|
|
}
|
|
return func(p *messageDataType) pref.KnownFields {
|
|
if p.p.IsNil() {
|
|
return emptyExtensionFields{}
|
|
}
|
|
return legacyExtensionFields{p.mi, f(p)}
|
|
}
|
|
}
|
|
|
|
var (
|
|
extTypeA = reflect.TypeOf(map[int32]ExtensionFieldV1(nil))
|
|
extTypeB = reflect.TypeOf(ExtensionFieldsV1{})
|
|
)
|
|
|
|
func makeLegacyExtensionMapFunc(t reflect.Type) func(*messageDataType) legacyExtensionFieldsIface {
|
|
fx1, _ := t.FieldByName("XXX_extensions")
|
|
fx2, _ := t.FieldByName("XXX_InternalExtensions")
|
|
switch {
|
|
case fx1.Type == extTypeA:
|
|
fieldOffset := offsetOf(fx1)
|
|
return func(p *messageDataType) legacyExtensionFieldsIface {
|
|
v := p.p.Apply(fieldOffset).AsValueOf(fx1.Type).Interface()
|
|
return Export{}.ExtensionFieldsOf(v)
|
|
}
|
|
case fx2.Type == extTypeB:
|
|
fieldOffset := offsetOf(fx2)
|
|
return func(p *messageDataType) legacyExtensionFieldsIface {
|
|
v := p.p.Apply(fieldOffset).AsValueOf(fx2.Type).Interface()
|
|
return Export{}.ExtensionFieldsOf(v)
|
|
}
|
|
default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
type legacyExtensionFields struct {
|
|
mi *MessageType
|
|
x legacyExtensionFieldsIface
|
|
}
|
|
|
|
func (p legacyExtensionFields) Len() (n int) {
|
|
p.x.Range(func(num pref.FieldNumber, _ ExtensionFieldV1) bool {
|
|
if p.Has(pref.FieldNumber(num)) {
|
|
n++
|
|
}
|
|
return true
|
|
})
|
|
return n
|
|
}
|
|
|
|
func (p legacyExtensionFields) Has(n pref.FieldNumber) bool {
|
|
x := p.x.Get(n)
|
|
if x.Value == nil {
|
|
return false
|
|
}
|
|
t := extensionTypeFromDesc(x.Desc)
|
|
if t.Cardinality() == pref.Repeated {
|
|
return t.ValueOf(x.Value).List().Len() > 0
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (p legacyExtensionFields) Get(n pref.FieldNumber) pref.Value {
|
|
x := p.x.Get(n)
|
|
if x.Desc == nil {
|
|
return pref.Value{}
|
|
}
|
|
t := extensionTypeFromDesc(x.Desc)
|
|
if x.Value == nil {
|
|
// NOTE: x.Value is never nil for Lists since they are always populated
|
|
// during ExtensionFieldTypes.Register.
|
|
if t.Kind() == pref.MessageKind || t.Kind() == pref.GroupKind {
|
|
return pref.Value{}
|
|
}
|
|
return t.Default()
|
|
}
|
|
return t.ValueOf(x.Value)
|
|
}
|
|
|
|
func (p legacyExtensionFields) Set(n pref.FieldNumber, v pref.Value) {
|
|
x := p.x.Get(n)
|
|
if x.Desc == nil {
|
|
panic("no extension descriptor registered")
|
|
}
|
|
t := extensionTypeFromDesc(x.Desc)
|
|
x.Value = t.InterfaceOf(v)
|
|
p.x.Set(n, x)
|
|
}
|
|
|
|
func (p legacyExtensionFields) Clear(n pref.FieldNumber) {
|
|
x := p.x.Get(n)
|
|
if x.Desc == nil {
|
|
return
|
|
}
|
|
t := extensionTypeFromDesc(x.Desc)
|
|
if t.Cardinality() == pref.Repeated {
|
|
t.ValueOf(x.Value).List().Truncate(0)
|
|
return
|
|
}
|
|
x.Value = nil
|
|
p.x.Set(n, x)
|
|
}
|
|
|
|
func (p legacyExtensionFields) Range(f func(pref.FieldNumber, pref.Value) bool) {
|
|
p.x.Range(func(n pref.FieldNumber, x ExtensionFieldV1) bool {
|
|
if p.Has(n) {
|
|
return f(n, p.Get(n))
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
|
|
func (p legacyExtensionFields) NewMessage(n pref.FieldNumber) pref.Message {
|
|
x := p.x.Get(n)
|
|
if x.Desc == nil {
|
|
panic("no extension descriptor registered")
|
|
}
|
|
xt := extensionTypeFromDesc(x.Desc)
|
|
return xt.New().Message()
|
|
}
|
|
|
|
func (p legacyExtensionFields) ExtensionTypes() pref.ExtensionFieldTypes {
|
|
return legacyExtensionTypes(p)
|
|
}
|
|
|
|
type legacyExtensionTypes legacyExtensionFields
|
|
|
|
func (p legacyExtensionTypes) Len() (n int) {
|
|
p.x.Range(func(_ pref.FieldNumber, x ExtensionFieldV1) bool {
|
|
if x.Desc != nil {
|
|
n++
|
|
}
|
|
return true
|
|
})
|
|
return n
|
|
}
|
|
|
|
func (p legacyExtensionTypes) Register(t pref.ExtensionType) {
|
|
if p.mi.PBType.FullName() != t.ExtendedType().FullName() {
|
|
panic("extended type mismatch")
|
|
}
|
|
if !p.mi.PBType.ExtensionRanges().Has(t.Number()) {
|
|
panic("invalid extension field number")
|
|
}
|
|
x := p.x.Get(t.Number())
|
|
if x.Desc != nil {
|
|
panic("extension descriptor already registered")
|
|
}
|
|
x.Desc = extensionDescFromType(t)
|
|
if t.Cardinality() == pref.Repeated {
|
|
// If the field is repeated, initialize the entry with an empty list
|
|
// so that future Get operations can return a mutable and concrete list.
|
|
x.Value = t.InterfaceOf(t.New())
|
|
}
|
|
p.x.Set(t.Number(), x)
|
|
}
|
|
|
|
func (p legacyExtensionTypes) Remove(t pref.ExtensionType) {
|
|
if !p.mi.PBType.ExtensionRanges().Has(t.Number()) {
|
|
return
|
|
}
|
|
x := p.x.Get(t.Number())
|
|
if t.Cardinality() == pref.Repeated {
|
|
// Treat an empty repeated field as unpopulated.
|
|
v := reflect.ValueOf(x.Value)
|
|
if x.Value == nil || v.IsNil() || v.Elem().Len() == 0 {
|
|
x.Value = nil
|
|
}
|
|
}
|
|
if x.Value != nil {
|
|
panic("value for extension descriptor still populated")
|
|
}
|
|
x.Desc = nil
|
|
if len(x.Raw) == 0 {
|
|
p.x.Clear(t.Number())
|
|
} else {
|
|
p.x.Set(t.Number(), x)
|
|
}
|
|
}
|
|
|
|
func (p legacyExtensionTypes) ByNumber(n pref.FieldNumber) pref.ExtensionType {
|
|
x := p.x.Get(n)
|
|
if x.Desc != nil {
|
|
return extensionTypeFromDesc(x.Desc)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p legacyExtensionTypes) ByName(s pref.FullName) (t pref.ExtensionType) {
|
|
p.x.Range(func(_ pref.FieldNumber, x ExtensionFieldV1) bool {
|
|
if x.Desc != nil && x.Desc.Name == string(s) {
|
|
t = extensionTypeFromDesc(x.Desc)
|
|
return false
|
|
}
|
|
return true
|
|
})
|
|
return t
|
|
}
|
|
|
|
func (p legacyExtensionTypes) Range(f func(pref.ExtensionType) bool) {
|
|
p.x.Range(func(_ pref.FieldNumber, x ExtensionFieldV1) bool {
|
|
if x.Desc != nil {
|
|
if !f(extensionTypeFromDesc(x.Desc)) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
|
|
func extensionDescFromType(typ pref.ExtensionType) *piface.ExtensionDescV1 {
|
|
if xt, ok := typ.(interface {
|
|
ProtoLegacyExtensionDesc() *piface.ExtensionDescV1
|
|
}); ok {
|
|
if desc := xt.ProtoLegacyExtensionDesc(); desc != nil {
|
|
return desc
|
|
}
|
|
}
|
|
return legacyWrapper.ExtensionDescFromType(typ)
|
|
}
|
|
|
|
func extensionTypeFromDesc(desc *piface.ExtensionDescV1) pref.ExtensionType {
|
|
if desc.Type != nil {
|
|
return desc.Type
|
|
}
|
|
return legacyWrapper.ExtensionTypeFromDesc(desc)
|
|
}
|
|
|
|
type legacyExtensionFieldsIface = interface {
|
|
Len() int
|
|
Has(pref.FieldNumber) bool
|
|
Get(pref.FieldNumber) ExtensionFieldV1
|
|
Set(pref.FieldNumber, ExtensionFieldV1)
|
|
Clear(pref.FieldNumber)
|
|
Range(f func(pref.FieldNumber, ExtensionFieldV1) bool)
|
|
|
|
// HasInit and Locker are used by v1 GetExtension to provide
|
|
// an artificial degree of concurrent safety.
|
|
HasInit() bool
|
|
sync.Locker
|
|
}
|
|
|
|
type ExtensionFieldV1 struct {
|
|
// TODO: Unexport these fields when v1 no longer interacts with the
|
|
// extension data structures directly.
|
|
|
|
// When an extension is stored in a message using SetExtension
|
|
// only desc and value are set. When the message is marshaled
|
|
// Raw will be set to the encoded form of the message.
|
|
//
|
|
// When a message is unmarshaled and contains extensions, each
|
|
// extension will have only Raw set. When such an extension is
|
|
// accessed using GetExtension (or GetExtensions) desc and value
|
|
// will be set.
|
|
Desc *piface.ExtensionDescV1 // TODO: switch to protoreflect.ExtensionType
|
|
|
|
// Value is a concrete value for the extension field. Let the type of
|
|
// Desc.ExtensionType be the "API type" and the type of Value be the
|
|
// "storage type". The API type and storage type are the same except:
|
|
// * for scalars (except []byte), where the API type uses *T,
|
|
// while the storage type uses T.
|
|
// * for repeated fields, where the API type uses []T,
|
|
// while the storage type uses *[]T.
|
|
//
|
|
// The reason for the divergence is so that the storage type more naturally
|
|
// matches what is expected of when retrieving the values through the
|
|
// protobuf reflection APIs.
|
|
//
|
|
// The Value may only be populated if Desc is also populated.
|
|
Value interface{} // TODO: switch to protoreflect.Value
|
|
|
|
// Raw is the raw encoded bytes for the extension field.
|
|
// It is possible for Raw to be populated irrespective of whether the
|
|
// other fields are populated.
|
|
Raw []byte // TODO: switch to protoreflect.RawFields
|
|
}
|
|
|
|
type ExtensionFieldsV1 legacyExtensionSyncMap
|
|
type legacyExtensionSyncMap struct {
|
|
p *struct {
|
|
mu sync.Mutex
|
|
m legacyExtensionMap
|
|
}
|
|
}
|
|
|
|
func (m legacyExtensionSyncMap) Len() int {
|
|
if m.p == nil {
|
|
return 0
|
|
}
|
|
return m.p.m.Len()
|
|
}
|
|
func (m legacyExtensionSyncMap) Has(n pref.FieldNumber) bool {
|
|
if m.p == nil {
|
|
return false
|
|
}
|
|
return m.p.m.Has(n)
|
|
}
|
|
func (m legacyExtensionSyncMap) Get(n pref.FieldNumber) ExtensionFieldV1 {
|
|
if m.p == nil {
|
|
return ExtensionFieldV1{}
|
|
}
|
|
return m.p.m.Get(n)
|
|
}
|
|
func (m *legacyExtensionSyncMap) Set(n pref.FieldNumber, x ExtensionFieldV1) {
|
|
if m.p == nil {
|
|
m.p = new(struct {
|
|
mu sync.Mutex
|
|
m legacyExtensionMap
|
|
})
|
|
}
|
|
m.p.m.Set(n, x)
|
|
}
|
|
func (m legacyExtensionSyncMap) Clear(n pref.FieldNumber) {
|
|
if m.p == nil {
|
|
return
|
|
}
|
|
m.p.m.Clear(n)
|
|
}
|
|
func (m legacyExtensionSyncMap) Range(f func(pref.FieldNumber, ExtensionFieldV1) bool) {
|
|
if m.p == nil {
|
|
return
|
|
}
|
|
m.p.m.Range(f)
|
|
}
|
|
|
|
func (m legacyExtensionSyncMap) HasInit() bool {
|
|
return m.p != nil
|
|
}
|
|
func (m legacyExtensionSyncMap) Lock() {
|
|
m.p.mu.Lock()
|
|
}
|
|
func (m legacyExtensionSyncMap) Unlock() {
|
|
m.p.mu.Unlock()
|
|
}
|
|
|
|
type legacyExtensionMap map[int32]ExtensionFieldV1
|
|
|
|
func (m legacyExtensionMap) Len() int {
|
|
return len(m)
|
|
}
|
|
func (m legacyExtensionMap) Has(n pref.FieldNumber) bool {
|
|
_, ok := m[int32(n)]
|
|
return ok
|
|
}
|
|
func (m legacyExtensionMap) Get(n pref.FieldNumber) ExtensionFieldV1 {
|
|
return m[int32(n)]
|
|
}
|
|
func (m *legacyExtensionMap) Set(n pref.FieldNumber, x ExtensionFieldV1) {
|
|
if *m == nil {
|
|
*m = make(map[int32]ExtensionFieldV1)
|
|
}
|
|
(*m)[int32(n)] = x
|
|
}
|
|
func (m *legacyExtensionMap) Clear(n pref.FieldNumber) {
|
|
delete(*m, int32(n))
|
|
}
|
|
func (m legacyExtensionMap) Range(f func(pref.FieldNumber, ExtensionFieldV1) bool) {
|
|
for n, x := range m {
|
|
if !f(pref.FieldNumber(n), x) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
var legacyExtensionLock sync.Mutex
|
|
|
|
func (m legacyExtensionMap) HasInit() bool {
|
|
return m != nil
|
|
}
|
|
func (m legacyExtensionMap) Lock() {
|
|
if !m.HasInit() {
|
|
panic("cannot lock an uninitialized map")
|
|
}
|
|
legacyExtensionLock.Lock()
|
|
}
|
|
func (m legacyExtensionMap) Unlock() {
|
|
legacyExtensionLock.Unlock()
|
|
}
|