Skip to content

Commit 1c68de9

Browse files
committed
replace macro 'dynamic_object_interface' by the macro helper attribute 'object_interface_dynamic' for macro 'object_interface'
Signed-off-by: fbrouille <[email protected]>
1 parent f78cdaa commit 1c68de9

File tree

5 files changed

+180
-178
lines changed

5 files changed

+180
-178
lines changed

glib-macros/src/lib.rs

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -841,84 +841,102 @@ pub fn object_subclass(_attr: TokenStream, item: TokenStream) -> TokenStream {
841841
/// type Prerequisites = ();
842842
/// ```
843843
///
844-
/// [`ObjectInterface`]: ../glib/subclass/interface/trait.ObjectInterface.html
845-
#[proc_macro_attribute]
846-
#[proc_macro_error]
847-
pub fn object_interface(_attr: TokenStream, item: TokenStream) -> TokenStream {
848-
use proc_macro_error::abort_call_site;
849-
match syn::parse::<syn::ItemImpl>(item) {
850-
Ok(input) => object_interface_attribute::impl_object_interface(&input).into(),
851-
Err(_) => abort_call_site!(object_interface_attribute::WRONG_PLACE_MSG),
852-
}
853-
}
854-
855-
/// Macro for boilerplate of [`ObjectInterface`] implementations that are
856-
/// registered as dynamic types.
844+
/// An object interface can be registered as a dynamic type by setting the
845+
/// macro helper attribute `object_interface_dynamic`:
846+
/// ```ignore
847+
/// pub struct MyInterface {
848+
/// parent: glib::gobject_ffi::GTypeInterface,
849+
/// }
850+
/// #[glib::object_interface]
851+
/// #[object_interface_dynamic]
852+
/// unsafe impl ObjectInterface for MyInterface { ... }
853+
/// ```
857854
///
858-
/// An object interface must be explicitly registeredas a dynamic type when the
859-
/// system loads its implementation (see [`TypePlugin`] and [`TypeModule`].
855+
/// As a dynamic type, an object interface must be explicitly registered when
856+
/// the system loads the implementation (see [`TypePlugin`] and [`TypeModule`].
860857
/// Therefore, whereas an object interface can be registered only once as a
861858
/// static type, it can be registered several times as a dynamic type.
862859
///
863860
/// An object interface registered as a dynamic type is never unregistered. The
864-
/// system calls [`TypePluginExt::unuse`] to unload its implementation. If the
861+
/// system calls [`TypePluginExt::unuse`] to unload the implementation. If the
865862
/// [`TypePlugin`] subclass is a [`TypeModule`], the object interface
866863
/// registered as a dynamic type is marked as unloaded and must be registered
867864
/// again when the module is reloaded.
868865
///
869-
/// This macro provides two behaviors when registering an object interface as a
870-
/// dynamic type:
866+
/// The macro helper attribute `object_interface_dynamic` provides two
867+
/// behaviors when registering an object interface as a dynamic type:
871868
///
872-
/// By default an object interface is registered as a dynamic type when the
873-
/// system loads its implementation (e.g. when the module is loaded):
869+
/// - lazy registration: by default an object interface is registered as a
870+
/// dynamic type when the system loads the implementation (e.g. when the module
871+
/// is loaded). Optionally setting `lazy_registration` to `true` postpones
872+
/// registration on the first use (when `type_()` is called for the first time):
874873
/// ```ignore
875-
/// #[glib::dynamic_object_interface]
874+
/// pub struct MyInterface {
875+
/// parent: glib::gobject_ffi::GTypeInterface,
876+
/// }
877+
/// #[glib::object_interface]
878+
/// #[object_interface_dynamic(lazy_registration = true)]
876879
/// unsafe impl ObjectInterface for MyInterface { ... }
877880
/// ```
878881
///
879-
/// Optionally setting the macro attribute `lazy_registration` to `true`
880-
/// postpones registration on the first use (when `type_()` is called for the
881-
/// first time), similarly to the [`macro@object_subclass`]
882-
/// [`macro@object_interface`] macro.
882+
/// - registration within [`TypeModule`] subclass or within [`TypePlugin`]
883+
/// subclass: an object interface is usually registered as a dynamic type
884+
/// within a [`TypeModule`] subclass:
883885
/// ```ignore
884-
/// #[glib::dynamic_object_interface(lazy_registration = true)]
885-
/// unsafe impl ObjectInterface for MyInterface { ... }
886+
/// pub struct MyModuleInterface {
887+
/// parent: glib::gobject_ffi::GTypeInterface,
888+
/// }
889+
/// #[glib::object_interface]
890+
/// #[object_interface_dynamic]
891+
/// unsafe impl ObjectInterface for MyModuleInterface { ... }
892+
/// ...
893+
/// #[derive(Default)]
894+
/// pub struct MyModule;
895+
/// ...
896+
/// impl TypeModuleImpl for MyModule {
897+
/// fn load(&self) -> bool {
898+
/// // registers object interfaces as dynamic types.
899+
/// let my_module = self.obj();
900+
/// let type_module: &glib::TypeModule = my_module.upcast_ref();
901+
/// MyModuleInterface::on_implementation_load(type_module)
902+
/// }
903+
/// ...
904+
/// }
886905
/// ```
887906
///
888-
/// By default an object interface is considered to be registered as a dynamic
889-
/// type within a [`TypeModule`] subclass. Optionally setting the macro
890-
/// attribute `plugin_type` allows to register an object interface as a dynamic
891-
/// type within a given [`TypePlugin`] subclass:
907+
/// Optionally setting `plugin_type` allows to register an object interface as
908+
/// a dynamic type within a [`TypePlugin`] subclass that is not a [`TypeModule`]:
892909
/// ```ignore
893-
/// #[glib::dynamic_object_interface(plugin_type = MyPlugin)]
894-
/// unsafe impl ObjectInterface for MyInterface { ... }
910+
/// pub struct MyPluginInterface {
911+
/// parent: glib::gobject_ffi::GTypeInterface,
912+
/// }
913+
/// #[glib::object_interface]
914+
/// #[object_interface_dynamic(plugin_type = MyPlugin)]
915+
/// unsafe impl ObjectInterface for MyPluginInterface { ... }
916+
/// ...
917+
/// #[derive(Default)]
918+
/// pub struct MyPlugin;
919+
/// ...
920+
/// impl TypePluginImpl for MyPlugin {
921+
/// fn use_plugin(&self) {
922+
/// // register object interfaces as dynamic types.
923+
/// let my_plugin = self.obj();
924+
/// MyPluginInterface::on_implementation_load(my_plugin.as_ref());
925+
/// }
926+
/// ...
927+
/// }
895928
/// ```
896929
///
897930
/// [`ObjectInterface`]: ../glib/subclass/interface/trait.ObjectInterface.html
898931
/// [`TypePlugin`]: ../glib/gobject/type_plugin/struct.TypePlugin.html
899932
/// [`TypeModule`]: ../glib/gobject/type_module/struct.TypeModule.html
900-
/// [`TypePluginExt::unuse`]: ../glib/gobject/type_plugin/trait.TypePluginExt.html#method.unuse
933+
/// [`TypePluginExt::unuse`]: ../glib/gobject/type_plugin/trait.TypePluginExt.html#method.unuse///
901934
#[proc_macro_attribute]
902935
#[proc_macro_error]
903-
pub fn dynamic_object_interface(attr: TokenStream, item: TokenStream) -> TokenStream {
936+
pub fn object_interface(_attr: TokenStream, item: TokenStream) -> TokenStream {
904937
use proc_macro_error::abort_call_site;
905-
let attrs = match syn::parse::Parser::parse(
906-
syn::punctuated::Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated,
907-
attr,
908-
) {
909-
Ok(attrs)
910-
if attrs
911-
.iter()
912-
.all(|attr| matches!(attr, syn::Expr::Assign(_))) =>
913-
{
914-
attrs
915-
}
916-
_ => abort_call_site!(object_interface_attribute::WRONG_EXPRESSION_MSG),
917-
};
918938
match syn::parse::<syn::ItemImpl>(item) {
919-
Ok(input) => {
920-
object_interface_attribute::impl_dynamic_object_interface(&attrs, &input).into()
921-
}
939+
Ok(mut input) => object_interface_attribute::impl_object_interface(&mut input).into(),
922940
Err(_) => abort_call_site!(object_interface_attribute::WRONG_PLACE_MSG),
923941
}
924942
}

glib-macros/src/object_interface_attribute.rs

Lines changed: 97 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,101 @@ use proc_macro2::TokenStream;
44
use proc_macro_error::abort_call_site;
55
use quote::{quote, ToTokens};
66

7-
pub const WRONG_EXPRESSION_MSG: &str =
8-
"This macro's attributes should be a sequence of assign expressions punctuated by comma";
9-
10-
pub const UNSUPPORTED_EXPRESSION_MSG: &str =
11-
"This macro's supported attributes are: `plugin_type = <subclass_of_glib::TypePlugin>, lazy_registration = true|false`";
7+
use crate::utils::{parse_optional_nested_meta_items, NestedMetaItem};
128

139
pub const WRONG_PLACE_MSG: &str =
1410
"This macro should be used on `impl` block for `glib::ObjectInterface` trait";
1511

16-
pub fn impl_object_interface(input: &syn::ItemImpl) -> TokenStream {
12+
pub fn impl_object_interface(input: &mut syn::ItemImpl) -> TokenStream {
1713
let crate_ident = crate::utils::crate_ident_new();
18-
let syn::ItemImpl { self_ty, .. } = &input;
14+
let syn::ItemImpl {
15+
attrs,
16+
generics,
17+
trait_,
18+
self_ty,
19+
unsafety,
20+
items,
21+
..
22+
} = input;
23+
24+
let mut plugin_type = NestedMetaItem::<syn::Path>::new("plugin_type").value_required();
25+
let mut lazy_registration =
26+
NestedMetaItem::<syn::LitBool>::new("lazy_registration").value_required();
27+
28+
let found = parse_optional_nested_meta_items(
29+
&*attrs,
30+
"object_interface_dynamic",
31+
&mut [&mut plugin_type, &mut lazy_registration],
32+
);
33+
34+
let register_object_interface = match found {
35+
Err(e) => return e.to_compile_error(),
36+
Ok(None) => register_object_interface_as_static(&crate_ident, self_ty),
37+
Ok(Some(_)) => {
38+
// remove attribute 'object_interface_dynamic' from the attribute list because it is not a real proc_macro_attribute
39+
attrs.retain(|attr| !attr.path().is_ident("object_interface_dynamic"));
40+
let plugin_ty = plugin_type
41+
.value
42+
.map(|p| p.into_token_stream())
43+
.unwrap_or(quote!(#crate_ident::TypeModule));
44+
let lazy_registration = lazy_registration.value.map(|b| b.value).unwrap_or_default();
45+
register_object_interface_as_dynamic(
46+
&crate_ident,
47+
self_ty,
48+
plugin_ty,
49+
lazy_registration,
50+
)
51+
}
52+
};
53+
54+
let mut has_prerequisites = false;
55+
for item in items.iter() {
56+
if let syn::ImplItem::Type(type_) = item {
57+
let name = type_.ident.to_string();
58+
if name == "Prerequisites" {
59+
has_prerequisites = true;
60+
}
61+
}
62+
}
63+
64+
let prerequisites_opt = if has_prerequisites {
65+
None
66+
} else {
67+
Some(quote!(
68+
type Prerequisites = ();
69+
))
70+
};
71+
72+
let trait_path = match &trait_ {
73+
Some(path) => &path.1,
74+
None => abort_call_site!(WRONG_PLACE_MSG),
75+
};
1976

77+
quote! {
78+
#(#attrs)*
79+
#unsafety impl #generics #trait_path for #self_ty {
80+
#prerequisites_opt
81+
#(#items)*
82+
}
83+
84+
unsafe impl #crate_ident::subclass::interface::ObjectInterfaceType for #self_ty {
85+
#[inline]
86+
fn type_() -> #crate_ident::Type {
87+
Self::register_interface()
88+
}
89+
}
90+
91+
#register_object_interface
92+
}
93+
}
94+
95+
// Registers the object interface as a static type.
96+
fn register_object_interface_as_static(
97+
crate_ident: &TokenStream,
98+
self_ty: &syn::Type,
99+
) -> TokenStream {
20100
// registers the interface on first use (lazy registration).
21-
let register_interface = quote! {
101+
quote! {
22102
impl #self_ty {
23103
/// Registers the interface only once.
24104
#[inline]
@@ -35,60 +115,20 @@ pub fn impl_object_interface(input: &syn::ItemImpl) -> TokenStream {
35115
}
36116
}
37117
}
38-
};
39-
40-
impl_object_interface_(register_interface, input)
118+
}
41119
}
42120

43-
pub fn impl_dynamic_object_interface(
44-
attrs: &syn::punctuated::Punctuated<syn::Expr, syn::Token![,]>,
45-
input: &syn::ItemImpl,
121+
// The following implementations follows the lifecycle of plugins and of dynamic types (see [`TypePluginExt`] and [`TypeModuleExt`]).
122+
// An object interface can be reregistered as a dynamic type.
123+
fn register_object_interface_as_dynamic(
124+
crate_ident: &TokenStream,
125+
self_ty: &syn::Type,
126+
plugin_ty: TokenStream,
127+
lazy_registration: bool,
46128
) -> TokenStream {
47-
let crate_ident = crate::utils::crate_ident_new();
48-
let syn::ItemImpl { self_ty, .. } = &input;
49-
50-
let mut plugin_type_opt: Option<syn::Path> = None;
51-
let mut lazy_registration_opt: Option<bool> = None;
52-
53-
for attr in attrs {
54-
match attr {
55-
// attribute must be one of supported assign expressions.
56-
syn::Expr::Assign(syn::ExprAssign { left, right, .. }) => {
57-
match (*left.to_owned(), *right.to_owned()) {
58-
// `plugin_type = <subclass_of_TypePlugin>`
59-
(
60-
syn::Expr::Path(syn::ExprPath { path: path1, .. }),
61-
syn::Expr::Path(syn::ExprPath { path: path2, .. }),
62-
) if path1.is_ident(&"plugin_type") => plugin_type_opt = Some(path2),
63-
// `lazy_registration = true|false`
64-
(
65-
syn::Expr::Path(syn::ExprPath { path, .. }),
66-
syn::Expr::Lit(syn::ExprLit {
67-
lit: syn::Lit::Bool(syn::LitBool { value, .. }),
68-
..
69-
}),
70-
) if path.is_ident(&"lazy_registration") => lazy_registration_opt = Some(value),
71-
_ => abort_call_site!(UNSUPPORTED_EXPRESSION_MSG),
72-
};
73-
}
74-
_ => abort_call_site!(WRONG_EXPRESSION_MSG),
75-
};
76-
}
77-
78-
let (plugin_ty, lazy_registration) = match (plugin_type_opt, lazy_registration_opt) {
79-
(Some(type_plugin), lazy_registration_opt) => (
80-
type_plugin.into_token_stream(),
81-
lazy_registration_opt.unwrap_or_default(),
82-
),
83-
(None, lazy_registration_opt) => (
84-
quote!(#crate_ident::TypeModule),
85-
lazy_registration_opt.unwrap_or_default(),
86-
),
87-
};
88-
89129
// The following implementations follows the lifecycle of plugins and of dynamic types (see [`TypePluginExt`] and [`TypeModuleExt`]).
90130
// An object interface can be reregistered as a dynamic type.
91-
let register_interface = if lazy_registration {
131+
if lazy_registration {
92132
// registers the object interface as a dynamic type on the first use (lazy registration).
93133
// a weak reference on the plugin is stored and will be used later on the first use of the object interface.
94134
// 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.
@@ -201,64 +241,5 @@ pub fn impl_dynamic_object_interface(
201241
}
202242
}
203243
}
204-
};
205-
206-
impl_object_interface_(register_interface, input)
207-
}
208-
209-
pub fn impl_object_interface_(
210-
register_interface: TokenStream,
211-
input: &syn::ItemImpl,
212-
) -> TokenStream {
213-
let mut has_prerequisites = false;
214-
for item in &input.items {
215-
if let syn::ImplItem::Type(type_) = item {
216-
let name = type_.ident.to_string();
217-
if name == "Prerequisites" {
218-
has_prerequisites = true;
219-
}
220-
}
221-
}
222-
223-
let syn::ItemImpl {
224-
attrs,
225-
generics,
226-
trait_,
227-
self_ty,
228-
unsafety,
229-
items,
230-
..
231-
} = &input;
232-
233-
let prerequisites_opt = if has_prerequisites {
234-
None
235-
} else {
236-
Some(quote!(
237-
type Prerequisites = ();
238-
))
239-
};
240-
241-
let crate_ident = crate::utils::crate_ident_new();
242-
243-
let trait_path = match &trait_ {
244-
Some(path) => &path.1,
245-
None => abort_call_site!(WRONG_PLACE_MSG),
246-
};
247-
248-
quote! {
249-
#(#attrs)*
250-
#unsafety impl #generics #trait_path for #self_ty {
251-
#prerequisites_opt
252-
#(#items)*
253-
}
254-
255-
unsafe impl #crate_ident::subclass::interface::ObjectInterfaceType for #self_ty {
256-
#[inline]
257-
fn type_() -> #crate_ident::Type {
258-
Self::register_interface()
259-
}
260-
}
261-
262-
#register_interface
263244
}
264245
}

0 commit comments

Comments
 (0)