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