mirror of
https://github.com/protocolbuffers/protobuf-go.git
synced 2025-01-30 21:32:43 +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>
216 lines
5.1 KiB
Go
216 lines
5.1 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 (
|
|
"container/list"
|
|
"reflect"
|
|
"sort"
|
|
|
|
"github.com/golang/protobuf/v2/internal/encoding/wire"
|
|
pref "github.com/golang/protobuf/v2/reflect/protoreflect"
|
|
)
|
|
|
|
var bytesType = reflect.TypeOf([]byte(nil))
|
|
|
|
func makeLegacyUnknownFieldsFunc(t reflect.Type) func(p *messageDataType) pref.UnknownFields {
|
|
fu, ok := t.FieldByName("XXX_unrecognized")
|
|
if !ok || fu.Type != bytesType {
|
|
return nil
|
|
}
|
|
fieldOffset := offsetOf(fu)
|
|
unkFunc := func(p *messageDataType) pref.UnknownFields {
|
|
if p.p.IsNil() {
|
|
return emptyUnknownFields{}
|
|
}
|
|
rv := p.p.Apply(fieldOffset).AsValueOf(bytesType)
|
|
return (*legacyUnknownBytes)(rv.Interface().(*[]byte))
|
|
}
|
|
extFunc := makeLegacyExtensionMapFunc(t)
|
|
if extFunc != nil {
|
|
return func(p *messageDataType) pref.UnknownFields {
|
|
if p.p.IsNil() {
|
|
return emptyUnknownFields{}
|
|
}
|
|
return &legacyUnknownBytesAndExtensionMap{
|
|
unkFunc(p), extFunc(p), p.mi.PBType.ExtensionRanges(),
|
|
}
|
|
}
|
|
}
|
|
return unkFunc
|
|
}
|
|
|
|
// legacyUnknownBytesAndExtensionMap is a wrapper around both XXX_unrecognized
|
|
// and also the extension field map.
|
|
type legacyUnknownBytesAndExtensionMap struct {
|
|
u pref.UnknownFields
|
|
x legacyExtensionFieldsIface
|
|
r pref.FieldRanges
|
|
}
|
|
|
|
func (fs *legacyUnknownBytesAndExtensionMap) Len() int {
|
|
n := fs.u.Len()
|
|
fs.x.Range(func(_ pref.FieldNumber, x ExtensionFieldV1) bool {
|
|
if len(x.Raw) > 0 {
|
|
n++
|
|
}
|
|
return true
|
|
})
|
|
return n
|
|
}
|
|
|
|
func (fs *legacyUnknownBytesAndExtensionMap) Get(num pref.FieldNumber) (raw pref.RawFields) {
|
|
if fs.r.Has(num) {
|
|
return fs.x.Get(num).Raw
|
|
}
|
|
return fs.u.Get(num)
|
|
}
|
|
|
|
func (fs *legacyUnknownBytesAndExtensionMap) Set(num pref.FieldNumber, raw pref.RawFields) {
|
|
if fs.r.Has(num) {
|
|
x := fs.x.Get(num)
|
|
x.Raw = raw
|
|
fs.x.Set(num, x)
|
|
return
|
|
}
|
|
fs.u.Set(num, raw)
|
|
}
|
|
|
|
func (fs *legacyUnknownBytesAndExtensionMap) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
|
|
// Range over unknown fields not in the extension range.
|
|
// Create a closure around f to capture whether iteration terminated early.
|
|
var stop bool
|
|
fs.u.Range(func(n pref.FieldNumber, b pref.RawFields) bool {
|
|
stop = stop || !f(n, b)
|
|
return !stop
|
|
})
|
|
if stop {
|
|
return
|
|
}
|
|
|
|
// Range over unknown fields in the extension range in ascending order
|
|
// to ensure protoreflect.UnknownFields.Range remains deterministic.
|
|
type entry struct {
|
|
num pref.FieldNumber
|
|
raw pref.RawFields
|
|
}
|
|
var xs []entry
|
|
fs.x.Range(func(n pref.FieldNumber, x ExtensionFieldV1) bool {
|
|
if len(x.Raw) > 0 {
|
|
xs = append(xs, entry{n, x.Raw})
|
|
}
|
|
return true
|
|
})
|
|
sort.Slice(xs, func(i, j int) bool { return xs[i].num < xs[j].num })
|
|
for _, x := range xs {
|
|
if !f(x.num, x.raw) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (fs *legacyUnknownBytesAndExtensionMap) IsSupported() bool {
|
|
return true
|
|
}
|
|
|
|
// legacyUnknownBytes is a wrapper around XXX_unrecognized that implements
|
|
// the protoreflect.UnknownFields interface. This is challenging since we are
|
|
// limited to a []byte, so we do not have much flexibility in the choice
|
|
// of data structure that would have been ideal.
|
|
type legacyUnknownBytes []byte
|
|
|
|
func (fs *legacyUnknownBytes) Len() int {
|
|
// Runtime complexity: O(n)
|
|
b := *fs
|
|
m := map[pref.FieldNumber]bool{}
|
|
for len(b) > 0 {
|
|
num, _, n := wire.ConsumeField(b)
|
|
m[num] = true
|
|
b = b[n:]
|
|
}
|
|
return len(m)
|
|
}
|
|
|
|
func (fs *legacyUnknownBytes) Get(num pref.FieldNumber) (raw pref.RawFields) {
|
|
// Runtime complexity: O(n)
|
|
b := *fs
|
|
for len(b) > 0 {
|
|
num2, _, n := wire.ConsumeField(b)
|
|
if num == num2 {
|
|
raw = append(raw, b[:n]...)
|
|
}
|
|
b = b[n:]
|
|
}
|
|
return raw
|
|
}
|
|
|
|
func (fs *legacyUnknownBytes) Set(num pref.FieldNumber, raw pref.RawFields) {
|
|
num2, _, _ := wire.ConsumeTag(raw)
|
|
if len(raw) > 0 && (!raw.IsValid() || num != num2) {
|
|
panic("invalid raw fields")
|
|
}
|
|
|
|
// Remove all current fields of num.
|
|
// Runtime complexity: O(n)
|
|
b := *fs
|
|
out := (*fs)[:0]
|
|
for len(b) > 0 {
|
|
num2, _, n := wire.ConsumeField(b)
|
|
if num != num2 {
|
|
out = append(out, b[:n]...)
|
|
}
|
|
b = b[n:]
|
|
}
|
|
*fs = out
|
|
|
|
// Append new fields of num.
|
|
*fs = append(*fs, raw...)
|
|
}
|
|
|
|
func (fs *legacyUnknownBytes) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
|
|
type entry struct {
|
|
num pref.FieldNumber
|
|
raw pref.RawFields
|
|
}
|
|
|
|
// Collect up a list of all the raw fields.
|
|
// We preserve the order such that the latest encountered fields
|
|
// are presented at the end.
|
|
//
|
|
// Runtime complexity: O(n)
|
|
b := *fs
|
|
l := list.New()
|
|
m := map[pref.FieldNumber]*list.Element{}
|
|
for len(b) > 0 {
|
|
num, _, n := wire.ConsumeField(b)
|
|
if e, ok := m[num]; ok {
|
|
x := e.Value.(*entry)
|
|
x.raw = append(x.raw, b[:n]...)
|
|
l.MoveToBack(e)
|
|
} else {
|
|
x := &entry{num: num}
|
|
x.raw = append(x.raw, b[:n]...)
|
|
m[num] = l.PushBack(x)
|
|
}
|
|
b = b[n:]
|
|
}
|
|
|
|
// Iterate over all the raw fields.
|
|
// This ranges over a snapshot of the current state such that mutations
|
|
// while ranging are not observable.
|
|
//
|
|
// Runtime complexity: O(n)
|
|
for e := l.Front(); e != nil; e = e.Next() {
|
|
x := e.Value.(*entry)
|
|
if !f(x.num, x.raw) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
func (fs *legacyUnknownBytes) IsSupported() bool {
|
|
return true
|
|
}
|