blob: e7083e52811ca1341ecc9e391b5e93bbc7852514 [file] [log] [blame]
Damien Neilf1e905b2019-08-08 15:45:59 -07001// 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 and tdesc fields have been
30 // set, but the descriptor is not otherwise initialized. Legacy
31 // exported fields may or may not be set. This is the starting state
32 // for an ExtensionInfo in new generated code. Calling the Descriptor
33 // method will not trigger lazy initialization, although any other
34 // method will.
35 //
36 // extensionInfoFullInit: The ExtensionInfo is fully initialized.
37 // This state is only entered after lazy initialization is complete.
38 init uint32
39 mu sync.Mutex
40
41 desc pref.ExtensionDescriptor
42 tdesc extensionTypeDescriptor
43 goType reflect.Type
44 conv Converter
45
46 // TODO: Remove after updating v2 to not set this.
47 Type interface{}
48
49 // ExtendedType is a typed nil-pointer to the parent message type that
50 // is being extended. It is possible for this to be unpopulated in v2
51 // since the message may no longer implement the MessageV1 interface.
52 //
53 // Deprecated: Use the ExtendedType method instead.
54 ExtendedType piface.MessageV1
55
56 // ExtensionType is zero value of the extension type.
57 //
58 // For historical reasons, reflect.TypeOf(ExtensionType) and Type.GoType
59 // may not be identical:
60 // * for scalars (except []byte), where ExtensionType uses *T,
61 // while Type.GoType uses T.
62 // * for repeated fields, where ExtensionType uses []T,
63 // while Type.GoType uses *[]T.
64 //
65 // Deprecated: Use the GoType method instead.
66 ExtensionType interface{}
67
68 // Field is the field number of the extension.
69 //
70 // Deprecated: Use the Descriptor().Number method instead.
71 Field int32
72
73 // Name is the fully qualified name of extension.
74 //
75 // Deprecated: Use the Descriptor().FullName method instead.
76 Name string
77
78 // Tag is the protobuf struct tag used in the v1 API.
79 //
80 // Deprecated: Do not use.
81 Tag string
82
83 // Filename is the proto filename in which the extension is defined.
84 //
85 // Deprecated: Use Descriptor().ParentFile().Path() instead.
86 Filename string
87}
88
89// Stages of initialization: See the ExtensionInfo.init field.
90const (
91 extensionInfoUninitialized = 0
92 extensionInfoDescInit = 1
93 extensionInfoFullInit = 2
94)
95
96func InitExtensionInfo(xi *ExtensionInfo, xd pref.ExtensionDescriptor, goType reflect.Type) {
97 if xi.desc != nil {
98 return
99 }
100 xi.desc = xd
101 xi.goType = goType
102
103 xi.tdesc.ExtensionDescriptor = xi.desc
104 xi.tdesc.xi = xi
105 xi.init = extensionInfoDescInit
106}
107
108func (xi *ExtensionInfo) New() pref.Value {
109 return xi.lazyInit().New()
110}
111func (xi *ExtensionInfo) Zero() pref.Value {
112 return xi.lazyInit().Zero()
113}
114func (xi *ExtensionInfo) ValueOf(v interface{}) pref.Value {
115 return xi.lazyInit().PBValueOf(reflect.ValueOf(v))
116}
117func (xi *ExtensionInfo) InterfaceOf(v pref.Value) interface{} {
118 return xi.lazyInit().GoValueOf(v).Interface()
119}
120func (xi *ExtensionInfo) GoType() reflect.Type {
121 xi.lazyInit()
122 return xi.goType
123}
124func (xi *ExtensionInfo) Descriptor() pref.ExtensionTypeDescriptor {
125 if atomic.LoadUint32(&xi.init) == extensionInfoUninitialized {
126 xi.lazyInitSlow()
127 }
128 return &xi.tdesc
129}
130
131func (xi *ExtensionInfo) lazyInit() Converter {
132 if atomic.LoadUint32(&xi.init) != extensionInfoFullInit {
133 xi.lazyInitSlow()
134 }
135 return xi.conv
136}
137
138func (xi *ExtensionInfo) lazyInitSlow() {
139 xi.mu.Lock()
140 defer xi.mu.Unlock()
141
142 if xi.init == extensionInfoFullInit {
143 return
144 }
145 atomic.StoreUint32(&xi.init, extensionInfoFullInit)
146
147 if xi.desc == nil {
148 xi.initFromLegacy()
149 } else if xi.desc.Cardinality() == pref.Repeated {
150 // Cardinality is initialized lazily, so we defer consulting it until here.
151 xi.goType = reflect.PtrTo(reflect.SliceOf(xi.goType))
152 }
153 xi.conv = NewConverter(xi.goType, xi.desc)
154 xi.tdesc.ExtensionDescriptor = xi.desc
155 xi.tdesc.xi = xi
156
157 if xi.ExtensionType == nil {
158 xi.initToLegacy()
159 }
160}
161
162type extensionTypeDescriptor struct {
163 pref.ExtensionDescriptor
164 xi *ExtensionInfo
165}
166
167func (xtd *extensionTypeDescriptor) Type() pref.ExtensionType {
168 return xtd.xi
169}
170func (xtd *extensionTypeDescriptor) Descriptor() pref.ExtensionDescriptor {
171 return xtd.ExtensionDescriptor
172}