extension.go raw

   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  
   5  package impl
   6  
   7  import (
   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.
  21  type 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.
  80  const (
  81  	extensionInfoUninitialized = 0
  82  	extensionInfoDescInit      = 1
  83  	extensionInfoFullInit      = 2
  84  )
  85  
  86  func 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  
  92  func (xi *ExtensionInfo) New() protoreflect.Value {
  93  	return xi.lazyInit().New()
  94  }
  95  func (xi *ExtensionInfo) Zero() protoreflect.Value {
  96  	return xi.lazyInit().Zero()
  97  }
  98  func (xi *ExtensionInfo) ValueOf(v any) protoreflect.Value {
  99  	return xi.lazyInit().PBValueOf(reflect.ValueOf(v))
 100  }
 101  func (xi *ExtensionInfo) InterfaceOf(v protoreflect.Value) any {
 102  	return xi.lazyInit().GoValueOf(v).Interface()
 103  }
 104  func (xi *ExtensionInfo) IsValidValue(v protoreflect.Value) bool {
 105  	return xi.lazyInit().IsValidPB(v)
 106  }
 107  func (xi *ExtensionInfo) IsValidInterface(v any) bool {
 108  	return xi.lazyInit().IsValidGo(reflect.ValueOf(v))
 109  }
 110  func (xi *ExtensionInfo) TypeDescriptor() protoreflect.ExtensionTypeDescriptor {
 111  	if atomic.LoadUint32(&xi.init) < extensionInfoDescInit {
 112  		xi.lazyInitSlow()
 113  	}
 114  	return &xi.desc
 115  }
 116  
 117  func (xi *ExtensionInfo) lazyInit() Converter {
 118  	if atomic.LoadUint32(&xi.init) < extensionInfoFullInit {
 119  		xi.lazyInitSlow()
 120  	}
 121  	return xi.conv
 122  }
 123  
 124  func (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  
 146  type extensionTypeDescriptor struct {
 147  	protoreflect.ExtensionDescriptor
 148  	xi *ExtensionInfo
 149  }
 150  
 151  func (xtd *extensionTypeDescriptor) Type() protoreflect.ExtensionType {
 152  	return xtd.xi
 153  }
 154  func (xtd *extensionTypeDescriptor) Descriptor() protoreflect.ExtensionDescriptor {
 155  	return xtd.ExtensionDescriptor
 156  }
 157