blob: 1ba473dc37d701413b53537ad813b56afd19b583 [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 {
122 if atomic.LoadUint32(&xi.init) == extensionInfoUninitialized {
123 xi.lazyInitSlow()
124 }
125 return &xi.tdesc
126}
127
128func (xi *ExtensionInfo) lazyInit() Converter {
129 if atomic.LoadUint32(&xi.init) != extensionInfoFullInit {
130 xi.lazyInitSlow()
131 }
132 return xi.conv
133}
134
135func (xi *ExtensionInfo) lazyInitSlow() {
136 xi.mu.Lock()
137 defer xi.mu.Unlock()
138
139 if xi.init == extensionInfoFullInit {
140 return
141 }
142 atomic.StoreUint32(&xi.init, extensionInfoFullInit)
143
144 if xi.desc == nil {
145 xi.initFromLegacy()
146 } else if xi.desc.Cardinality() == pref.Repeated {
147 // Cardinality is initialized lazily, so we defer consulting it until here.
148 xi.goType = reflect.PtrTo(reflect.SliceOf(xi.goType))
149 }
150 xi.conv = NewConverter(xi.goType, xi.desc)
151 xi.tdesc.ExtensionDescriptor = xi.desc
152 xi.tdesc.xi = xi
153
154 if xi.ExtensionType == nil {
155 xi.initToLegacy()
156 }
157}
158
159type extensionTypeDescriptor struct {
160 pref.ExtensionDescriptor
161 xi *ExtensionInfo
162}
163
164func (xtd *extensionTypeDescriptor) Type() pref.ExtensionType {
165 return xtd.xi
166}
167func (xtd *extensionTypeDescriptor) Descriptor() pref.ExtensionDescriptor {
168 return xtd.ExtensionDescriptor
169}