blob: 141a3cda95095fdcce328b5c2445731e3b55282e [file] [log] [blame]
Damien Neilc37adef2019-04-01 13:49:56 -07001// Copyright 2019 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 Tsai89d49632019-06-04 16:20:00 -07008 "sync"
9 "sync/atomic"
10
Damien Neilc37adef2019-04-01 13:49:56 -070011 "google.golang.org/protobuf/internal/encoding/wire"
Damien Neil0ae1c972020-01-28 14:53:44 -080012 "google.golang.org/protobuf/internal/errors"
Joe Tsai89d49632019-06-04 16:20:00 -070013 pref "google.golang.org/protobuf/reflect/protoreflect"
Damien Neilc37adef2019-04-01 13:49:56 -070014)
15
16type extensionFieldInfo struct {
Damien Neile91877d2019-06-27 10:54:42 -070017 wiretag uint64
18 tagsize int
19 unmarshalNeedsValue bool
Damien Neil68b81c32019-08-22 11:41:32 -070020 funcs valueCoderFuncs
Damien Neilb0c26f12019-12-16 09:37:59 -080021 validation validationInfo
Damien Neilc37adef2019-04-01 13:49:56 -070022}
23
Damien Neil79571e92019-12-09 10:24:36 -080024var legacyExtensionFieldInfoCache sync.Map // map[protoreflect.ExtensionType]*extensionFieldInfo
Damien Neilc37adef2019-04-01 13:49:56 -070025
Damien Neil79571e92019-12-09 10:24:36 -080026func getExtensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
27 if xi, ok := xt.(*ExtensionInfo); ok {
28 xi.lazyInit()
29 return xi.info
30 }
31 return legacyLoadExtensionFieldInfo(xt)
32}
33
34// legacyLoadExtensionFieldInfo dynamically loads a *ExtensionInfo for xt.
35func legacyLoadExtensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
36 if xi, ok := legacyExtensionFieldInfoCache.Load(xt); ok {
37 return xi.(*extensionFieldInfo)
38 }
39 e := makeExtensionFieldInfo(xt.TypeDescriptor())
40 if e, ok := legacyMessageTypeCache.LoadOrStore(xt, e); ok {
41 return e.(*extensionFieldInfo)
42 }
43 return e
44}
45
46func makeExtensionFieldInfo(xd pref.ExtensionDescriptor) *extensionFieldInfo {
Damien Neil7492a092019-07-10 15:23:29 -070047 var wiretag uint64
Damien Neil92f76182019-08-02 16:58:08 -070048 if !xd.IsPacked() {
49 wiretag = wire.EncodeTag(xd.Number(), wireTypes[xd.Kind()])
Damien Neil7492a092019-07-10 15:23:29 -070050 } else {
Damien Neil92f76182019-08-02 16:58:08 -070051 wiretag = wire.EncodeTag(xd.Number(), wire.BytesType)
Damien Neil7492a092019-07-10 15:23:29 -070052 }
Damien Neil79571e92019-12-09 10:24:36 -080053 e := &extensionFieldInfo{
Damien Neilc37adef2019-04-01 13:49:56 -070054 wiretag: wiretag,
55 tagsize: wire.SizeVarint(wiretag),
Damien Neil4b3a82f2019-09-04 19:07:00 -070056 funcs: encoderFuncsForValue(xd),
Damien Neilc37adef2019-04-01 13:49:56 -070057 }
Damien Neile91877d2019-06-27 10:54:42 -070058 // Does the unmarshal function need a value passed to it?
59 // This is true for composite types, where we pass in a message, list, or map to fill in,
60 // and for enums, where we pass in a prototype value to specify the concrete enum type.
Damien Neil92f76182019-08-02 16:58:08 -070061 switch xd.Kind() {
Damien Neile91877d2019-06-27 10:54:42 -070062 case pref.MessageKind, pref.GroupKind, pref.EnumKind:
63 e.unmarshalNeedsValue = true
64 default:
Damien Neil92f76182019-08-02 16:58:08 -070065 if xd.Cardinality() == pref.Repeated {
Damien Neile91877d2019-06-27 10:54:42 -070066 e.unmarshalNeedsValue = true
67 }
68 }
Damien Neilc37adef2019-04-01 13:49:56 -070069 return e
70}
Joe Tsai89d49632019-06-04 16:20:00 -070071
Damien Neil0ae1c972020-01-28 14:53:44 -080072type lazyExtensionValue struct {
73 atomicOnce uint32 // atomically set if value is valid
74 mu sync.Mutex
75 xi *extensionFieldInfo
76 value pref.Value
77 b []byte
78 fn func() pref.Value
79}
80
Joe Tsai89d49632019-06-04 16:20:00 -070081type ExtensionField struct {
Joe Tsai05e11b82019-06-04 17:05:04 -070082 typ pref.ExtensionType
Joe Tsai89d49632019-06-04 16:20:00 -070083
84 // value is either the value of GetValue,
85 // or a *lazyExtensionValue that then returns the value of GetValue.
Damien Neil68b81c32019-08-22 11:41:32 -070086 value pref.Value
87 lazy *lazyExtensionValue
Joe Tsai89d49632019-06-04 16:20:00 -070088}
89
Damien Neil0ae1c972020-01-28 14:53:44 -080090func (f *ExtensionField) appendLazyBytes(xt pref.ExtensionType, xi *extensionFieldInfo, num wire.Number, wtyp wire.Type, b []byte) {
91 if f.lazy == nil {
92 f.lazy = &lazyExtensionValue{xi: xi}
93 }
94 f.typ = xt
95 f.lazy.xi = xi
96 f.lazy.b = wire.AppendTag(f.lazy.b, num, wtyp)
97 f.lazy.b = append(f.lazy.b, b...)
98}
99
100func (f *ExtensionField) canLazy(xt pref.ExtensionType) bool {
101 if f.typ == nil {
102 return true
103 }
104 if f.typ == xt && f.lazy != nil && atomic.LoadUint32(&f.lazy.atomicOnce) == 0 {
105 return true
106 }
107 return false
108}
109
110func (f *ExtensionField) lazyInit() {
111 f.lazy.mu.Lock()
112 defer f.lazy.mu.Unlock()
113 if f.lazy.xi != nil {
114 b := f.lazy.b
115 val := f.typ.New()
116 for len(b) > 0 {
117 var tag uint64
118 if b[0] < 0x80 {
119 tag = uint64(b[0])
120 b = b[1:]
121 } else if len(b) >= 2 && b[1] < 128 {
122 tag = uint64(b[0]&0x7f) + uint64(b[1])<<7
123 b = b[2:]
124 } else {
125 var n int
126 tag, n = wire.ConsumeVarint(b)
127 if n < 0 {
128 panic(errors.New("bad tag in lazy extension decoding"))
129 }
130 b = b[n:]
131 }
132 num := wire.Number(tag >> 3)
133 wtyp := wire.Type(tag & 7)
134 var out unmarshalOutput
135 var err error
136 val, out, err = f.lazy.xi.funcs.unmarshal(b, val, num, wtyp, unmarshalOptions{}) // TODO: options
137 if err != nil {
138 panic(errors.New("decode failure in lazy extension decoding: %v", err))
139 }
140 b = b[out.n:]
141 }
142 f.lazy.value = val
143 } else {
144 f.lazy.value = f.lazy.fn()
145 }
146 f.lazy.xi = nil
147 f.lazy.fn = nil
148 f.lazy.b = nil
149 atomic.StoreUint32(&f.lazy.atomicOnce, 1)
150}
151
Damien Neil68b81c32019-08-22 11:41:32 -0700152// Set sets the type and value of the extension field.
153// This must not be called concurrently.
154func (f *ExtensionField) Set(t pref.ExtensionType, v pref.Value) {
Joe Tsai05e11b82019-06-04 17:05:04 -0700155 f.typ = t
Damien Neil68b81c32019-08-22 11:41:32 -0700156 f.value = v
Damien Neil0ae1c972020-01-28 14:53:44 -0800157 f.lazy = nil
Joe Tsai89d49632019-06-04 16:20:00 -0700158}
159
Damien Neil68b81c32019-08-22 11:41:32 -0700160// SetLazy sets the type and a value that is to be lazily evaluated upon first use.
161// This must not be called concurrently.
162func (f *ExtensionField) SetLazy(t pref.ExtensionType, fn func() pref.Value) {
163 f.typ = t
Damien Neil0ae1c972020-01-28 14:53:44 -0800164 f.lazy = &lazyExtensionValue{fn: fn}
Joe Tsai89d49632019-06-04 16:20:00 -0700165}
166
Damien Neil68b81c32019-08-22 11:41:32 -0700167// Value returns the value of the extension field.
Joe Tsai89d49632019-06-04 16:20:00 -0700168// This may be called concurrently.
Damien Neil68b81c32019-08-22 11:41:32 -0700169func (f *ExtensionField) Value() pref.Value {
170 if f.lazy != nil {
Damien Neil0ae1c972020-01-28 14:53:44 -0800171 if atomic.LoadUint32(&f.lazy.atomicOnce) == 0 {
172 f.lazyInit()
173 }
174 return f.lazy.value
Joe Tsai89d49632019-06-04 16:20:00 -0700175 }
176 return f.value
177}
178
Damien Neil68b81c32019-08-22 11:41:32 -0700179// Type returns the type of the extension field.
180// This may be called concurrently.
181func (f ExtensionField) Type() pref.ExtensionType {
182 return f.typ
Joe Tsai89d49632019-06-04 16:20:00 -0700183}
184
Damien Neil68b81c32019-08-22 11:41:32 -0700185// IsSet returns whether the extension field is set.
186// This may be called concurrently.
187func (f ExtensionField) IsSet() bool {
188 return f.typ != nil
189}
190
191// Deprecated: Do not use.
192func (f ExtensionField) HasType() bool {
193 return f.typ != nil
194}
195
196// Deprecated: Do not use.
197func (f ExtensionField) GetType() pref.ExtensionType {
198 return f.typ
199}
200
201// Deprecated: Do not use.
202func (f *ExtensionField) SetType(t pref.ExtensionType) {
203 f.typ = t
204}
205
206// Deprecated: Do not use.
207func (f ExtensionField) HasValue() bool {
208 return f.value.IsValid() || f.lazy != nil
209}
210
211// Deprecated: Do not use.
212func (f ExtensionField) GetValue() interface{} {
213 return f.typ.InterfaceOf(f.Value())
214}
215
216// Deprecated: Do not use.
217func (f *ExtensionField) SetEagerValue(ival interface{}) {
218 f.value = f.typ.ValueOf(ival)
219}
220
221// Deprecated: Do not use.
222func (f *ExtensionField) SetLazyValue(fn func() interface{}) {
Damien Neil0ae1c972020-01-28 14:53:44 -0800223 f.SetLazy(f.typ, func() pref.Value {
Damien Neil68b81c32019-08-22 11:41:32 -0700224 return f.typ.ValueOf(fn())
Damien Neil0ae1c972020-01-28 14:53:44 -0800225 })
Joe Tsai89d49632019-06-04 16:20:00 -0700226}