123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- // Copyright 2019 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package impl
- import (
- "sync"
- "sync/atomic"
- "google.golang.org/protobuf/internal/encoding/wire"
- pref "google.golang.org/protobuf/reflect/protoreflect"
- )
- type extensionFieldInfo struct {
- wiretag uint64
- tagsize int
- unmarshalNeedsValue bool
- funcs valueCoderFuncs
- }
- func (mi *MessageInfo) extensionFieldInfo(xt pref.ExtensionType) *extensionFieldInfo {
- // As of this time (Go 1.12, linux/amd64), an RWMutex benchmarks as faster
- // than a sync.Map.
- mi.extensionFieldInfosMu.RLock()
- e, ok := mi.extensionFieldInfos[xt]
- mi.extensionFieldInfosMu.RUnlock()
- if ok {
- return e
- }
- xd := xt.TypeDescriptor()
- var wiretag uint64
- if !xd.IsPacked() {
- wiretag = wire.EncodeTag(xd.Number(), wireTypes[xd.Kind()])
- } else {
- wiretag = wire.EncodeTag(xd.Number(), wire.BytesType)
- }
- e = &extensionFieldInfo{
- wiretag: wiretag,
- tagsize: wire.SizeVarint(wiretag),
- funcs: encoderFuncsForValue(xd),
- }
- // Does the unmarshal function need a value passed to it?
- // This is true for composite types, where we pass in a message, list, or map to fill in,
- // and for enums, where we pass in a prototype value to specify the concrete enum type.
- switch xd.Kind() {
- case pref.MessageKind, pref.GroupKind, pref.EnumKind:
- e.unmarshalNeedsValue = true
- default:
- if xd.Cardinality() == pref.Repeated {
- e.unmarshalNeedsValue = true
- }
- }
- mi.extensionFieldInfosMu.Lock()
- if mi.extensionFieldInfos == nil {
- mi.extensionFieldInfos = make(map[pref.ExtensionType]*extensionFieldInfo)
- }
- mi.extensionFieldInfos[xt] = e
- mi.extensionFieldInfosMu.Unlock()
- return e
- }
- type ExtensionField struct {
- typ pref.ExtensionType
- // value is either the value of GetValue,
- // or a *lazyExtensionValue that then returns the value of GetValue.
- value pref.Value
- lazy *lazyExtensionValue
- }
- // Set sets the type and value of the extension field.
- // This must not be called concurrently.
- func (f *ExtensionField) Set(t pref.ExtensionType, v pref.Value) {
- f.typ = t
- f.value = v
- }
- // SetLazy sets the type and a value that is to be lazily evaluated upon first use.
- // This must not be called concurrently.
- func (f *ExtensionField) SetLazy(t pref.ExtensionType, fn func() pref.Value) {
- f.typ = t
- f.lazy = &lazyExtensionValue{value: fn}
- }
- // Value returns the value of the extension field.
- // This may be called concurrently.
- func (f *ExtensionField) Value() pref.Value {
- if f.lazy != nil {
- return f.lazy.GetValue()
- }
- return f.value
- }
- // Type returns the type of the extension field.
- // This may be called concurrently.
- func (f ExtensionField) Type() pref.ExtensionType {
- return f.typ
- }
- // IsSet returns whether the extension field is set.
- // This may be called concurrently.
- func (f ExtensionField) IsSet() bool {
- return f.typ != nil
- }
- // Deprecated: Do not use.
- func (f ExtensionField) HasType() bool {
- return f.typ != nil
- }
- // Deprecated: Do not use.
- func (f ExtensionField) GetType() pref.ExtensionType {
- return f.typ
- }
- // Deprecated: Do not use.
- func (f *ExtensionField) SetType(t pref.ExtensionType) {
- f.typ = t
- }
- // Deprecated: Do not use.
- func (f ExtensionField) HasValue() bool {
- return f.value.IsValid() || f.lazy != nil
- }
- // Deprecated: Do not use.
- func (f ExtensionField) GetValue() interface{} {
- return f.typ.InterfaceOf(f.Value())
- }
- // Deprecated: Do not use.
- func (f *ExtensionField) SetEagerValue(ival interface{}) {
- f.value = f.typ.ValueOf(ival)
- }
- // Deprecated: Do not use.
- func (f *ExtensionField) SetLazyValue(fn func() interface{}) {
- f.lazy = &lazyExtensionValue{value: func() pref.Value {
- return f.typ.ValueOf(fn())
- }}
- }
- type lazyExtensionValue struct {
- once uint32 // atomically set if value is valid
- mu sync.Mutex // protects value
- value interface{} // either a pref.Value itself or a func() pref.ValueOf
- }
- func (v *lazyExtensionValue) GetValue() pref.Value {
- if atomic.LoadUint32(&v.once) == 0 {
- v.mu.Lock()
- if f, ok := v.value.(func() pref.Value); ok {
- v.value = f()
- }
- atomic.StoreUint32(&v.once, 1)
- v.mu.Unlock()
- }
- return v.value.(pref.Value)
- }
|