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