mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-26 00:35:25 +00:00
4ec39c7663
Add a method that provides efficiently querying for which member field in a oneof is actually set. This is useful when dealing with oneofs with many member fields. Change-Id: I918b566c432f8bdd24dcecbb5501d231ffefef29 Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/170580 Reviewed-by: Damien Neil <dneil@google.com>
401 lines
10 KiB
Go
401 lines
10 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) WhichOneof(pref.Name) pref.FieldNumber {
|
|
return 0
|
|
}
|
|
|
|
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()
|
|
}
|