blob: 442628e79c988b1dd620255511b6ba409a74f13d [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
Joe Tsai89d49632019-06-04 16:20:00 -070022func (mi *MessageInfo) extensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
Damien Neilc37adef2019-04-01 13:49:56 -070023 // As of this time (Go 1.12, linux/amd64), an RWMutex benchmarks as faster
24 // than a sync.Map.
25 mi.extensionFieldInfosMu.RLock()
Joe Tsai89d49632019-06-04 16:20:00 -070026 e, ok := mi.extensionFieldInfos[xt]
Damien Neilc37adef2019-04-01 13:49:56 -070027 mi.extensionFieldInfosMu.RUnlock()
28 if ok {
29 return e
30 }
31
Damien Neil79bfdbe2019-08-28 11:08:22 -070032 xd := xt.TypeDescriptor()
Damien Neil7492a092019-07-10 15:23:29 -070033 var wiretag uint64
Damien Neil92f76182019-08-02 16:58:08 -070034 if !xd.IsPacked() {
35 wiretag = wire.EncodeTag(xd.Number(), wireTypes[xd.Kind()])
Damien Neil7492a092019-07-10 15:23:29 -070036 } else {
Damien Neil92f76182019-08-02 16:58:08 -070037 wiretag = wire.EncodeTag(xd.Number(), wire.BytesType)
Damien Neil7492a092019-07-10 15:23:29 -070038 }
Damien Neilc37adef2019-04-01 13:49:56 -070039 e = &extensionFieldInfo{
40 wiretag: wiretag,
41 tagsize: wire.SizeVarint(wiretag),
Damien Neil92f76182019-08-02 16:58:08 -070042 funcs: encoderFuncsForValue(xd, xt.GoType()),
Damien Neilc37adef2019-04-01 13:49:56 -070043 }
Damien Neile91877d2019-06-27 10:54:42 -070044 // Does the unmarshal function need a value passed to it?
45 // This is true for composite types, where we pass in a message, list, or map to fill in,
46 // and for enums, where we pass in a prototype value to specify the concrete enum type.
Damien Neil92f76182019-08-02 16:58:08 -070047 switch xd.Kind() {
Damien Neile91877d2019-06-27 10:54:42 -070048 case pref.MessageKind, pref.GroupKind, pref.EnumKind:
49 e.unmarshalNeedsValue = true
50 default:
Damien Neil92f76182019-08-02 16:58:08 -070051 if xd.Cardinality() == pref.Repeated {
Damien Neile91877d2019-06-27 10:54:42 -070052 e.unmarshalNeedsValue = true
53 }
54 }
Damien Neilc37adef2019-04-01 13:49:56 -070055 mi.extensionFieldInfosMu.Lock()
56 if mi.extensionFieldInfos == nil {
Joe Tsai89d49632019-06-04 16:20:00 -070057 mi.extensionFieldInfos = make(map[pref.ExtensionType]*extensionFieldInfo)
Damien Neilc37adef2019-04-01 13:49:56 -070058 }
Joe Tsai89d49632019-06-04 16:20:00 -070059 mi.extensionFieldInfos[xt] = e
Damien Neilc37adef2019-04-01 13:49:56 -070060 mi.extensionFieldInfosMu.Unlock()
61 return e
62}
Joe Tsai89d49632019-06-04 16:20:00 -070063
64type ExtensionField struct {
Joe Tsai05e11b82019-06-04 17:05:04 -070065 typ pref.ExtensionType
Joe Tsai89d49632019-06-04 16:20:00 -070066
67 // value is either the value of GetValue,
68 // or a *lazyExtensionValue that then returns the value of GetValue.
Damien Neil68b81c32019-08-22 11:41:32 -070069 value pref.Value
70 lazy *lazyExtensionValue
Joe Tsai89d49632019-06-04 16:20:00 -070071}
72
Damien Neil68b81c32019-08-22 11:41:32 -070073// Set sets the type and value of the extension field.
74// This must not be called concurrently.
75func (f *ExtensionField) Set(t pref.ExtensionType, v pref.Value) {
Joe Tsai05e11b82019-06-04 17:05:04 -070076 f.typ = t
Damien Neil68b81c32019-08-22 11:41:32 -070077 f.value = v
Joe Tsai89d49632019-06-04 16:20:00 -070078}
79
Damien Neil68b81c32019-08-22 11:41:32 -070080// SetLazy sets the type and a value that is to be lazily evaluated upon first use.
81// This must not be called concurrently.
82func (f *ExtensionField) SetLazy(t pref.ExtensionType, fn func() pref.Value) {
83 f.typ = t
84 f.lazy = &lazyExtensionValue{value: fn}
Joe Tsai89d49632019-06-04 16:20:00 -070085}
86
Damien Neil68b81c32019-08-22 11:41:32 -070087// Value returns the value of the extension field.
Joe Tsai89d49632019-06-04 16:20:00 -070088// This may be called concurrently.
Damien Neil68b81c32019-08-22 11:41:32 -070089func (f *ExtensionField) Value() pref.Value {
90 if f.lazy != nil {
91 return f.lazy.GetValue()
Joe Tsai89d49632019-06-04 16:20:00 -070092 }
93 return f.value
94}
95
Damien Neil68b81c32019-08-22 11:41:32 -070096// Type returns the type of the extension field.
97// This may be called concurrently.
98func (f ExtensionField) Type() pref.ExtensionType {
99 return f.typ
Joe Tsai89d49632019-06-04 16:20:00 -0700100}
101
Damien Neil68b81c32019-08-22 11:41:32 -0700102// IsSet returns whether the extension field is set.
103// This may be called concurrently.
104func (f ExtensionField) IsSet() bool {
105 return f.typ != nil
106}
107
108// Deprecated: Do not use.
109func (f ExtensionField) HasType() bool {
110 return f.typ != nil
111}
112
113// Deprecated: Do not use.
114func (f ExtensionField) GetType() pref.ExtensionType {
115 return f.typ
116}
117
118// Deprecated: Do not use.
119func (f *ExtensionField) SetType(t pref.ExtensionType) {
120 f.typ = t
121}
122
123// Deprecated: Do not use.
124func (f ExtensionField) HasValue() bool {
125 return f.value.IsValid() || f.lazy != nil
126}
127
128// Deprecated: Do not use.
129func (f ExtensionField) GetValue() interface{} {
130 return f.typ.InterfaceOf(f.Value())
131}
132
133// Deprecated: Do not use.
134func (f *ExtensionField) SetEagerValue(ival interface{}) {
135 f.value = f.typ.ValueOf(ival)
136}
137
138// Deprecated: Do not use.
139func (f *ExtensionField) SetLazyValue(fn func() interface{}) {
140 f.lazy = &lazyExtensionValue{value: func() interface{} {
141 return f.typ.ValueOf(fn())
142 }}
Joe Tsai89d49632019-06-04 16:20:00 -0700143}
144
145type lazyExtensionValue struct {
146 once uint32 // atomically set if value is valid
147 mu sync.Mutex // protects value
148 value interface{} // either the value itself or a func() interface{}
149}
150
Damien Neil68b81c32019-08-22 11:41:32 -0700151func (v *lazyExtensionValue) GetValue() pref.Value {
Joe Tsai89d49632019-06-04 16:20:00 -0700152 if atomic.LoadUint32(&v.once) == 0 {
153 v.mu.Lock()
Damien Neil68b81c32019-08-22 11:41:32 -0700154 if f, ok := v.value.(func() pref.Value); ok {
Joe Tsai89d49632019-06-04 16:20:00 -0700155 v.value = f()
156 }
157 atomic.StoreUint32(&v.once, 1)
158 v.mu.Unlock()
159 }
Damien Neil68b81c32019-08-22 11:41:32 -0700160 return v.value.(pref.Value)
Joe Tsai89d49632019-06-04 16:20:00 -0700161}