Skip to content

Commit

Permalink
add support of object subclasses and interfaces registered as dynamic…
Browse files Browse the repository at this point in the history
… types

Signed-off-by: fbrouille <fbrouille@users.noreply.github.com>
  • Loading branch information
fbrouille committed Oct 28, 2023
1 parent e93e899 commit d945d12
Show file tree
Hide file tree
Showing 23 changed files with 2,485 additions and 51 deletions.
1 change: 1 addition & 0 deletions glib-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = ["full"] }
proc-macro-crate = "2.0"
libc = "0.2"

[lib]
proc-macro = true
Expand Down
140 changes: 140 additions & 0 deletions glib-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,75 @@ pub fn object_subclass(_attr: TokenStream, item: TokenStream) -> TokenStream {
}
}

/// Macro for boilerplate of [`ObjectSubclass`] implementations that are
/// registered as dynamic types.
///
/// An object subclass must be explicitly registered as a dynamic type when the
/// system loads its implementation (see [`TypePlugin`] and [`TypeModule`].
/// Therefore, whereas an object subclass can be registered only once as a
/// static type, it can be registered several times as a dynamic type.
///
/// An object subclass registered as a dynamic type is never unregistered. The
/// system calls [`TypePluginExt::unuse`] to unload its implementation. If the
/// [`TypePlugin`] subclass is a [`TypeModule`], the object subclass registered
/// as a dynamic type is marked as unloaded and must be registered again when
/// the module is reloaded.
///
/// This macro provides two behaviors when registering an object subclass as a
/// dynamic type:
///
/// By default an object subclass is registered as a dynamic type when the
/// system loads its implementation (e.g. when the module is loaded):
/// ```ignore
/// #[glib::dynamic_object_subclass]
/// impl ObjectSubclass for MyType { ... }
/// ```
///
/// Optionally setting the macro attribute `lazy_registration` to `true`
/// postpones registration on the first use (when `type_()` is called for the
/// first time), similarly to the [`macro@object_subclass`]
/// macro:
/// ```ignore
/// #[glib::dynamic_object_subclass(lazy_registration = true)]
/// impl ObjectSubclass for MyType { ... }
/// ```
///
/// By default an object subclass is considered to be registered as a dynamic
/// type within a [`TypeModule`] subclass. Optionally setting the macro
/// attribute `plugin_type` allows to register an object subclass as a dynamic
/// type within a given [`TypePlugin`] subclass:
/// ```ignore
/// #[glib::dynamic_object_subclass(plugin_type = MyPlugin)]
/// impl ObjectSubclass for MyType { ... }
/// ```
///
/// [`ObjectSubclass`]: ../glib/subclass/types/trait.ObjectSubclass.html
/// [`TypePlugin`]: ../glib/gobject/type_plugin/struct.TypePlugin.html
/// [`TypeModule`]: ../glib/gobject/type_module/struct.TypeModule.html
/// [`TypePluginExt::unuse`]: ../glib/gobject/type_plugin/trait.TypePluginExt.html#method.unuse
#[proc_macro_attribute]
#[proc_macro_error]
pub fn dynamic_object_subclass(attr: TokenStream, item: TokenStream) -> TokenStream {
use proc_macro_error::abort_call_site;
let attrs = match syn::parse::Parser::parse(
syn::punctuated::Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated,
attr,
) {
Ok(attrs)
if attrs
.iter()
.all(|attr| matches!(attr, syn::Expr::Assign(_))) =>
{
attrs
}
_ => abort_call_site!(object_subclass_attribute::WRONG_EXPRESSION_MSG),
};
match syn::parse::<syn::ItemImpl>(item) {
Ok(input) => object_subclass_attribute::impl_dynamic_object_subclass(&attrs, &input).into(),
Err(_) => abort_call_site!(object_subclass_attribute::WRONG_PLACE_MSG),
}
}

/// Macro for boilerplate of [`ObjectInterface`] implementations.
///
/// This adds implementations for the `get_type()` method, which should probably never be defined
Expand All @@ -670,6 +739,77 @@ pub fn object_interface(_attr: TokenStream, item: TokenStream) -> TokenStream {
}
}

/// Macro for boilerplate of [`ObjectInterface`] implementations that are
/// registered as dynamic types.
///
/// An object interface must be explicitly registeredas a dynamic type when the
/// system loads its implementation (see [`TypePlugin`] and [`TypeModule`].
/// Therefore, whereas an object interface can be registered only once as a
/// static type, it can be registered several times as a dynamic type.
///
/// An object interface registered as a dynamic type is never unregistered. The
/// system calls [`TypePluginExt::unuse`] to unload its implementation. If the
/// [`TypePlugin`] subclass is a [`TypeModule`], the object interface
/// registered as a dynamic type is marked as unloaded and must be registered
/// again when the module is reloaded.
///
/// This macro provides two behaviors when registering an object interface as a
/// dynamic type:
///
/// By default an object interface is registered as a dynamic type when the
/// system loads its implementation (e.g. when the module is loaded):
/// ```ignore
/// #[glib::dynamic_object_interface]
/// unsafe impl ObjectInterface for MyInterface { ... }
/// ```
///
/// Optionally setting the macro attribute `lazy_registration` to `true`
/// postpones registration on the first use (when `type_()` is called for the
/// first time), similarly to the [`macro@object_subclass`]
/// [`macro@object_interface`] macro.
/// ```ignore
/// #[glib::dynamic_object_interface(lazy_registration = true)]
/// unsafe impl ObjectInterface for MyInterface { ... }
/// ```
///
/// By default an object interface is considered to be registered as a dynamic
/// type within a [`TypeModule`] subclass. Optionally setting the macro
/// attribute `plugin_type` allows to register an object interface as a dynamic
/// type within a given [`TypePlugin`] subclass:
/// ```ignore
/// #[glib::dynamic_object_interface(plugin_type = MyPlugin)]
/// unsafe impl ObjectInterface for MyInterface { ... }
/// ```
///
/// [`ObjectInterface`]: ../glib/subclass/interface/trait.ObjectInterface.html
/// [`TypePlugin`]: ../glib/gobject/type_plugin/struct.TypePlugin.html
/// [`TypeModule`]: ../glib/gobject/type_module/struct.TypeModule.html
/// [`TypePluginExt::unuse`]: ../glib/gobject/type_plugin/trait.TypePluginExt.html#method.unuse
#[proc_macro_attribute]
#[proc_macro_error]
pub fn dynamic_object_interface(attr: TokenStream, item: TokenStream) -> TokenStream {
use proc_macro_error::abort_call_site;
let attrs = match syn::parse::Parser::parse(
syn::punctuated::Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated,
attr,
) {
Ok(attrs)
if attrs
.iter()
.all(|attr| matches!(attr, syn::Expr::Assign(_))) =>
{
attrs
}
_ => abort_call_site!(object_interface_attribute::WRONG_EXPRESSION_MSG),
};
match syn::parse::<syn::ItemImpl>(item) {
Ok(input) => {
object_interface_attribute::impl_dynamic_object_interface(&attrs, &input).into()
}
Err(_) => abort_call_site!(object_interface_attribute::WRONG_PLACE_MSG),
}
}

/// Macro for deriving implementations of [`glib::clone::Downgrade`] and
/// [`glib::clone::Upgrade`] traits and a weak type.
///
Expand Down
Loading

0 comments on commit d945d12

Please sign in to comment.