blob: efeea2f01ba0bc4e74bb6babc191b8abdb041024 [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()
Damien Neilc70f5d52020-01-29 14:40:11 -0800113 if atomic.LoadUint32(&f.lazy.atomicOnce) == 1 {
114 return
115 }
Damien Neil0ae1c972020-01-28 14:53:44 -0800116 if f.lazy.xi != nil {
117 b := f.lazy.b
118 val := f.typ.New()
119 for len(b) > 0 {
120 var tag uint64
121 if b[0] < 0x80 {
122 tag = uint64(b[0])
123 b = b[1:]
124 } else if len(b) >= 2 && b[1] < 128 {
125 tag = uint64(b[0]&0x7f) + uint64(b[1])<<7
126 b = b[2:]
127 } else {
128 var n int
129 tag, n = wire.ConsumeVarint(b)
130 if n < 0 {
131 panic(errors.New("bad tag in lazy extension decoding"))
132 }
133 b = b[n:]
134 }
135 num := wire.Number(tag >> 3)
136 wtyp := wire.Type(tag & 7)
137 var out unmarshalOutput
138 var err error
Damien Neil6fb29942020-02-05 16:26:45 -0800139 val, out, err = f.lazy.xi.funcs.unmarshal(b, val, num, wtyp, lazyUnmarshalOptions)
Damien Neil0ae1c972020-01-28 14:53:44 -0800140 if err != nil {
141 panic(errors.New("decode failure in lazy extension decoding: %v", err))
142 }
143 b = b[out.n:]
144 }
145 f.lazy.value = val
146 } else {
147 f.lazy.value = f.lazy.fn()
148 }
149 f.lazy.xi = nil
150 f.lazy.fn = nil
151 f.lazy.b = nil
152 atomic.StoreUint32(&f.lazy.atomicOnce, 1)
153}
154
Damien Neil68b81c32019-08-22 11:41:32 -0700155// Set sets the type and value of the extension field.
156// This must not be called concurrently.
157func (f *ExtensionField) Set(t pref.ExtensionType, v pref.Value) {
Joe Tsai05e11b82019-06-04 17:05:04 -0700158 f.typ = t
Damien Neil68b81c32019-08-22 11:41:32 -0700159 f.value = v
Damien Neil0ae1c972020-01-28 14:53:44 -0800160 f.lazy = nil
Joe Tsai89d49632019-06-04 16:20:00 -0700161}
162
Damien Neil68b81c32019-08-22 11:41:32 -0700163// SetLazy sets the type and a value that is to be lazily evaluated upon first use.
164// This must not be called concurrently.
165func (f *ExtensionField) SetLazy(t pref.ExtensionType, fn func() pref.Value) {
166 f.typ = t
Damien Neil0ae1c972020-01-28 14:53:44 -0800167 f.lazy = &lazyExtensionValue{fn: fn}
Joe Tsai89d49632019-06-04 16:20:00 -0700168}
169
Damien Neil68b81c32019-08-22 11:41:32 -0700170// Value returns the value of the extension field.
Joe Tsai89d49632019-06-04 16:20:00 -0700171// This may be called concurrently.
Damien Neil68b81c32019-08-22 11:41:32 -0700172func (f *ExtensionField) Value() pref.Value {
173 if f.lazy != nil {
Damien Neil0ae1c972020-01-28 14:53:44 -0800174 if atomic.LoadUint32(&f.lazy.atomicOnce) == 0 {
175 f.lazyInit()
176 }
177 return f.lazy.value
Joe Tsai89d49632019-06-04 16:20:00 -0700178 }
179 return f.value
180}
181
Damien Neil68b81c32019-08-22 11:41:32 -0700182// Type returns the type of the extension field.
183// This may be called concurrently.
184func (f ExtensionField) Type() pref.ExtensionType {
185 return f.typ
Joe Tsai89d49632019-06-04 16:20:00 -0700186}
187
Damien Neil68b81c32019-08-22 11:41:32 -0700188// IsSet returns whether the extension field is set.
189// This may be called concurrently.
190func (f ExtensionField) IsSet() bool {
191 return f.typ != nil
192}
193
194// Deprecated: Do not use.
195func (f ExtensionField) HasType() bool {
196 return f.typ != nil
197}
198
199// Deprecated: Do not use.
200func (f ExtensionField) GetType() pref.ExtensionType {
201 return f.typ
202}
203
204// Deprecated: Do not use.
205func (f *ExtensionField) SetType(t pref.ExtensionType) {
206 f.typ = t
207}
208
209// Deprecated: Do not use.
210func (f ExtensionField) HasValue() bool {
211 return f.value.IsValid() || f.lazy != nil
212}
213
214// Deprecated: Do not use.
215func (f ExtensionField) GetValue() interface{} {
216 return f.typ.InterfaceOf(f.Value())
217}
218
219// Deprecated: Do not use.
220func (f *ExtensionField) SetEagerValue(ival interface{}) {
221 f.value = f.typ.ValueOf(ival)
222}
223
224// Deprecated: Do not use.
225func (f *ExtensionField) SetLazyValue(fn func() interface{}) {
Damien Neil0ae1c972020-01-28 14:53:44 -0800226 f.SetLazy(f.typ, func() pref.Value {
Damien Neil68b81c32019-08-22 11:41:32 -0700227 return f.typ.ValueOf(fn())
Damien Neil0ae1c972020-01-28 14:53:44 -0800228 })
Joe Tsai89d49632019-06-04 16:20:00 -0700229}
Damien Neil6fb29942020-02-05 16:26:45 -0800230
231// IsLazy reports whether a field is lazily encoded.
232// It is exported for testing.
233func IsLazy(m pref.Message, fd pref.FieldDescriptor) bool {
234 var mi *MessageInfo
235 var p pointer
236 switch m := m.(type) {
237 case *messageState:
238 mi = m.messageInfo()
239 p = m.pointer()
240 case *messageReflectWrapper:
241 mi = m.messageInfo()
242 p = m.pointer()
243 default:
244 return false
245 }
246 xd, ok := fd.(pref.ExtensionTypeDescriptor)
247 if !ok {
248 return false
249 }
250 xt := xd.Type()
251 ext := mi.extensionMap(p)
252 if ext == nil {
253 return false
254 }
255 f, ok := (*ext)[int32(fd.Number())]
256 if !ok {
257 return false
258 }
259 return f.typ == xt && f.lazy != nil && atomic.LoadUint32(&f.lazy.atomicOnce) == 0
260}