blob: e904fd993657c613484e0b3d127cd7cdb1548c87 [file] [log] [blame]
David K. Bainbridgebd6b2882021-08-26 13:31:02 +00001// 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}