blob: c8c3a693ed692cdf6536f977750248608eb253f9 [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 (
8 "reflect"
9
10 protoV1 "github.com/golang/protobuf/proto"
11 "github.com/golang/protobuf/v2/internal/encoding/wire"
12 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
13)
14
15var (
16 extTypeA = reflect.TypeOf(map[int32]protoV1.Extension(nil))
17 extTypeB = reflect.TypeOf(protoV1.XXX_InternalExtensions{})
18)
19
20func generateLegacyUnknownFieldFuncs(t reflect.Type, md pref.MessageDescriptor) func(p *messageDataType) pref.UnknownFields {
21 fu, ok := t.FieldByName("XXX_unrecognized")
22 if !ok || fu.Type != bytesType {
23 return nil
24 }
25 fx1, _ := t.FieldByName("XXX_extensions")
26 fx2, _ := t.FieldByName("XXX_InternalExtensions")
27 if fx1.Type == extTypeA || fx2.Type == extTypeB {
28 // TODO: In proto v1, the unknown fields are split between both
29 // XXX_unrecognized and XXX_InternalExtensions. If the message supports
30 // extensions, then we will need to create a wrapper data structure
31 // that presents unknown fields in both lists as a single ordered list.
32 panic("not implemented")
33 }
34 fieldOffset := offsetOf(fu)
35 return func(p *messageDataType) pref.UnknownFields {
36 rv := p.p.apply(fieldOffset).asType(bytesType)
37 return (*legacyUnknownBytes)(rv.Interface().(*[]byte))
38 }
39}
40
41// legacyUnknownBytes is a wrapper around XXX_unrecognized that implements
42// the protoreflect.UnknownFields interface. This is challenging since we are
43// limited to a []byte, so we do not have much flexibility in the choice
44// of data structure that would have been ideal.
45type legacyUnknownBytes []byte
46
47func (fs *legacyUnknownBytes) Len() int {
48 // Runtime complexity: O(n)
49 b := *fs
50 m := map[pref.FieldNumber]bool{}
51 for len(b) > 0 {
52 num, _, n := wire.ConsumeField(b)
53 m[num] = true
54 b = b[n:]
55 }
56 return len(m)
57}
58
59func (fs *legacyUnknownBytes) Get(num pref.FieldNumber) (raw pref.RawFields) {
60 // Runtime complexity: O(n)
61 b := *fs
62 for len(b) > 0 {
63 num2, _, n := wire.ConsumeField(b)
64 if num == num2 {
65 raw = append(raw, b[:n]...)
66 }
67 b = b[n:]
68 }
69 return raw
70}
71
72func (fs *legacyUnknownBytes) Set(num pref.FieldNumber, raw pref.RawFields) {
73 num2, _, _ := wire.ConsumeTag(raw)
74 if len(raw) > 0 && (!raw.IsValid() || num != num2) {
75 panic("invalid raw fields")
76 }
77
78 // Remove all current fields of num.
79 // Runtime complexity: O(n)
80 b := *fs
81 out := (*fs)[:0]
82 for len(b) > 0 {
83 num2, _, n := wire.ConsumeField(b)
84 if num != num2 {
85 out = append(out, b[:n]...)
86 }
87 b = b[n:]
88 }
89 *fs = out
90
91 // Append new fields of num.
92 *fs = append(*fs, raw...)
93}
94
95func (fs *legacyUnknownBytes) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
96 type entry struct {
97 num pref.FieldNumber
98 raw pref.RawFields
99 }
100 var xs []entry
101
102 // Collect up a list of all the raw fields.
103 // We preserve the order such that the latest encountered fields
104 // are presented at the end.
105 //
106 // Runtime complexity: O(n)
107 b := *fs
108 m := map[pref.FieldNumber]int{}
109 for len(b) > 0 {
110 num, _, n := wire.ConsumeField(b)
111
112 // Ensure the most recently updated entry is always at the end of xs.
113 x := entry{num: num}
114 if i, ok := m[num]; ok {
115 j := len(xs) - 1
116 xs[i], xs[j] = xs[j], xs[i] // swap current entry with last entry
117 m[xs[i].num] = i // update index of swapped entry
118 x = xs[j] // retrieve the last entry
119 xs = xs[:j] // truncate off the last entry
120 }
121 m[num] = len(xs)
122 x.raw = append(x.raw, b[:n]...)
123 xs = append(xs, x)
124
125 b = b[n:]
126 }
127
128 // Iterate over all the raw fields.
129 // This ranges over a snapshot of the current state such that mutations
130 // while ranging are not observable.
131 //
132 // Runtime complexity: O(n)
133 for _, x := range xs {
134 if !f(x.num, x.raw) {
135 return
136 }
137 }
138}
139
140func (fs *legacyUnknownBytes) IsSupported() bool {
141 return true
142}