blob: 22a25dc8b8e0eb373174b7da059e4c71c6597086 [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 Neilc37adef2019-04-01 13:49:56 -070020}
21
Damien Neil79571e92019-12-09 10:24:36 -080022var legacyExtensionFieldInfoCache sync.Map // map[protoreflect.ExtensionType]*extensionFieldInfo
Damien Neilc37adef2019-04-01 13:49:56 -070023
Damien Neil79571e92019-12-09 10:24:36 -080024func getExtensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
25 if xi, ok := xt.(*ExtensionInfo); ok {
26 xi.lazyInit()
27 return xi.info
28 }
29 return legacyLoadExtensionFieldInfo(xt)
30}
31
32// legacyLoadExtensionFieldInfo dynamically loads a *ExtensionInfo for xt.
33func legacyLoadExtensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
34 if xi, ok := legacyExtensionFieldInfoCache.Load(xt); ok {
35 return xi.(*extensionFieldInfo)
36 }
37 e := makeExtensionFieldInfo(xt.TypeDescriptor())
38 if e, ok := legacyMessageTypeCache.LoadOrStore(xt, e); ok {
39 return e.(*extensionFieldInfo)
40 }
41 return e
42}
43
44func makeExtensionFieldInfo(xd pref.ExtensionDescriptor) *extensionFieldInfo {
Damien Neil7492a092019-07-10 15:23:29 -070045 var wiretag uint64
Damien Neil92f76182019-08-02 16:58:08 -070046 if !xd.IsPacked() {
47 wiretag = wire.EncodeTag(xd.Number(), wireTypes[xd.Kind()])
Damien Neil7492a092019-07-10 15:23:29 -070048 } else {
Damien Neil92f76182019-08-02 16:58:08 -070049 wiretag = wire.EncodeTag(xd.Number(), wire.BytesType)
Damien Neil7492a092019-07-10 15:23:29 -070050 }
Damien Neil79571e92019-12-09 10:24:36 -080051 e := &extensionFieldInfo{
Damien Neilc37adef2019-04-01 13:49:56 -070052 wiretag: wiretag,
53 tagsize: wire.SizeVarint(wiretag),
Damien Neil4b3a82f2019-09-04 19:07:00 -070054 funcs: encoderFuncsForValue(xd),
Damien Neilc37adef2019-04-01 13:49:56 -070055 }
Damien Neile91877d2019-06-27 10:54:42 -070056 // Does the unmarshal function need a value passed to it?
57 // This is true for composite types, where we pass in a message, list, or map to fill in,
58 // and for enums, where we pass in a prototype value to specify the concrete enum type.
Damien Neil92f76182019-08-02 16:58:08 -070059 switch xd.Kind() {
Damien Neile91877d2019-06-27 10:54:42 -070060 case pref.MessageKind, pref.GroupKind, pref.EnumKind:
61 e.unmarshalNeedsValue = true
62 default:
Damien Neil92f76182019-08-02 16:58:08 -070063 if xd.Cardinality() == pref.Repeated {
Damien Neile91877d2019-06-27 10:54:42 -070064 e.unmarshalNeedsValue = true
65 }
66 }
Damien Neilc37adef2019-04-01 13:49:56 -070067 return e
68}
Joe Tsai89d49632019-06-04 16:20:00 -070069
70type ExtensionField struct {
Joe Tsai05e11b82019-06-04 17:05:04 -070071 typ pref.ExtensionType
Joe Tsai89d49632019-06-04 16:20:00 -070072
73 // value is either the value of GetValue,
74 // or a *lazyExtensionValue that then returns the value of GetValue.
Damien Neil68b81c32019-08-22 11:41:32 -070075 value pref.Value
76 lazy *lazyExtensionValue
Joe Tsai89d49632019-06-04 16:20:00 -070077}
78
Damien Neil68b81c32019-08-22 11:41:32 -070079// Set sets the type and value of the extension field.
80// This must not be called concurrently.
81func (f *ExtensionField) Set(t pref.ExtensionType, v pref.Value) {
Joe Tsai05e11b82019-06-04 17:05:04 -070082 f.typ = t
Damien Neil68b81c32019-08-22 11:41:32 -070083 f.value = v
Joe Tsai89d49632019-06-04 16:20:00 -070084}
85
Damien Neil68b81c32019-08-22 11:41:32 -070086// SetLazy sets the type and a value that is to be lazily evaluated upon first use.
87// This must not be called concurrently.
88func (f *ExtensionField) SetLazy(t pref.ExtensionType, fn func() pref.Value) {
89 f.typ = t
90 f.lazy = &lazyExtensionValue{value: fn}
Joe Tsai89d49632019-06-04 16:20:00 -070091}
92
Damien Neil68b81c32019-08-22 11:41:32 -070093// Value returns the value of the extension field.
Joe Tsai89d49632019-06-04 16:20:00 -070094// This may be called concurrently.
Damien Neil68b81c32019-08-22 11:41:32 -070095func (f *ExtensionField) Value() pref.Value {
96 if f.lazy != nil {
97 return f.lazy.GetValue()
Joe Tsai89d49632019-06-04 16:20:00 -070098 }
99 return f.value
100}
101
Damien Neil68b81c32019-08-22 11:41:32 -0700102// Type returns the type of the extension field.
103// This may be called concurrently.
104func (f ExtensionField) Type() pref.ExtensionType {
105 return f.typ
Joe Tsai89d49632019-06-04 16:20:00 -0700106}
107
Damien Neil68b81c32019-08-22 11:41:32 -0700108// IsSet returns whether the extension field is set.
109// This may be called concurrently.
110func (f ExtensionField) IsSet() bool {
111 return f.typ != nil
112}
113
114// Deprecated: Do not use.
115func (f ExtensionField) HasType() bool {
116 return f.typ != nil
117}
118
119// Deprecated: Do not use.
120func (f ExtensionField) GetType() pref.ExtensionType {
121 return f.typ
122}
123
124// Deprecated: Do not use.
125func (f *ExtensionField) SetType(t pref.ExtensionType) {
126 f.typ = t
127}
128
129// Deprecated: Do not use.
130func (f ExtensionField) HasValue() bool {
131 return f.value.IsValid() || f.lazy != nil
132}
133
134// Deprecated: Do not use.
135func (f ExtensionField) GetValue() interface{} {
136 return f.typ.InterfaceOf(f.Value())
137}
138
139// Deprecated: Do not use.
140func (f *ExtensionField) SetEagerValue(ival interface{}) {
141 f.value = f.typ.ValueOf(ival)
142}
143
144// Deprecated: Do not use.
145func (f *ExtensionField) SetLazyValue(fn func() interface{}) {
Joe Tsai8ee364e2019-09-06 00:19:33 -0700146 f.lazy = &lazyExtensionValue{value: func() pref.Value {
Damien Neil68b81c32019-08-22 11:41:32 -0700147 return f.typ.ValueOf(fn())
148 }}
Joe Tsai89d49632019-06-04 16:20:00 -0700149}
150
151type lazyExtensionValue struct {
152 once uint32 // atomically set if value is valid
153 mu sync.Mutex // protects value
Joe Tsai8ee364e2019-09-06 00:19:33 -0700154 value interface{} // either a pref.Value itself or a func() pref.ValueOf
Joe Tsai89d49632019-06-04 16:20:00 -0700155}
156
Damien Neil68b81c32019-08-22 11:41:32 -0700157func (v *lazyExtensionValue) GetValue() pref.Value {
Joe Tsai89d49632019-06-04 16:20:00 -0700158 if atomic.LoadUint32(&v.once) == 0 {
159 v.mu.Lock()
Damien Neil68b81c32019-08-22 11:41:32 -0700160 if f, ok := v.value.(func() pref.Value); ok {
Joe Tsai89d49632019-06-04 16:20:00 -0700161 v.value = f()
162 }
163 atomic.StoreUint32(&v.once, 1)
164 v.mu.Unlock()
165 }
Damien Neil68b81c32019-08-22 11:41:32 -0700166 return v.value.(pref.Value)
Joe Tsai89d49632019-06-04 16:20:00 -0700167}