blob: b4f57dafc551c500612b49221b50b99ccf17014f [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 Tsaif18ab532018-11-27 17:25:04 -080012 papi "github.com/golang/protobuf/protoapi"
Joe Tsaie2afdc22018-10-25 14:06:56 -070013 "github.com/golang/protobuf/v2/internal/encoding/wire"
14 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
15)
16
Joe Tsai88bc5a72018-11-05 11:42:22 -080017var bytesType = reflect.TypeOf([]byte(nil))
18
Joe Tsai95b02902018-10-31 18:23:42 -070019func makeLegacyUnknownFieldsFunc(t reflect.Type) func(p *messageDataType) pref.UnknownFields {
Joe Tsaie2afdc22018-10-25 14:06:56 -070020 fu, ok := t.FieldByName("XXX_unrecognized")
21 if !ok || fu.Type != bytesType {
22 return nil
23 }
Joe Tsaie2afdc22018-10-25 14:06:56 -070024 fieldOffset := offsetOf(fu)
Joe Tsai95b02902018-10-31 18:23:42 -070025 unkFunc := func(p *messageDataType) pref.UnknownFields {
Joe Tsai6cf80c42018-12-01 04:57:09 -080026 if p.p.IsNil() {
27 return emptyUnknownFields{}
28 }
29 rv := p.p.Apply(fieldOffset).AsValueOf(bytesType)
Joe Tsaie2afdc22018-10-25 14:06:56 -070030 return (*legacyUnknownBytes)(rv.Interface().(*[]byte))
31 }
Joe Tsai95b02902018-10-31 18:23:42 -070032 extFunc := makeLegacyExtensionMapFunc(t)
33 if extFunc != nil {
34 return func(p *messageDataType) pref.UnknownFields {
Joe Tsai6cf80c42018-12-01 04:57:09 -080035 if p.p.IsNil() {
36 return emptyUnknownFields{}
37 }
Joe Tsai95b02902018-10-31 18:23:42 -070038 return &legacyUnknownBytesAndExtensionMap{
Joe Tsaif0c01e42018-11-06 13:05:20 -080039 unkFunc(p), extFunc(p), p.mi.Type.ExtensionRanges(),
Joe Tsai95b02902018-10-31 18:23:42 -070040 }
41 }
42 }
43 return unkFunc
44}
45
46// legacyUnknownBytesAndExtensionMap is a wrapper around both XXX_unrecognized
47// and also the extension field map.
48type legacyUnknownBytesAndExtensionMap struct {
49 u pref.UnknownFields
Joe Tsaif18ab532018-11-27 17:25:04 -080050 x papi.ExtensionFields
Joe Tsai95b02902018-10-31 18:23:42 -070051 r pref.FieldRanges
52}
53
54func (fs *legacyUnknownBytesAndExtensionMap) Len() int {
55 n := fs.u.Len()
Joe Tsaif18ab532018-11-27 17:25:04 -080056 fs.x.Range(func(_ pref.FieldNumber, x papi.ExtensionField) bool {
57 if len(x.Raw) > 0 {
Joe Tsai95b02902018-10-31 18:23:42 -070058 n++
59 }
60 return true
61 })
62 return n
63}
64
65func (fs *legacyUnknownBytesAndExtensionMap) Get(num pref.FieldNumber) (raw pref.RawFields) {
66 if fs.r.Has(num) {
Joe Tsaif18ab532018-11-27 17:25:04 -080067 return fs.x.Get(num).Raw
Joe Tsai95b02902018-10-31 18:23:42 -070068 }
69 return fs.u.Get(num)
70}
71
72func (fs *legacyUnknownBytesAndExtensionMap) Set(num pref.FieldNumber, raw pref.RawFields) {
73 if fs.r.Has(num) {
74 x := fs.x.Get(num)
Joe Tsaif18ab532018-11-27 17:25:04 -080075 x.Raw = raw
Joe Tsai95b02902018-10-31 18:23:42 -070076 fs.x.Set(num, x)
77 return
78 }
79 fs.u.Set(num, raw)
80}
81
82func (fs *legacyUnknownBytesAndExtensionMap) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
83 // Range over unknown fields not in the extension range.
84 // Create a closure around f to capture whether iteration terminated early.
85 var stop bool
86 fs.u.Range(func(n pref.FieldNumber, b pref.RawFields) bool {
87 stop = stop || !f(n, b)
88 return !stop
89 })
90 if stop {
91 return
92 }
93
94 // Range over unknown fields in the extension range in ascending order
95 // to ensure protoreflect.UnknownFields.Range remains deterministic.
96 type entry struct {
97 num pref.FieldNumber
98 raw pref.RawFields
99 }
100 var xs []entry
Joe Tsaif18ab532018-11-27 17:25:04 -0800101 fs.x.Range(func(n pref.FieldNumber, x papi.ExtensionField) bool {
102 if len(x.Raw) > 0 {
103 xs = append(xs, entry{n, x.Raw})
Joe Tsai95b02902018-10-31 18:23:42 -0700104 }
105 return true
106 })
107 sort.Slice(xs, func(i, j int) bool { return xs[i].num < xs[j].num })
108 for _, x := range xs {
109 if !f(x.num, x.raw) {
110 return
111 }
112 }
113}
114
115func (fs *legacyUnknownBytesAndExtensionMap) IsSupported() bool {
116 return true
Joe Tsaie2afdc22018-10-25 14:06:56 -0700117}
118
119// legacyUnknownBytes is a wrapper around XXX_unrecognized that implements
120// the protoreflect.UnknownFields interface. This is challenging since we are
121// limited to a []byte, so we do not have much flexibility in the choice
122// of data structure that would have been ideal.
123type legacyUnknownBytes []byte
124
125func (fs *legacyUnknownBytes) Len() int {
126 // Runtime complexity: O(n)
127 b := *fs
128 m := map[pref.FieldNumber]bool{}
129 for len(b) > 0 {
130 num, _, n := wire.ConsumeField(b)
131 m[num] = true
132 b = b[n:]
133 }
134 return len(m)
135}
136
137func (fs *legacyUnknownBytes) Get(num pref.FieldNumber) (raw pref.RawFields) {
138 // Runtime complexity: O(n)
139 b := *fs
140 for len(b) > 0 {
141 num2, _, n := wire.ConsumeField(b)
142 if num == num2 {
143 raw = append(raw, b[:n]...)
144 }
145 b = b[n:]
146 }
147 return raw
148}
149
150func (fs *legacyUnknownBytes) Set(num pref.FieldNumber, raw pref.RawFields) {
151 num2, _, _ := wire.ConsumeTag(raw)
152 if len(raw) > 0 && (!raw.IsValid() || num != num2) {
153 panic("invalid raw fields")
154 }
155
156 // Remove all current fields of num.
157 // Runtime complexity: O(n)
158 b := *fs
159 out := (*fs)[:0]
160 for len(b) > 0 {
161 num2, _, n := wire.ConsumeField(b)
162 if num != num2 {
163 out = append(out, b[:n]...)
164 }
165 b = b[n:]
166 }
167 *fs = out
168
169 // Append new fields of num.
170 *fs = append(*fs, raw...)
171}
172
173func (fs *legacyUnknownBytes) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
174 type entry struct {
175 num pref.FieldNumber
176 raw pref.RawFields
177 }
Joe Tsaie2afdc22018-10-25 14:06:56 -0700178
179 // Collect up a list of all the raw fields.
180 // We preserve the order such that the latest encountered fields
181 // are presented at the end.
182 //
183 // Runtime complexity: O(n)
184 b := *fs
Joe Tsai2d5a1692018-10-29 02:10:42 -0700185 l := list.New()
186 m := map[pref.FieldNumber]*list.Element{}
Joe Tsaie2afdc22018-10-25 14:06:56 -0700187 for len(b) > 0 {
188 num, _, n := wire.ConsumeField(b)
Joe Tsai2d5a1692018-10-29 02:10:42 -0700189 if e, ok := m[num]; ok {
190 x := e.Value.(*entry)
191 x.raw = append(x.raw, b[:n]...)
192 l.MoveToBack(e)
193 } else {
194 x := &entry{num: num}
195 x.raw = append(x.raw, b[:n]...)
196 m[num] = l.PushBack(x)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700197 }
Joe Tsaie2afdc22018-10-25 14:06:56 -0700198 b = b[n:]
199 }
200
201 // Iterate over all the raw fields.
202 // This ranges over a snapshot of the current state such that mutations
203 // while ranging are not observable.
204 //
205 // Runtime complexity: O(n)
Joe Tsai2d5a1692018-10-29 02:10:42 -0700206 for e := l.Front(); e != nil; e = e.Next() {
207 x := e.Value.(*entry)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700208 if !f(x.num, x.raw) {
209 return
210 }
211 }
212}
213
214func (fs *legacyUnknownBytes) IsSupported() bool {
215 return true
216}