1
1
// Take a look at the license at the top of the repository in the LICENSE file.
2
2
3
+ use heck:: ToShoutySnakeCase ;
3
4
use proc_macro2:: TokenStream ;
4
5
use proc_macro_error:: abort_call_site;
5
- use quote:: { quote, ToTokens } ;
6
+ use quote:: { format_ident , quote, ToTokens } ;
6
7
7
8
use crate :: utils:: { parse_optional_nested_meta_items, NestedMetaItem } ;
8
9
@@ -21,6 +22,18 @@ pub fn impl_object_interface(input: &mut syn::ItemImpl) -> TokenStream {
21
22
..
22
23
} = input;
23
24
25
+ let self_ty_as_ident = match & * * self_ty {
26
+ syn:: Type :: Path ( syn:: TypePath { path, .. } ) => path. require_ident ( ) ,
27
+ _ => Err ( syn:: Error :: new (
28
+ syn:: spanned:: Spanned :: span ( self_ty) ,
29
+ "expected this path to be an identifier" ,
30
+ ) ) ,
31
+ } ;
32
+ let self_ty = match self_ty_as_ident {
33
+ Ok ( ident) => ident,
34
+ Err ( e) => return e. to_compile_error ( ) ,
35
+ } ;
36
+
24
37
let mut plugin_type = NestedMetaItem :: < syn:: Path > :: new ( "plugin_type" ) . value_required ( ) ;
25
38
let mut lazy_registration =
26
39
NestedMetaItem :: < syn:: LitBool > :: new ( "lazy_registration" ) . value_required ( ) ;
@@ -95,7 +108,7 @@ pub fn impl_object_interface(input: &mut syn::ItemImpl) -> TokenStream {
95
108
// Registers the object interface as a static type.
96
109
fn register_object_interface_as_static (
97
110
crate_ident : & TokenStream ,
98
- self_ty : & syn:: Type ,
111
+ self_ty : & syn:: Ident ,
99
112
) -> TokenStream {
100
113
// registers the interface on first use (lazy registration).
101
114
quote ! {
@@ -122,7 +135,7 @@ fn register_object_interface_as_static(
122
135
// An object interface can be reregistered as a dynamic type.
123
136
fn register_object_interface_as_dynamic (
124
137
crate_ident : & TokenStream ,
125
- self_ty : & syn:: Type ,
138
+ self_ty : & syn:: Ident ,
126
139
plugin_ty : TokenStream ,
127
140
lazy_registration : bool ,
128
141
) -> TokenStream {
@@ -132,32 +145,40 @@ fn register_object_interface_as_dynamic(
132
145
// registers the object interface as a dynamic type on the first use (lazy registration).
133
146
// a weak reference on the plugin is stored and will be used later on the first use of the object interface.
134
147
// this implementation relies on a static storage of a weak reference on the plugin and of the GLib type to know if the object interface has been registered.
148
+
149
+ // the registration status type.
150
+ let registration_status_type = format_ident ! ( "{}RegistrationStatus" , self_ty) ;
151
+ // name of the static variable to store the registration status.
152
+ let registration_status = format_ident ! (
153
+ "{}" ,
154
+ registration_status_type. to_string( ) . to_shouty_snake_case( )
155
+ ) ;
156
+
135
157
quote ! {
136
- impl #self_ty {
137
- /// Returns a mutable reference to the registration status: a tuple of the weak reference on the plugin and of the GLib type.
138
- /// This is safe because the mutable reference guarantees that no other threads are concurrently accessing the data.
139
- #[ inline]
140
- fn get_registration_status_ref_mut( ) -> & ' static mut Option <( <#plugin_ty as #crate_ident:: clone:: Downgrade >:: Weak , #crate_ident:: Type ) > {
141
- static mut REGISTRATION_STATUS : :: std:: sync:: Mutex <Option <( <#plugin_ty as #crate_ident:: clone:: Downgrade >:: Weak , #crate_ident:: Type ) >> = :: std:: sync:: Mutex :: new( None ) ;
142
- unsafe { REGISTRATION_STATUS . get_mut( ) . unwrap( ) }
143
- }
158
+ /// The registration status type: a tuple of the weak reference on the plugin and of the GLib type.
159
+ struct #registration_status_type( <#plugin_ty as #crate_ident:: clone:: Downgrade >:: Weak , #crate_ident:: Type ) ;
160
+ unsafe impl Send for #registration_status_type { }
144
161
162
+ /// The registration status protected by a mutex guarantees so that no other threads are concurrently accessing the data.
163
+ static #registration_status: :: std:: sync:: Mutex <Option <#registration_status_type>> = :: std:: sync:: Mutex :: new( None ) ;
164
+
165
+ impl #self_ty {
145
166
/// Registers the object interface as a dynamic type within the plugin only once.
146
167
/// Plugin must have been used at least once.
147
168
/// Do nothing if plugin has never been used or if the object interface is already registered as a dynamic type.
148
169
#[ inline]
149
170
fn register_interface( ) -> #crate_ident:: Type {
150
- let registration_status_ref_mut = Self :: get_registration_status_ref_mut ( ) ;
151
- match registration_status_ref_mut {
171
+ let mut registration_status = #registration_status . lock ( ) . unwrap ( ) ;
172
+ match :: std :: ops :: DerefMut :: deref_mut ( & mut registration_status ) {
152
173
// plugin has never been used, so the object interface cannot be registered as a dynamic type.
153
174
None => #crate_ident:: Type :: INVALID ,
154
175
// plugin has been used and the object interface has not been registered yet, so registers it as a dynamic type.
155
- Some ( ( type_plugin, type_) ) if !type_. is_valid( ) => {
176
+ Some ( #registration_status_type ( type_plugin, type_) ) if !type_. is_valid( ) => {
156
177
* type_ = #crate_ident:: subclass:: register_dynamic_interface:: <#plugin_ty, Self >( & ( type_plugin. upgrade( ) . unwrap( ) ) ) ;
157
178
* type_
158
179
} ,
159
180
// plugin has been used and the object interface has already been registered as a dynamic type.
160
- Some ( ( _, type_) ) => * type_
181
+ Some ( #registration_status_type ( _, type_) ) => * type_
161
182
}
162
183
}
163
184
@@ -168,15 +189,15 @@ fn register_object_interface_as_dynamic(
168
189
/// If plugin is reused (and has reloaded the implementation) and the object interface has not been registered yet as a dynamic type, do nothing.
169
190
#[ inline]
170
191
pub fn on_implementation_load( type_plugin: & #plugin_ty) -> bool {
171
- let registration_status_ref_mut = Self :: get_registration_status_ref_mut ( ) ;
172
- match registration_status_ref_mut {
192
+ let mut registration_status = #registration_status . lock ( ) . unwrap ( ) ;
193
+ match :: std :: ops :: DerefMut :: deref_mut ( & mut registration_status ) {
173
194
// plugin has never been used (this is the first time), so postpones registration of the object interface as a dynamic type on the first use.
174
195
None => {
175
- * registration_status_ref_mut = Some ( ( #crate_ident:: clone:: Downgrade :: downgrade( type_plugin) , #crate_ident:: Type :: INVALID ) ) ;
196
+ * registration_status = Some ( #registration_status_type ( #crate_ident:: clone:: Downgrade :: downgrade( type_plugin) , #crate_ident:: Type :: INVALID ) ) ;
176
197
true
177
198
} ,
178
199
// plugin has been used at least one time and the object interface has been registered as a dynamic type at least one time, so re-registers it.
179
- Some ( ( _, type_) ) if type_. is_valid( ) => {
200
+ Some ( #registration_status_type ( _, type_) ) if type_. is_valid( ) => {
180
201
* type_ = #crate_ident:: subclass:: register_dynamic_interface:: <#plugin_ty, Self >( type_plugin) ;
181
202
type_. is_valid( )
182
203
} ,
@@ -192,15 +213,15 @@ fn register_object_interface_as_dynamic(
192
213
/// Else do nothing.
193
214
#[ inline]
194
215
pub fn on_implementation_unload( type_plugin_: & #plugin_ty) -> bool {
195
- let registration_status_ref_mut = Self :: get_registration_status_ref_mut ( ) ;
196
- match registration_status_ref_mut {
216
+ let mut registration_status = #registration_status . lock ( ) . unwrap ( ) ;
217
+ match :: std :: ops :: DerefMut :: deref_mut ( & mut registration_status ) {
197
218
// plugin has never been used, so unload implementation is unexpected.
198
219
None => false ,
199
220
// plugin has been used at least one time and the object interface has been registered as a dynamic type at least one time.
200
- Some ( ( _, type_) ) if type_. is_valid( ) => true ,
221
+ Some ( #registration_status_type ( _, type_) ) if type_. is_valid( ) => true ,
201
222
// plugin has been used at least one time but the object interface has not been registered yet as a dynamic type, so cancels the postponed registration.
202
223
Some ( _) => {
203
- * registration_status_ref_mut = None ;
224
+ * registration_status = None ;
204
225
true
205
226
}
206
227
}
@@ -209,29 +230,29 @@ fn register_object_interface_as_dynamic(
209
230
}
210
231
} else {
211
232
// registers immediately the object interface as a dynamic type.
233
+
234
+ // name of the static variable to store the GLib type.
235
+ let gtype_status = format_ident ! ( "{}_G_TYPE" , self_ty. to_string( ) . to_shouty_snake_case( ) ) ;
236
+
212
237
quote ! {
213
- impl #self_ty {
214
- /// Returns a mutable reference to the GLib type.
215
- /// This is safe because the mutable reference guarantees that no other threads are concurrently accessing the atomic data.
216
- #[ inline]
217
- fn get_type_mut( ) -> & ' static mut #crate_ident:: ffi:: GType {
218
- static mut TYPE : :: std:: sync:: atomic:: AtomicUsize = :: std:: sync:: atomic:: AtomicUsize :: new( #crate_ident:: gobject_ffi:: G_TYPE_INVALID ) ;
219
- unsafe { TYPE . get_mut( ) }
220
- }
238
+ /// The GLib type which can be safely shared between threads.
239
+ static #gtype_status: :: std:: sync:: atomic:: AtomicUsize = :: std:: sync:: atomic:: AtomicUsize :: new( #crate_ident:: gobject_ffi:: G_TYPE_INVALID ) ;
221
240
241
+ impl #self_ty {
222
242
/// Do nothing as the object interface has been registered on implementation load.
223
243
#[ inline]
224
244
fn register_interface( ) -> #crate_ident:: Type {
225
- unsafe { <#crate_ident:: Type as #crate_ident:: translate:: FromGlib <#crate_ident:: ffi:: GType >>:: from_glib( * Self :: get_type_mut( ) ) }
245
+ let gtype = #gtype_status. load( :: std:: sync:: atomic:: Ordering :: Acquire ) ;
246
+ unsafe { <#crate_ident:: Type as #crate_ident:: translate:: FromGlib <#crate_ident:: ffi:: GType >>:: from_glib( gtype) }
226
247
}
227
248
228
249
/// Registers the object interface as a dynamic type within the plugin.
229
250
/// The object interface can be registered several times as a dynamic type.
230
251
#[ inline]
231
252
pub fn on_implementation_load( type_plugin: & #plugin_ty) -> bool {
232
- let type_mut = Self :: get_type_mut ( ) ;
233
- * type_mut = #crate_ident :: translate :: IntoGlib :: into_glib ( #crate_ident :: subclass :: register_dynamic_interface :: <#plugin_ty , Self > ( type_plugin ) ) ;
234
- * type_mut != #crate_ident:: gobject_ffi:: G_TYPE_INVALID
253
+ let gtype = #crate_ident :: translate :: IntoGlib :: into_glib ( #crate_ident :: subclass :: register_dynamic_interface :: <#plugin_ty , Self > ( type_plugin ) ) ;
254
+ #gtype_status . store ( gtype , :: std :: sync :: atomic :: Ordering :: Release ) ;
255
+ gtype != #crate_ident:: gobject_ffi:: G_TYPE_INVALID
235
256
}
236
257
237
258
/// Do nothing as object interfaces registered as dynamic types are never unregistered.
0 commit comments