blob: 919d02dfa8d5281b543b52cfa9c64d79e93a56a0 [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
Joe Tsaie2afdc22018-10-25 14:06:56 -070011 "github.com/golang/protobuf/v2/internal/encoding/wire"
12 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
13)
14
Joe Tsai88bc5a72018-11-05 11:42:22 -080015var bytesType = reflect.TypeOf([]byte(nil))
16
Joe Tsai95b02902018-10-31 18:23:42 -070017func makeLegacyUnknownFieldsFunc(t reflect.Type) func(p *messageDataType) pref.UnknownFields {
Joe Tsaie2afdc22018-10-25 14:06:56 -070018 fu, ok := t.FieldByName("XXX_unrecognized")
19 if !ok || fu.Type != bytesType {
20 return nil
21 }
Joe Tsaie2afdc22018-10-25 14:06:56 -070022 fieldOffset := offsetOf(fu)
Joe Tsai00a323d2019-05-06 23:27:29 -070023 return func(p *messageDataType) pref.UnknownFields {
Joe Tsai6cf80c42018-12-01 04:57:09 -080024 if p.p.IsNil() {
25 return emptyUnknownFields{}
26 }
27 rv := p.p.Apply(fieldOffset).AsValueOf(bytesType)
Joe Tsaie2afdc22018-10-25 14:06:56 -070028 return (*legacyUnknownBytes)(rv.Interface().(*[]byte))
29 }
30}
31
32// legacyUnknownBytes is a wrapper around XXX_unrecognized that implements
33// the protoreflect.UnknownFields interface. This is challenging since we are
34// limited to a []byte, so we do not have much flexibility in the choice
35// of data structure that would have been ideal.
36type legacyUnknownBytes []byte
37
38func (fs *legacyUnknownBytes) Len() int {
39 // Runtime complexity: O(n)
40 b := *fs
41 m := map[pref.FieldNumber]bool{}
42 for len(b) > 0 {
43 num, _, n := wire.ConsumeField(b)
44 m[num] = true
45 b = b[n:]
46 }
47 return len(m)
48}
49
50func (fs *legacyUnknownBytes) Get(num pref.FieldNumber) (raw pref.RawFields) {
51 // Runtime complexity: O(n)
52 b := *fs
53 for len(b) > 0 {
54 num2, _, n := wire.ConsumeField(b)
55 if num == num2 {
56 raw = append(raw, b[:n]...)
57 }
58 b = b[n:]
59 }
60 return raw
61}
62
63func (fs *legacyUnknownBytes) Set(num pref.FieldNumber, raw pref.RawFields) {
64 num2, _, _ := wire.ConsumeTag(raw)
65 if len(raw) > 0 && (!raw.IsValid() || num != num2) {
66 panic("invalid raw fields")
67 }
68
69 // Remove all current fields of num.
70 // Runtime complexity: O(n)
71 b := *fs
72 out := (*fs)[:0]
73 for len(b) > 0 {
74 num2, _, n := wire.ConsumeField(b)
75 if num != num2 {
76 out = append(out, b[:n]...)
77 }
78 b = b[n:]
79 }
80 *fs = out
81
82 // Append new fields of num.
83 *fs = append(*fs, raw...)
84}
85
86func (fs *legacyUnknownBytes) Range(f func(pref.FieldNumber, pref.RawFields) bool) {
87 type entry struct {
88 num pref.FieldNumber
89 raw pref.RawFields
90 }
Joe Tsaie2afdc22018-10-25 14:06:56 -070091
92 // Collect up a list of all the raw fields.
93 // We preserve the order such that the latest encountered fields
94 // are presented at the end.
95 //
96 // Runtime complexity: O(n)
97 b := *fs
Joe Tsai2d5a1692018-10-29 02:10:42 -070098 l := list.New()
99 m := map[pref.FieldNumber]*list.Element{}
Joe Tsaie2afdc22018-10-25 14:06:56 -0700100 for len(b) > 0 {
101 num, _, n := wire.ConsumeField(b)
Joe Tsai2d5a1692018-10-29 02:10:42 -0700102 if e, ok := m[num]; ok {
103 x := e.Value.(*entry)
104 x.raw = append(x.raw, b[:n]...)
105 l.MoveToBack(e)
106 } else {
107 x := &entry{num: num}
108 x.raw = append(x.raw, b[:n]...)
109 m[num] = l.PushBack(x)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700110 }
Joe Tsaie2afdc22018-10-25 14:06:56 -0700111 b = b[n:]
112 }
113
114 // Iterate over all the raw fields.
115 // This ranges over a snapshot of the current state such that mutations
116 // while ranging are not observable.
117 //
118 // Runtime complexity: O(n)
Joe Tsai2d5a1692018-10-29 02:10:42 -0700119 for e := l.Front(); e != nil; e = e.Next() {
120 x := e.Value.(*entry)
Joe Tsaie2afdc22018-10-25 14:06:56 -0700121 if !f(x.num, x.raw) {
122 return
123 }
124 }
125}
126
127func (fs *legacyUnknownBytes) IsSupported() bool {
128 return true
129}