blob: 0492ecac940e3620d89e9e4afea88908112bc241 [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 Tsaie2afdc22018-10-25 14:06:56 -070026 rv := p.p.apply(fieldOffset).asType(bytesType)
27 return (*legacyUnknownBytes)(rv.Interface().(*[]byte))
28 }
Joe Tsai95b02902018-10-31 18:23:42 -070029 extFunc := makeLegacyExtensionMapFunc(t)
30 if extFunc != nil {
31 return func(p *messageDataType) pref.UnknownFields {
32 return &legacyUnknownBytesAndExtensionMap{
Joe Tsaif0c01e42018-11-06 13:05:20 -080033 unkFunc(p), extFunc(p), p.mi.Type.ExtensionRanges(),
Joe Tsai95b02902018-10-31 18:23:42 -070034 }
35 }
36 }
37 return unkFunc
38}
39
40// legacyUnknownBytesAndExtensionMap is a wrapper around both XXX_unrecognized
41// and also the extension field map.
42type legacyUnknownBytesAndExtensionMap struct {
43 u pref.UnknownFields
Joe Tsaif18ab532018-11-27 17:25:04 -080044 x papi.ExtensionFields
Joe Tsai95b02902018-10-31 18:23:42 -070045 r pref.FieldRanges
46}
47
48func (fs *legacyUnknownBytesAndExtensionMap) Len() int {
49 n := fs.u.Len()
Joe Tsaif18ab532018-11-27 17:25:04 -080050 fs.x.Range(func(_ pref.FieldNumber, x papi.ExtensionField) bool {
51 if len(x.Raw) > 0 {
Joe Tsai95b02902018-10-31 18:23:42 -070052 n++
53 }
54 return true
55 })
56 return n
57}
58
59func (fs *legacyUnknownBytesAndExtensionMap) Get(num pref.FieldNumber) (raw pref.RawFields) {
60 if fs.r.Has(num) {
Joe Tsaif18ab532018-11-27 17:25:04 -080061 return fs.x.Get(num).Raw
Joe Tsai95b02902018-10-31 18:23:42 -070062 }
63 return fs.u.Get(num)
64}
65
66func (fs *legacyUnknownBytesAndExtensionMap) Set(num pref.FieldNumber, raw pref.RawFields) {
67 if fs.r.Has(num) {
68 x := fs.x.Get(num)
Joe Tsaif18ab532018-11-27 17:25:04 -080069 x.Raw = raw
Joe Tsai95b02902018-10-31 18:23:42 -070070 fs.x.Set(num, x)
71 return
72 }
73 fs.u.Set(num, raw)
74}
75
76func (fs *legacyUnknownBytesAndExtensionMap) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
77 // Range over unknown fields not in the extension range.
78 // Create a closure around f to capture whether iteration terminated early.
79 var stop bool
80 fs.u.Range(func(n pref.FieldNumber, b pref.RawFields) bool {
81 stop = stop || !f(n, b)
82 return !stop
83 })
84 if stop {
85 return
86 }
87
88 // Range over unknown fields in the extension range in ascending order
89 // to ensure protoreflect.UnknownFields.Range remains deterministic.
90 type entry struct {
91 num pref.FieldNumber
92 raw pref.RawFields
93 }
94 var xs []entry
Joe Tsaif18ab532018-11-27 17:25:04 -080095 fs.x.Range(func(n pref.FieldNumber, x papi.ExtensionField) bool {
96 if len(x.Raw) > 0 {
97 xs = append(xs, entry{n, x.Raw})
Joe Tsai95b02902018-10-31 18:23:42 -070098 }
99 return true
100 })
101 sort.Slice(xs, func(i, j int) bool { return xs[i].num < xs[j].num })
102 for _, x := range xs {
103 if !f(x.num, x.raw) {
104 return
105 }
106 }
107}
108
109func (fs *legacyUnknownBytesAndExtensionMap) IsSupported() bool {
110 return true
Joe Tsaie2afdc22018-10-25 14:06:56 -0700111}
112
113// legacyUnknownBytes is a wrapper around XXX_unrecognized that implements
114// the protoreflect.UnknownFields interface. This is challenging since we are
115// limited to a []byte, so we do not have much flexibility in the choice
116// of data structure that would have been ideal.
117type legacyUnknownBytes []byte
118
119func (fs *legacyUnknownBytes) Len() int {
120 // Runtime complexity: O(n)
121 b := *fs
122 m := map[pref.FieldNumber]bool{}
123 for len(b) > 0 {
124 num, _, n := wire.ConsumeField(b)
125 m[num] = true
126 b = b[n:]
127 }
128 return len(m)
129}
130
131func (fs *legacyUnknownBytes) Get(num pref.FieldNumber) (raw pref.RawFields) {
132 // Runtime complexity: O(n)
133 b := *fs
134 for len(b) > 0 {
135 num2, _, n := wire.ConsumeField(b)
136 if num == num2 {
137 raw = append(raw, b[:n]...)
138 }
139 b = b[n:]
140 }
141 return raw
142}
143
144func (fs *legacyUnknownBytes) Set(num pref.FieldNumber, raw pref.RawFields) {
145 num2, _, _ := wire.ConsumeTag(raw)
146 if len(raw) > 0 && (!raw.IsValid() || num != num2) {
147 panic("invalid raw fields")
148 }
149
150 // Remove all current fields of num.
151 // Runtime complexity: O(n)
152 b := *fs
153 out := (*fs)[:0]
154 for len(b) > 0 {
155 num2, _, n := wire.ConsumeField(b)
156 if num != num2 {
157 out = append(out, b[:n]...)
158 }
159 b = b[n:]
160 }
161 *fs = out
162
163 // Append new fields of num.
164 *fs = append(*fs, raw...)
165}
166
167func (fs *legacyUnknownBytes) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
168 type entry struct {
169 num pref.FieldNumber
170 raw pref.RawFields
171 }
Joe Tsaie2afdc22018-10-25 14:06:56 -0700172
173 // Collect up a list of all the raw fields.
174 // We preserve the order such that the latest encountered fields
175 // are presented at the end.
176 //
177 // Runtime complexity: O(n)
178 b := *fs
Joe Tsai2d5a1692018-10-29 02:10:42 -0700179 l := list.New()
180 m := map[pref.FieldNumber]*list.Element{}
Joe Tsaie2afdc22018-10-25 14:06:56 -0700181 for len(b) > 0 {
182 num, _, n := wire.ConsumeField(b)
Joe Tsai2d5a1692018-10-29 02:10:42 -0700183 if e, ok := m[num]; ok {
184 x := e.Value.(*entry)
185 x.raw = append(x.raw, b[:n]...)
186 l.MoveToBack(e)
187 } else {
188 x := &entry{num: num}
189 x.raw = append(x.raw, b[:n]...)
190 m[num] = l.PushBack(x)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700191 }
Joe Tsaie2afdc22018-10-25 14:06:56 -0700192 b = b[n:]
193 }
194
195 // Iterate over all the raw fields.
196 // This ranges over a snapshot of the current state such that mutations
197 // while ranging are not observable.
198 //
199 // Runtime complexity: O(n)
Joe Tsai2d5a1692018-10-29 02:10:42 -0700200 for e := l.Front(); e != nil; e = e.Next() {
201 x := e.Value.(*entry)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700202 if !f(x.num, x.raw) {
203 return
204 }
205 }
206}
207
208func (fs *legacyUnknownBytes) IsSupported() bool {
209 return true
210}