blob: 759bab9192ac1f94dfa7b5941e4c5745f67c580a [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 Tsai88bc5a72018-11-05 11:42:22 -080016var bytesType = reflect.TypeOf([]byte(nil))
17
Joe Tsai95b02902018-10-31 18:23:42 -070018func makeLegacyUnknownFieldsFunc(t reflect.Type) func(p *messageDataType) pref.UnknownFields {
Joe Tsaie2afdc22018-10-25 14:06:56 -070019 fu, ok := t.FieldByName("XXX_unrecognized")
20 if !ok || fu.Type != bytesType {
21 return nil
22 }
Joe Tsaie2afdc22018-10-25 14:06:56 -070023 fieldOffset := offsetOf(fu)
Joe Tsai95b02902018-10-31 18:23:42 -070024 unkFunc := func(p *messageDataType) pref.UnknownFields {
Joe Tsai6cf80c42018-12-01 04:57:09 -080025 if p.p.IsNil() {
26 return emptyUnknownFields{}
27 }
28 rv := p.p.Apply(fieldOffset).AsValueOf(bytesType)
Joe Tsaie2afdc22018-10-25 14:06:56 -070029 return (*legacyUnknownBytes)(rv.Interface().(*[]byte))
30 }
Joe Tsai95b02902018-10-31 18:23:42 -070031 extFunc := makeLegacyExtensionMapFunc(t)
32 if extFunc != nil {
33 return func(p *messageDataType) pref.UnknownFields {
Joe Tsai6cf80c42018-12-01 04:57:09 -080034 if p.p.IsNil() {
35 return emptyUnknownFields{}
36 }
Joe Tsai95b02902018-10-31 18:23:42 -070037 return &legacyUnknownBytesAndExtensionMap{
Damien Neil8012b442019-01-18 09:32:24 -080038 unkFunc(p), extFunc(p), p.mi.PBType.ExtensionRanges(),
Joe Tsai95b02902018-10-31 18:23:42 -070039 }
40 }
41 }
42 return unkFunc
43}
44
45// legacyUnknownBytesAndExtensionMap is a wrapper around both XXX_unrecognized
46// and also the extension field map.
47type legacyUnknownBytesAndExtensionMap struct {
48 u pref.UnknownFields
Joe Tsai4fddeba2019-03-20 18:29:32 -070049 x legacyExtensionFieldsIface
Joe Tsai95b02902018-10-31 18:23:42 -070050 r pref.FieldRanges
51}
52
53func (fs *legacyUnknownBytesAndExtensionMap) Len() int {
54 n := fs.u.Len()
Joe Tsai4fddeba2019-03-20 18:29:32 -070055 fs.x.Range(func(_ pref.FieldNumber, x ExtensionFieldV1) bool {
Joe Tsaif18ab532018-11-27 17:25:04 -080056 if len(x.Raw) > 0 {
Joe Tsai95b02902018-10-31 18:23:42 -070057 n++
58 }
59 return true
60 })
61 return n
62}
63
64func (fs *legacyUnknownBytesAndExtensionMap) Get(num pref.FieldNumber) (raw pref.RawFields) {
65 if fs.r.Has(num) {
Joe Tsaif18ab532018-11-27 17:25:04 -080066 return fs.x.Get(num).Raw
Joe Tsai95b02902018-10-31 18:23:42 -070067 }
68 return fs.u.Get(num)
69}
70
71func (fs *legacyUnknownBytesAndExtensionMap) Set(num pref.FieldNumber, raw pref.RawFields) {
72 if fs.r.Has(num) {
73 x := fs.x.Get(num)
Joe Tsaif18ab532018-11-27 17:25:04 -080074 x.Raw = raw
Joe Tsai95b02902018-10-31 18:23:42 -070075 fs.x.Set(num, x)
76 return
77 }
78 fs.u.Set(num, raw)
79}
80
81func (fs *legacyUnknownBytesAndExtensionMap) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
82 // Range over unknown fields not in the extension range.
83 // Create a closure around f to capture whether iteration terminated early.
84 var stop bool
85 fs.u.Range(func(n pref.FieldNumber, b pref.RawFields) bool {
86 stop = stop || !f(n, b)
87 return !stop
88 })
89 if stop {
90 return
91 }
92
93 // Range over unknown fields in the extension range in ascending order
94 // to ensure protoreflect.UnknownFields.Range remains deterministic.
95 type entry struct {
96 num pref.FieldNumber
97 raw pref.RawFields
98 }
99 var xs []entry
Joe Tsai4fddeba2019-03-20 18:29:32 -0700100 fs.x.Range(func(n pref.FieldNumber, x ExtensionFieldV1) bool {
Joe Tsaif18ab532018-11-27 17:25:04 -0800101 if len(x.Raw) > 0 {
102 xs = append(xs, entry{n, x.Raw})
Joe Tsai95b02902018-10-31 18:23:42 -0700103 }
104 return true
105 })
106 sort.Slice(xs, func(i, j int) bool { return xs[i].num < xs[j].num })
107 for _, x := range xs {
108 if !f(x.num, x.raw) {
109 return
110 }
111 }
112}
113
114func (fs *legacyUnknownBytesAndExtensionMap) IsSupported() bool {
115 return true
Joe Tsaie2afdc22018-10-25 14:06:56 -0700116}
117
118// legacyUnknownBytes is a wrapper around XXX_unrecognized that implements
119// the protoreflect.UnknownFields interface. This is challenging since we are
120// limited to a []byte, so we do not have much flexibility in the choice
121// of data structure that would have been ideal.
122type legacyUnknownBytes []byte
123
124func (fs *legacyUnknownBytes) Len() int {
125 // Runtime complexity: O(n)
126 b := *fs
127 m := map[pref.FieldNumber]bool{}
128 for len(b) > 0 {
129 num, _, n := wire.ConsumeField(b)
130 m[num] = true
131 b = b[n:]
132 }
133 return len(m)
134}
135
136func (fs *legacyUnknownBytes) Get(num pref.FieldNumber) (raw pref.RawFields) {
137 // Runtime complexity: O(n)
138 b := *fs
139 for len(b) > 0 {
140 num2, _, n := wire.ConsumeField(b)
141 if num == num2 {
142 raw = append(raw, b[:n]...)
143 }
144 b = b[n:]
145 }
146 return raw
147}
148
149func (fs *legacyUnknownBytes) Set(num pref.FieldNumber, raw pref.RawFields) {
150 num2, _, _ := wire.ConsumeTag(raw)
151 if len(raw) > 0 && (!raw.IsValid() || num != num2) {
152 panic("invalid raw fields")
153 }
154
155 // Remove all current fields of num.
156 // Runtime complexity: O(n)
157 b := *fs
158 out := (*fs)[:0]
159 for len(b) > 0 {
160 num2, _, n := wire.ConsumeField(b)
161 if num != num2 {
162 out = append(out, b[:n]...)
163 }
164 b = b[n:]
165 }
166 *fs = out
167
168 // Append new fields of num.
169 *fs = append(*fs, raw...)
170}
171
172func (fs *legacyUnknownBytes) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
173 type entry struct {
174 num pref.FieldNumber
175 raw pref.RawFields
176 }
Joe Tsaie2afdc22018-10-25 14:06:56 -0700177
178 // Collect up a list of all the raw fields.
179 // We preserve the order such that the latest encountered fields
180 // are presented at the end.
181 //
182 // Runtime complexity: O(n)
183 b := *fs
Joe Tsai2d5a1692018-10-29 02:10:42 -0700184 l := list.New()
185 m := map[pref.FieldNumber]*list.Element{}
Joe Tsaie2afdc22018-10-25 14:06:56 -0700186 for len(b) > 0 {
187 num, _, n := wire.ConsumeField(b)
Joe Tsai2d5a1692018-10-29 02:10:42 -0700188 if e, ok := m[num]; ok {
189 x := e.Value.(*entry)
190 x.raw = append(x.raw, b[:n]...)
191 l.MoveToBack(e)
192 } else {
193 x := &entry{num: num}
194 x.raw = append(x.raw, b[:n]...)
195 m[num] = l.PushBack(x)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700196 }
Joe Tsaie2afdc22018-10-25 14:06:56 -0700197 b = b[n:]
198 }
199
200 // Iterate over all the raw fields.
201 // This ranges over a snapshot of the current state such that mutations
202 // while ranging are not observable.
203 //
204 // Runtime complexity: O(n)
Joe Tsai2d5a1692018-10-29 02:10:42 -0700205 for e := l.Front(); e != nil; e = e.Next() {
206 x := e.Value.(*entry)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700207 if !f(x.num, x.raw) {
208 return
209 }
210 }
211}
212
213func (fs *legacyUnknownBytes) IsSupported() bool {
214 return true
215}