extension.go

  1// 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 (
  8	"reflect"
  9	"sync"
 10	"sync/atomic"
 11
 12	"google.golang.org/protobuf/reflect/protoreflect"
 13	"google.golang.org/protobuf/runtime/protoiface"
 14)
 15
 16// ExtensionInfo implements ExtensionType.
 17//
 18// This type contains a number of exported fields for legacy compatibility.
 19// The only non-deprecated use of this type is through the methods of the
 20// ExtensionType interface.
 21type ExtensionInfo struct {
 22	// An ExtensionInfo may exist in several stages of initialization.
 23	//
 24	// extensionInfoUninitialized: Some or all of the legacy exported
 25	// fields may be set, but none of the unexported fields have been
 26	// initialized. This is the starting state for an ExtensionInfo
 27	// in legacy generated code.
 28	//
 29	// extensionInfoDescInit: The desc field is set, but other unexported fields
 30	// may not be initialized. Legacy exported fields may or may not be set.
 31	// This is the starting state for an ExtensionInfo in newly generated code.
 32	//
 33	// extensionInfoFullInit: The ExtensionInfo is fully initialized.
 34	// This state is only entered after lazy initialization is complete.
 35	init uint32
 36	mu   sync.Mutex
 37
 38	goType reflect.Type
 39	desc   extensionTypeDescriptor
 40	conv   Converter
 41	info   *extensionFieldInfo // for fast-path method implementations
 42
 43	// ExtendedType is a typed nil-pointer to the parent message type that
 44	// is being extended. It is possible for this to be unpopulated in v2
 45	// since the message may no longer implement the MessageV1 interface.
 46	//
 47	// Deprecated: Use the ExtendedType method instead.
 48	ExtendedType protoiface.MessageV1
 49
 50	// ExtensionType is the zero value of the extension type.
 51	//
 52	// For historical reasons, reflect.TypeOf(ExtensionType) and the
 53	// type returned by InterfaceOf may not be identical.
 54	//
 55	// Deprecated: Use InterfaceOf(xt.Zero()) instead.
 56	ExtensionType any
 57
 58	// Field is the field number of the extension.
 59	//
 60	// Deprecated: Use the Descriptor().Number method instead.
 61	Field int32
 62
 63	// Name is the fully qualified name of extension.
 64	//
 65	// Deprecated: Use the Descriptor().FullName method instead.
 66	Name string
 67
 68	// Tag is the protobuf struct tag used in the v1 API.
 69	//
 70	// Deprecated: Do not use.
 71	Tag string
 72
 73	// Filename is the proto filename in which the extension is defined.
 74	//
 75	// Deprecated: Use Descriptor().ParentFile().Path() instead.
 76	Filename string
 77}
 78
 79// Stages of initialization: See the ExtensionInfo.init field.
 80const (
 81	extensionInfoUninitialized = 0
 82	extensionInfoDescInit      = 1
 83	extensionInfoFullInit      = 2
 84)
 85
 86func InitExtensionInfo(xi *ExtensionInfo, xd protoreflect.ExtensionDescriptor, goType reflect.Type) {
 87	xi.goType = goType
 88	xi.desc = extensionTypeDescriptor{xd, xi}
 89	xi.init = extensionInfoDescInit
 90}
 91
 92func (xi *ExtensionInfo) New() protoreflect.Value {
 93	return xi.lazyInit().New()
 94}
 95func (xi *ExtensionInfo) Zero() protoreflect.Value {
 96	return xi.lazyInit().Zero()
 97}
 98func (xi *ExtensionInfo) ValueOf(v any) protoreflect.Value {
 99	return xi.lazyInit().PBValueOf(reflect.ValueOf(v))
100}
101func (xi *ExtensionInfo) InterfaceOf(v protoreflect.Value) any {
102	return xi.lazyInit().GoValueOf(v).Interface()
103}
104func (xi *ExtensionInfo) IsValidValue(v protoreflect.Value) bool {
105	return xi.lazyInit().IsValidPB(v)
106}
107func (xi *ExtensionInfo) IsValidInterface(v any) bool {
108	return xi.lazyInit().IsValidGo(reflect.ValueOf(v))
109}
110func (xi *ExtensionInfo) TypeDescriptor() protoreflect.ExtensionTypeDescriptor {
111	if atomic.LoadUint32(&xi.init) < extensionInfoDescInit {
112		xi.lazyInitSlow()
113	}
114	return &xi.desc
115}
116
117func (xi *ExtensionInfo) lazyInit() Converter {
118	if atomic.LoadUint32(&xi.init) < extensionInfoFullInit {
119		xi.lazyInitSlow()
120	}
121	return xi.conv
122}
123
124func (xi *ExtensionInfo) lazyInitSlow() {
125	xi.mu.Lock()
126	defer xi.mu.Unlock()
127
128	if xi.init == extensionInfoFullInit {
129		return
130	}
131	defer atomic.StoreUint32(&xi.init, extensionInfoFullInit)
132
133	if xi.desc.ExtensionDescriptor == nil {
134		xi.initFromLegacy()
135	}
136	if !xi.desc.ExtensionDescriptor.IsPlaceholder() {
137		if xi.ExtensionType == nil {
138			xi.initToLegacy()
139		}
140		xi.conv = NewConverter(xi.goType, xi.desc.ExtensionDescriptor)
141		xi.info = makeExtensionFieldInfo(xi.desc.ExtensionDescriptor)
142		xi.info.validation = newValidationInfo(xi.desc.ExtensionDescriptor, xi.goType)
143	}
144}
145
146type extensionTypeDescriptor struct {
147	protoreflect.ExtensionDescriptor
148	xi *ExtensionInfo
149}
150
151func (xtd *extensionTypeDescriptor) Type() protoreflect.ExtensionType {
152	return xtd.xi
153}
154func (xtd *extensionTypeDescriptor) Descriptor() protoreflect.ExtensionDescriptor {
155	return xtd.ExtensionDescriptor
156}