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	pref "google.golang.org/protobuf/reflect/protoreflect"
13	piface "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 piface.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 interface{}
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 pref.ExtensionDescriptor, goType reflect.Type) {
87	xi.goType = goType
88	xi.desc = extensionTypeDescriptor{xd, xi}
89	xi.init = extensionInfoDescInit
90}
91
92func (xi *ExtensionInfo) New() pref.Value {
93	return xi.lazyInit().New()
94}
95func (xi *ExtensionInfo) Zero() pref.Value {
96	return xi.lazyInit().Zero()
97}
98func (xi *ExtensionInfo) ValueOf(v interface{}) pref.Value {
99	return xi.lazyInit().PBValueOf(reflect.ValueOf(v))
100}
101func (xi *ExtensionInfo) InterfaceOf(v pref.Value) interface{} {
102	return xi.lazyInit().GoValueOf(v).Interface()
103}
104func (xi *ExtensionInfo) IsValidValue(v pref.Value) bool {
105	return xi.lazyInit().IsValidPB(v)
106}
107func (xi *ExtensionInfo) IsValidInterface(v interface{}) bool {
108	return xi.lazyInit().IsValidGo(reflect.ValueOf(v))
109}
110func (xi *ExtensionInfo) TypeDescriptor() pref.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	pref.ExtensionDescriptor
148	xi *ExtensionInfo
149}
150
151func (xtd *extensionTypeDescriptor) Type() pref.ExtensionType {
152	return xtd.xi
153}
154func (xtd *extensionTypeDescriptor) Descriptor() pref.ExtensionDescriptor {
155	return xtd.ExtensionDescriptor
156}
157