blob: 9ab617bd0abf6f979d2d264e688ff55cc08a5e85 [file] [log] [blame]
Joe Tsaie2afdc22018-10-25 14:06:56 -07001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package impl
6
7import (
Joe Tsai2d5a1692018-10-29 02:10:42 -07008 "container/list"
Joe Tsaie2afdc22018-10-25 14:06:56 -07009 "reflect"
Joe Tsai95b02902018-10-31 18:23:42 -070010 "sort"
Joe Tsaie2afdc22018-10-25 14:06:56 -070011
Joe Tsaie2afdc22018-10-25 14:06:56 -070012 "github.com/golang/protobuf/v2/internal/encoding/wire"
13 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
14)
15
Joe Tsai95b02902018-10-31 18:23:42 -070016func makeLegacyUnknownFieldsFunc(t reflect.Type) func(p *messageDataType) pref.UnknownFields {
Joe Tsaie2afdc22018-10-25 14:06:56 -070017 fu, ok := t.FieldByName("XXX_unrecognized")
18 if !ok || fu.Type != bytesType {
19 return nil
20 }
Joe Tsaie2afdc22018-10-25 14:06:56 -070021 fieldOffset := offsetOf(fu)
Joe Tsai95b02902018-10-31 18:23:42 -070022 unkFunc := func(p *messageDataType) pref.UnknownFields {
Joe Tsaie2afdc22018-10-25 14:06:56 -070023 rv := p.p.apply(fieldOffset).asType(bytesType)
24 return (*legacyUnknownBytes)(rv.Interface().(*[]byte))
25 }
Joe Tsai95b02902018-10-31 18:23:42 -070026 extFunc := makeLegacyExtensionMapFunc(t)
27 if extFunc != nil {
28 return func(p *messageDataType) pref.UnknownFields {
29 return &legacyUnknownBytesAndExtensionMap{
30 unkFunc(p), extFunc(p), p.mi.Desc.ExtensionRanges(),
31 }
32 }
33 }
34 return unkFunc
35}
36
37// legacyUnknownBytesAndExtensionMap is a wrapper around both XXX_unrecognized
38// and also the extension field map.
39type legacyUnknownBytesAndExtensionMap struct {
40 u pref.UnknownFields
41 x legacyExtensionIface
42 r pref.FieldRanges
43}
44
45func (fs *legacyUnknownBytesAndExtensionMap) Len() int {
46 n := fs.u.Len()
47 fs.x.Range(func(_ pref.FieldNumber, x legacyExtensionEntry) bool {
48 if len(x.raw) > 0 {
49 n++
50 }
51 return true
52 })
53 return n
54}
55
56func (fs *legacyUnknownBytesAndExtensionMap) Get(num pref.FieldNumber) (raw pref.RawFields) {
57 if fs.r.Has(num) {
58 return fs.x.Get(num).raw
59 }
60 return fs.u.Get(num)
61}
62
63func (fs *legacyUnknownBytesAndExtensionMap) Set(num pref.FieldNumber, raw pref.RawFields) {
64 if fs.r.Has(num) {
65 x := fs.x.Get(num)
66 x.raw = raw
67 fs.x.Set(num, x)
68 return
69 }
70 fs.u.Set(num, raw)
71}
72
73func (fs *legacyUnknownBytesAndExtensionMap) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
74 // Range over unknown fields not in the extension range.
75 // Create a closure around f to capture whether iteration terminated early.
76 var stop bool
77 fs.u.Range(func(n pref.FieldNumber, b pref.RawFields) bool {
78 stop = stop || !f(n, b)
79 return !stop
80 })
81 if stop {
82 return
83 }
84
85 // Range over unknown fields in the extension range in ascending order
86 // to ensure protoreflect.UnknownFields.Range remains deterministic.
87 type entry struct {
88 num pref.FieldNumber
89 raw pref.RawFields
90 }
91 var xs []entry
92 fs.x.Range(func(n pref.FieldNumber, x legacyExtensionEntry) bool {
93 if len(x.raw) > 0 {
94 xs = append(xs, entry{n, x.raw})
95 }
96 return true
97 })
98 sort.Slice(xs, func(i, j int) bool { return xs[i].num < xs[j].num })
99 for _, x := range xs {
100 if !f(x.num, x.raw) {
101 return
102 }
103 }
104}
105
106func (fs *legacyUnknownBytesAndExtensionMap) IsSupported() bool {
107 return true
Joe Tsaie2afdc22018-10-25 14:06:56 -0700108}
109
110// legacyUnknownBytes is a wrapper around XXX_unrecognized that implements
111// the protoreflect.UnknownFields interface. This is challenging since we are
112// limited to a []byte, so we do not have much flexibility in the choice
113// of data structure that would have been ideal.
114type legacyUnknownBytes []byte
115
116func (fs *legacyUnknownBytes) Len() int {
117 // Runtime complexity: O(n)
118 b := *fs
119 m := map[pref.FieldNumber]bool{}
120 for len(b) > 0 {
121 num, _, n := wire.ConsumeField(b)
122 m[num] = true
123 b = b[n:]
124 }
125 return len(m)
126}
127
128func (fs *legacyUnknownBytes) Get(num pref.FieldNumber) (raw pref.RawFields) {
129 // Runtime complexity: O(n)
130 b := *fs
131 for len(b) > 0 {
132 num2, _, n := wire.ConsumeField(b)
133 if num == num2 {
134 raw = append(raw, b[:n]...)
135 }
136 b = b[n:]
137 }
138 return raw
139}
140
141func (fs *legacyUnknownBytes) Set(num pref.FieldNumber, raw pref.RawFields) {
142 num2, _, _ := wire.ConsumeTag(raw)
143 if len(raw) > 0 && (!raw.IsValid() || num != num2) {
144 panic("invalid raw fields")
145 }
146
147 // Remove all current fields of num.
148 // Runtime complexity: O(n)
149 b := *fs
150 out := (*fs)[:0]
151 for len(b) > 0 {
152 num2, _, n := wire.ConsumeField(b)
153 if num != num2 {
154 out = append(out, b[:n]...)
155 }
156 b = b[n:]
157 }
158 *fs = out
159
160 // Append new fields of num.
161 *fs = append(*fs, raw...)
162}
163
164func (fs *legacyUnknownBytes) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
165 type entry struct {
166 num pref.FieldNumber
167 raw pref.RawFields
168 }
Joe Tsaie2afdc22018-10-25 14:06:56 -0700169
170 // Collect up a list of all the raw fields.
171 // We preserve the order such that the latest encountered fields
172 // are presented at the end.
173 //
174 // Runtime complexity: O(n)
175 b := *fs
Joe Tsai2d5a1692018-10-29 02:10:42 -0700176 l := list.New()
177 m := map[pref.FieldNumber]*list.Element{}
Joe Tsaie2afdc22018-10-25 14:06:56 -0700178 for len(b) > 0 {
179 num, _, n := wire.ConsumeField(b)
Joe Tsai2d5a1692018-10-29 02:10:42 -0700180 if e, ok := m[num]; ok {
181 x := e.Value.(*entry)
182 x.raw = append(x.raw, b[:n]...)
183 l.MoveToBack(e)
184 } else {
185 x := &entry{num: num}
186 x.raw = append(x.raw, b[:n]...)
187 m[num] = l.PushBack(x)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700188 }
Joe Tsaie2afdc22018-10-25 14:06:56 -0700189 b = b[n:]
190 }
191
192 // Iterate over all the raw fields.
193 // This ranges over a snapshot of the current state such that mutations
194 // while ranging are not observable.
195 //
196 // Runtime complexity: O(n)
Joe Tsai2d5a1692018-10-29 02:10:42 -0700197 for e := l.Front(); e != nil; e = e.Next() {
198 x := e.Value.(*entry)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700199 if !f(x.num, x.raw) {
200 return
201 }
202 }
203}
204
205func (fs *legacyUnknownBytes) IsSupported() bool {
206 return true
207}