Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support of enums as dynamic types #1220

Merged
merged 15 commits into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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 @@
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 @@
///
/// 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 Expand Up @@ -1023,7 +1124,7 @@
///
/// ## Using Rust keywords as property names
/// You might hit a roadblock when declaring properties with this macro because you want to use a name that happens to be a Rust keyword. This may happen with names like `loop`, which is a pretty common name when creating things like animation handlers.
/// To use those names, you can make use of the raw identifier feature of Rust. Simply prefix the identifier name with `r#` in the struct declaration. Internally, those `r#`s are stripped so you can use its expected name in [`ObjectExt::property`] or within GtkBuilder template files.

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

View workflow job for this annotation

GitHub Actions / build

unresolved link to `ObjectExt::property`
///
/// # Generated methods
/// The following methods are generated on the wrapper type specified on `#[properties(wrapper_type = ...)]`:
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
Loading