Skip to content

Commit

Permalink
Add support of enums as dynamic types (#1220)
Browse files Browse the repository at this point in the history
Add support of enums as dynamic types
  • Loading branch information
fbrouille authored Dec 16, 2023
1 parent 90153c5 commit d982e08
Show file tree
Hide file tree
Showing 14 changed files with 1,055 additions and 84 deletions.
274 changes: 244 additions & 30 deletions glib-macros/src/enum_derive.rs

Large diffs are not rendered by default.

107 changes: 104 additions & 3 deletions glib-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ pub fn closure_local(item: TokenStream) -> TokenStream {
closure::closure_inner(item, "new_local")
}

/// Derive macro for register a rust enum in the glib type system and derive the
/// Derive macro for register a Rust enum in the GLib type system and derive the
/// the [`glib::Value`] traits.
///
/// # Example
Expand Down Expand Up @@ -468,6 +468,108 @@ pub fn enum_derive(input: TokenStream) -> TokenStream {
gen.into()
}

/// Derive macro for register a Rust enum in the GLib type system as a dynamic

Check warning on line 471 in glib-macros/src/lib.rs

View workflow job for this annotation

GitHub Actions / build

unresolved link to `enum_derive`
/// type and derive the [`glib::Value`] traits.
///
/// An enum must be explicitly registered as a dynamic type when the system
/// loads its implementation (see [`TypePlugin`] and [`TypeModule`].
/// Therefore, whereas an enum can be registered only once as a static type,
/// it can be registered several times as a dynamic type.
///
/// An enum 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 enum 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 enum as a dynamic
/// type:
///
/// By default an enum is registered as a dynamic type when the system loads
/// its implementation (e.g. when the module is loaded):
/// ```ignore
/// use glib::prelude::*;
/// use glib::subclass::prelude::*;
///
/// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::DynamicEnum)]
/// #[enum_type(name = "MyEnum")]
/// enum MyEnum {
/// Val,
/// #[enum_value(name = "My Val")]
/// ValWithCustomName,
/// #[enum_value(name = "My Other Val", nick = "other")]
/// ValWithCustomNameAndNick,
/// }
/// ```
///
/// Optionally setting the macro attribute `lazy_registration` to `true`
/// postpones registration on the first use (when `static_type()` is called for
/// the first time), similarly to the [`macro@enum_derive`] macro:
/// ```ignore
/// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::DynamicEnum)]
/// #[enum_type(name = "MyEnum", lazy_registration = true)]
/// enum MyEnum {
/// ...
/// }
/// ```
///
/// An enum is usually registered as a dynamic type within a [`TypeModule`]
/// subclass:
/// ```ignore
/// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::DynamicEnum)]
/// #[enum_type(name = "MyModuleEnum")]
/// enum MyModuleEnum {
/// ...
/// }
/// ...
/// #[derive(Default)]
/// pub struct MyModule;
/// ...
/// impl TypeModuleImpl for MyModule {
/// fn load(&self) -> bool {
/// // registers enums as dynamic types.
/// let my_module = self.obj();
/// let type_module: &glib::TypeModule = my_module.upcast_ref();
/// MyModuleEnum::on_implementation_load(type_module)
/// }
/// ...
/// }
/// ```
///
/// Optionally setting the macro attribute `plugin_type` allows to register an
/// enum as a dynamic type within a given [`TypePlugin`] subclass:
/// ```ignore
/// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::DynamicEnum)]
/// #[enum_type(name = "MyPluginEnum", plugin_type = MyPlugin)]
/// enum MyPluginEnum {
/// ...
/// }
/// ...
/// #[derive(Default)]
/// pub struct MyPlugin;
/// ...
/// impl TypePluginImpl for MyPlugin {
/// fn use_plugin(&self) {
/// // register enums as dynamic types.
/// let my_plugin = self.obj();
/// MyPluginEnum::on_implementation_load(my_plugin.as_ref());
/// }
/// ...
/// }
/// ```
///
/// [`glib::Value`]: ../glib/value/struct.Value.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_derive(DynamicEnum, attributes(enum_type, enum_value))]
#[proc_macro_error]
pub fn dynamic_enum_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let gen = enum_derive::impl_dynamic_enum(&input);
gen.into()
}

/// Attribute macro for defining flags using the `bitflags` crate.
/// This macro will also define a `GFlags::type_` function and
/// the [`glib::Value`] traits.
Expand Down Expand Up @@ -671,8 +773,7 @@ pub fn object_subclass(_attr: TokenStream, item: TokenStream) -> TokenStream {
///
/// 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:
/// first time), similarly to the [`macro@object_subclass`] macro:
/// ```ignore
/// #[glib::dynamic_object_subclass(lazy_registration = true)]
/// impl ObjectSubclass for MyType { ... }
Expand Down
10 changes: 5 additions & 5 deletions glib-macros/src/object_interface_attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,15 @@ pub fn impl_dynamic_object_interface(
),
};

// The following implementations follows the lifecycle of plugins and of dynamic types (see [`TypePluginExt::unuse`]).
// An object interface can be reregistered as a dynamic type (see [`TypePluginExt::register_type`]).
// The following implementations follows the lifecycle of plugins and of dynamic types (see [`TypePluginExt`] and [`TypeModuleExt`]).
// An object interface can be reregistered as a dynamic type.
let register_interface = if lazy_registration {
// registers the object interface as a dynamic type on the first use (lazy registration).
// a weak reference on the plugin is stored and will be used later on the first use of the object interface.
// 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.
// 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.
quote! {
impl #self_ty {
/// Returns a mutable reference to the registration status: a tuple of the weak reference on the plugin and of the glib type.
/// Returns a mutable reference to the registration status: a tuple of the weak reference on the plugin and of the GLib type.
/// This is safe because the mutable reference guarantees that no other threads are concurrently accessing the data.
#[inline]
fn get_registration_status_ref_mut() -> &'static mut Option<(<#plugin_ty as #crate_ident::clone::Downgrade>::Weak, #crate_ident::Type)> {
Expand Down Expand Up @@ -171,7 +171,7 @@ pub fn impl_dynamic_object_interface(
// registers immediately the object interface as a dynamic type.
quote! {
impl #self_ty {
/// Returns a mutable reference to the glib type.
/// Returns a mutable reference to the GLib type.
/// This is safe because the mutable reference guarantees that no other threads are concurrently accessing the atomic data.
#[inline]
fn get_type_mut() -> &'static mut #crate_ident::ffi::GType {
Expand Down
8 changes: 4 additions & 4 deletions glib-macros/src/object_subclass_attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,15 @@ pub fn impl_dynamic_object_subclass(
),
};

// The following implementations follows the lifecycle of plugins and of dynamic types (see [`TypePluginExt::unuse`]).
// An object subclass can be reregistered as a dynamic type (see [`TypePluginExt::register_type`]).
// The following implementations follows the lifecycle of plugins and of dynamic types (see [`TypePluginExt`] and [`TypeModuleExt`]).
// An object subclass can be reregistered as a dynamic type.
let register_type = if lazy_registration {
// registers the object subclass as a dynamic type on the first use (lazy registration).
// a weak reference on the plugin is stored and will be used later on the first use of the object subclass.
// this implementation relies on a static storage of a weak reference on the plugin and of the glib type to know if the object subclass has been registered.
// this implementation relies on a static storage of a weak reference on the plugin and of the GLib type to know if the object subclass has been registered.
quote! {
impl #self_ty {
/// Returns a mutable reference to the registration status: a tuple of the weak reference on the plugin and of the glib type.
/// Returns a mutable reference to the registration status: a tuple of the weak reference on the plugin and of the GLib type.
/// This is safe because the mutable reference guarantees that no other threads are concurrently accessing the data.
#[inline]
fn get_registration_status_ref_mut() -> &'static mut Option<(<#plugin_ty as #crate_ident::clone::Downgrade>::Weak, #crate_ident::Type)> {
Expand Down
Loading

0 comments on commit d982e08

Please sign in to comment.