mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-07 12:56:47 +00:00
c14e7899f9
Extensions should be checked based on ContainingMessage, rather than the Parent. Add tests to ensure this works. Change-Id: Iaf257f65197fb8d332039bc77a192753f8c4159f Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/221426 Reviewed-by: Damien Neil <dneil@google.com>
261 lines
6.9 KiB
Go
261 lines
6.9 KiB
Go
// Copyright 2020 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 protocmp
|
|
|
|
import (
|
|
"reflect"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
"google.golang.org/protobuf/reflect/protoreflect"
|
|
"google.golang.org/protobuf/runtime/protoiface"
|
|
)
|
|
|
|
func reflectValueOf(v interface{}) protoreflect.Value {
|
|
switch v := v.(type) {
|
|
case Enum:
|
|
return protoreflect.ValueOfEnum(v.Number())
|
|
case Message:
|
|
return protoreflect.ValueOfMessage(v.ProtoReflect())
|
|
case []byte:
|
|
return protoreflect.ValueOfBytes(v) // avoid overlap with reflect.Slice check below
|
|
default:
|
|
switch rv := reflect.ValueOf(v); {
|
|
case rv.Kind() == reflect.Slice:
|
|
return protoreflect.ValueOfList(reflectList{rv})
|
|
case rv.Kind() == reflect.Map:
|
|
return protoreflect.ValueOfMap(reflectMap{rv})
|
|
default:
|
|
return protoreflect.ValueOf(v)
|
|
}
|
|
}
|
|
}
|
|
|
|
type reflectMessage Message
|
|
|
|
func (m reflectMessage) stringKey(fd protoreflect.FieldDescriptor) string {
|
|
if m.Descriptor() != fd.ContainingMessage() {
|
|
panic("mismatching containing message")
|
|
}
|
|
if fd.IsExtension() {
|
|
return string("[" + fd.FullName() + "]")
|
|
}
|
|
return string(fd.Name())
|
|
}
|
|
|
|
func (m reflectMessage) Descriptor() protoreflect.MessageDescriptor {
|
|
return (Message)(m).Descriptor()
|
|
}
|
|
func (m reflectMessage) Type() protoreflect.MessageType {
|
|
return reflectMessageType{m.Descriptor()}
|
|
}
|
|
func (m reflectMessage) New() protoreflect.Message {
|
|
return m.Type().New()
|
|
}
|
|
func (m reflectMessage) Interface() protoreflect.ProtoMessage {
|
|
return Message(m)
|
|
}
|
|
func (m reflectMessage) Range(f func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool) {
|
|
// Range over populated known fields.
|
|
fds := m.Descriptor().Fields()
|
|
for i := 0; i < fds.Len(); i++ {
|
|
fd := fds.Get(i)
|
|
if m.Has(fd) && !f(fd, m.Get(fd)) {
|
|
return
|
|
}
|
|
}
|
|
|
|
// Range over populated extension fields.
|
|
for _, xd := range m[messageTypeKey].(messageType).xds {
|
|
if m.Has(xd) && !f(xd, m.Get(xd)) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
func (m reflectMessage) Has(fd protoreflect.FieldDescriptor) bool {
|
|
_, ok := m[m.stringKey(fd)]
|
|
return ok
|
|
}
|
|
func (m reflectMessage) Clear(protoreflect.FieldDescriptor) {
|
|
panic("invalid mutation of read-only message")
|
|
}
|
|
func (m reflectMessage) Get(fd protoreflect.FieldDescriptor) protoreflect.Value {
|
|
v, ok := m[m.stringKey(fd)]
|
|
if !ok {
|
|
switch {
|
|
case fd.IsList():
|
|
return protoreflect.ValueOfList(reflectList{})
|
|
case fd.IsMap():
|
|
return protoreflect.ValueOfMap(reflectMap{})
|
|
case fd.Message() != nil:
|
|
return protoreflect.ValueOfMessage(reflectMessage{
|
|
messageTypeKey: messageType{md: m.Descriptor()},
|
|
})
|
|
default:
|
|
return fd.Default()
|
|
}
|
|
}
|
|
|
|
// The transformation may leave Any messages in structured form.
|
|
// If so, convert them back to a raw-encoded form.
|
|
if fd.FullName() == "google.protobuf.Any.value" {
|
|
if m, ok := v.(Message); ok {
|
|
b, err := proto.MarshalOptions{Deterministic: true}.Marshal(m)
|
|
if err != nil {
|
|
panic("BUG: " + err.Error())
|
|
}
|
|
return protoreflect.ValueOfBytes(b)
|
|
}
|
|
}
|
|
|
|
return reflectValueOf(v)
|
|
}
|
|
func (m reflectMessage) Set(protoreflect.FieldDescriptor, protoreflect.Value) {
|
|
panic("invalid mutation of read-only message")
|
|
}
|
|
func (m reflectMessage) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value {
|
|
panic("invalid mutation of read-only message")
|
|
}
|
|
func (m reflectMessage) NewField(protoreflect.FieldDescriptor) protoreflect.Value {
|
|
panic("not implemented")
|
|
}
|
|
func (m reflectMessage) WhichOneof(od protoreflect.OneofDescriptor) protoreflect.FieldDescriptor {
|
|
if m.Descriptor().Oneofs().ByName(od.Name()) != od {
|
|
panic("oneof descriptor does not belong to this message")
|
|
}
|
|
fds := od.Fields()
|
|
for i := 0; i < fds.Len(); i++ {
|
|
fd := fds.Get(i)
|
|
if _, ok := m[m.stringKey(fd)]; ok {
|
|
return fd
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
func (m reflectMessage) GetUnknown() protoreflect.RawFields {
|
|
var nums []protoreflect.FieldNumber
|
|
for k := range m {
|
|
if len(strings.Trim(k, "0123456789")) == 0 {
|
|
n, _ := strconv.ParseUint(k, 10, 32)
|
|
nums = append(nums, protoreflect.FieldNumber(n))
|
|
}
|
|
}
|
|
sort.Slice(nums, func(i, j int) bool { return nums[i] < nums[j] })
|
|
|
|
var raw protoreflect.RawFields
|
|
for _, num := range nums {
|
|
b, _ := m[strconv.FormatUint(uint64(num), 10)].(protoreflect.RawFields)
|
|
raw = append(raw, b...)
|
|
}
|
|
return raw
|
|
}
|
|
func (m reflectMessage) SetUnknown(protoreflect.RawFields) {
|
|
panic("invalid mutation of read-only message")
|
|
}
|
|
func (m reflectMessage) IsValid() bool {
|
|
invalid, _ := m[messageInvalidKey].(bool)
|
|
return !invalid
|
|
}
|
|
func (m reflectMessage) ProtoMethods() *protoiface.Methods {
|
|
return nil
|
|
}
|
|
|
|
type reflectMessageType struct{ protoreflect.MessageDescriptor }
|
|
|
|
func (t reflectMessageType) New() protoreflect.Message {
|
|
panic("not implemented")
|
|
}
|
|
func (t reflectMessageType) Zero() protoreflect.Message {
|
|
panic("not implemented")
|
|
}
|
|
func (t reflectMessageType) Descriptor() protoreflect.MessageDescriptor {
|
|
return t.MessageDescriptor
|
|
}
|
|
|
|
type reflectList struct{ v reflect.Value }
|
|
|
|
func (ls reflectList) Len() int {
|
|
if !ls.IsValid() {
|
|
return 0
|
|
}
|
|
return ls.v.Len()
|
|
}
|
|
func (ls reflectList) Get(i int) protoreflect.Value {
|
|
return reflectValueOf(ls.v.Index(i).Interface())
|
|
}
|
|
func (ls reflectList) Set(int, protoreflect.Value) {
|
|
panic("invalid mutation of read-only list")
|
|
}
|
|
func (ls reflectList) Append(protoreflect.Value) {
|
|
panic("invalid mutation of read-only list")
|
|
}
|
|
func (ls reflectList) AppendMutable() protoreflect.Value {
|
|
panic("invalid mutation of read-only list")
|
|
}
|
|
func (ls reflectList) Truncate(int) {
|
|
panic("invalid mutation of read-only list")
|
|
}
|
|
func (ls reflectList) NewElement() protoreflect.Value {
|
|
panic("not implemented")
|
|
}
|
|
func (ls reflectList) IsValid() bool {
|
|
return ls.v.IsValid()
|
|
}
|
|
|
|
type reflectMap struct{ v reflect.Value }
|
|
|
|
func (ms reflectMap) Len() int {
|
|
if !ms.IsValid() {
|
|
return 0
|
|
}
|
|
return ms.v.Len()
|
|
}
|
|
func (ms reflectMap) Range(f func(protoreflect.MapKey, protoreflect.Value) bool) {
|
|
if !ms.IsValid() {
|
|
return
|
|
}
|
|
ks := ms.v.MapKeys()
|
|
for _, k := range ks {
|
|
pk := reflectValueOf(k.Interface()).MapKey()
|
|
pv := reflectValueOf(ms.v.MapIndex(k).Interface())
|
|
if !f(pk, pv) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
func (ms reflectMap) Has(k protoreflect.MapKey) bool {
|
|
if !ms.IsValid() {
|
|
return false
|
|
}
|
|
return ms.v.MapIndex(reflect.ValueOf(k.Interface())).IsValid()
|
|
}
|
|
func (ms reflectMap) Clear(protoreflect.MapKey) {
|
|
panic("invalid mutation of read-only list")
|
|
}
|
|
func (ms reflectMap) Get(k protoreflect.MapKey) protoreflect.Value {
|
|
if !ms.IsValid() {
|
|
return protoreflect.Value{}
|
|
}
|
|
v := ms.v.MapIndex(reflect.ValueOf(k.Interface()))
|
|
if !v.IsValid() {
|
|
return protoreflect.Value{}
|
|
}
|
|
return reflectValueOf(v.Interface())
|
|
}
|
|
func (ms reflectMap) Set(protoreflect.MapKey, protoreflect.Value) {
|
|
panic("invalid mutation of read-only list")
|
|
}
|
|
func (ms reflectMap) Mutable(k protoreflect.MapKey) protoreflect.Value {
|
|
panic("invalid mutation of read-only list")
|
|
}
|
|
func (ms reflectMap) NewValue() protoreflect.Value {
|
|
panic("not implemented")
|
|
}
|
|
func (ms reflectMap) IsValid() bool {
|
|
return ms.v.IsValid()
|
|
}
|