blob: 8c8037781bba9b6345075134fe1729a4db9523ef [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"
Joe Tsai89d49632019-06-04 16:20:00 -070012 pref "google.golang.org/protobuf/reflect/protoreflect"
Damien Neilc37adef2019-04-01 13:49:56 -070013)
14
15type extensionFieldInfo struct {
Damien Neile91877d2019-06-27 10:54:42 -070016 wiretag uint64
17 tagsize int
18 unmarshalNeedsValue bool
Damien Neil68b81c32019-08-22 11:41:32 -070019 funcs valueCoderFuncs
Damien Neilb0c26f12019-12-16 09:37:59 -080020 validation validationInfo
Damien Neilc37adef2019-04-01 13:49:56 -070021}
22
Damien Neil79571e92019-12-09 10:24:36 -080023var legacyExtensionFieldInfoCache sync.Map // map[protoreflect.ExtensionType]*extensionFieldInfo
Damien Neilc37adef2019-04-01 13:49:56 -070024
Damien Neil79571e92019-12-09 10:24:36 -080025func getExtensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
26 if xi, ok := xt.(*ExtensionInfo); ok {
27 xi.lazyInit()
28 return xi.info
29 }
30 return legacyLoadExtensionFieldInfo(xt)
31}
32
33// legacyLoadExtensionFieldInfo dynamically loads a *ExtensionInfo for xt.
34func legacyLoadExtensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
35 if xi, ok := legacyExtensionFieldInfoCache.Load(xt); ok {
36 return xi.(*extensionFieldInfo)
37 }
38 e := makeExtensionFieldInfo(xt.TypeDescriptor())
39 if e, ok := legacyMessageTypeCache.LoadOrStore(xt, e); ok {
40 return e.(*extensionFieldInfo)
41 }
42 return e
43}
44
45func makeExtensionFieldInfo(xd pref.ExtensionDescriptor) *extensionFieldInfo {
Damien Neil7492a092019-07-10 15:23:29 -070046 var wiretag uint64
Damien Neil92f76182019-08-02 16:58:08 -070047 if !xd.IsPacked() {
48 wiretag = wire.EncodeTag(xd.Number(), wireTypes[xd.Kind()])
Damien Neil7492a092019-07-10 15:23:29 -070049 } else {
Damien Neil92f76182019-08-02 16:58:08 -070050 wiretag = wire.EncodeTag(xd.Number(), wire.BytesType)
Damien Neil7492a092019-07-10 15:23:29 -070051 }
Damien Neil79571e92019-12-09 10:24:36 -080052 e := &extensionFieldInfo{
Damien Neilc37adef2019-04-01 13:49:56 -070053 wiretag: wiretag,
54 tagsize: wire.SizeVarint(wiretag),
Damien Neil4b3a82f2019-09-04 19:07:00 -070055 funcs: encoderFuncsForValue(xd),
Damien Neilc37adef2019-04-01 13:49:56 -070056 }
Damien Neile91877d2019-06-27 10:54:42 -070057 // Does the unmarshal function need a value passed to it?
58 // This is true for composite types, where we pass in a message, list, or map to fill in,
59 // and for enums, where we pass in a prototype value to specify the concrete enum type.
Damien Neil92f76182019-08-02 16:58:08 -070060 switch xd.Kind() {
Damien Neile91877d2019-06-27 10:54:42 -070061 case pref.MessageKind, pref.GroupKind, pref.EnumKind:
62 e.unmarshalNeedsValue = true
63 default:
Damien Neil92f76182019-08-02 16:58:08 -070064 if xd.Cardinality() == pref.Repeated {
Damien Neile91877d2019-06-27 10:54:42 -070065 e.unmarshalNeedsValue = true
66 }
67 }
Damien Neilc37adef2019-04-01 13:49:56 -070068 return e
69}
Joe Tsai89d49632019-06-04 16:20:00 -070070
71type ExtensionField struct {
Joe Tsai05e11b82019-06-04 17:05:04 -070072 typ pref.ExtensionType
Joe Tsai89d49632019-06-04 16:20:00 -070073
74 // value is either the value of GetValue,
75 // or a *lazyExtensionValue that then returns the value of GetValue.
Damien Neil68b81c32019-08-22 11:41:32 -070076 value pref.Value
77 lazy *lazyExtensionValue
Joe Tsai89d49632019-06-04 16:20:00 -070078}
79
Damien Neil68b81c32019-08-22 11:41:32 -070080// Set sets the type and value of the extension field.
81// This must not be called concurrently.
82func (f *ExtensionField) Set(t pref.ExtensionType, v pref.Value) {
Joe Tsai05e11b82019-06-04 17:05:04 -070083 f.typ = t
Damien Neil68b81c32019-08-22 11:41:32 -070084 f.value = v
Joe Tsai89d49632019-06-04 16:20:00 -070085}
86
Damien Neil68b81c32019-08-22 11:41:32 -070087// SetLazy sets the type and a value that is to be lazily evaluated upon first use.
88// This must not be called concurrently.
89func (f *ExtensionField) SetLazy(t pref.ExtensionType, fn func() pref.Value) {
90 f.typ = t
91 f.lazy = &lazyExtensionValue{value: fn}
Joe Tsai89d49632019-06-04 16:20:00 -070092}
93
Damien Neil68b81c32019-08-22 11:41:32 -070094// Value returns the value of the extension field.
Joe Tsai89d49632019-06-04 16:20:00 -070095// This may be called concurrently.
Damien Neil68b81c32019-08-22 11:41:32 -070096func (f *ExtensionField) Value() pref.Value {
97 if f.lazy != nil {
98 return f.lazy.GetValue()
Joe Tsai89d49632019-06-04 16:20:00 -070099 }
100 return f.value
101}
102
Damien Neil68b81c32019-08-22 11:41:32 -0700103// Type returns the type of the extension field.
104// This may be called concurrently.
105func (f ExtensionField) Type() pref.ExtensionType {
106 return f.typ
Joe Tsai89d49632019-06-04 16:20:00 -0700107}
108
Damien Neil68b81c32019-08-22 11:41:32 -0700109// IsSet returns whether the extension field is set.
110// This may be called concurrently.
111func (f ExtensionField) IsSet() bool {
112 return f.typ != nil
113}
114
115// Deprecated: Do not use.
116func (f ExtensionField) HasType() bool {
117 return f.typ != nil
118}
119
120// Deprecated: Do not use.
121func (f ExtensionField) GetType() pref.ExtensionType {
122 return f.typ
123}
124
125// Deprecated: Do not use.
126func (f *ExtensionField) SetType(t pref.ExtensionType) {
127 f.typ = t
128}
129
130// Deprecated: Do not use.
131func (f ExtensionField) HasValue() bool {
132 return f.value.IsValid() || f.lazy != nil
133}
134
135// Deprecated: Do not use.
136func (f ExtensionField) GetValue() interface{} {
137 return f.typ.InterfaceOf(f.Value())
138}
139
140// Deprecated: Do not use.
141func (f *ExtensionField) SetEagerValue(ival interface{}) {
142 f.value = f.typ.ValueOf(ival)
143}
144
145// Deprecated: Do not use.
146func (f *ExtensionField) SetLazyValue(fn func() interface{}) {
Joe Tsai8ee364e2019-09-06 00:19:33 -0700147 f.lazy = &lazyExtensionValue{value: func() pref.Value {
Damien Neil68b81c32019-08-22 11:41:32 -0700148 return f.typ.ValueOf(fn())
149 }}
Joe Tsai89d49632019-06-04 16:20:00 -0700150}
151
152type lazyExtensionValue struct {
153 once uint32 // atomically set if value is valid
154 mu sync.Mutex // protects value
Joe Tsai8ee364e2019-09-06 00:19:33 -0700155 value interface{} // either a pref.Value itself or a func() pref.ValueOf
Joe Tsai89d49632019-06-04 16:20:00 -0700156}
157
Damien Neil68b81c32019-08-22 11:41:32 -0700158func (v *lazyExtensionValue) GetValue() pref.Value {
Joe Tsai89d49632019-06-04 16:20:00 -0700159 if atomic.LoadUint32(&v.once) == 0 {
160 v.mu.Lock()
Damien Neil68b81c32019-08-22 11:41:32 -0700161 if f, ok := v.value.(func() pref.Value); ok {
Joe Tsai89d49632019-06-04 16:20:00 -0700162 v.value = f()
163 }
164 atomic.StoreUint32(&v.once, 1)
165 v.mu.Unlock()
166 }
Damien Neil68b81c32019-08-22 11:41:32 -0700167 return v.value.(pref.Value)
Joe Tsai89d49632019-06-04 16:20:00 -0700168}