Skip to content

Commit d982e08

Browse files
authored
Add support of enums as dynamic types (#1220)
Add support of enums as dynamic types
1 parent 90153c5 commit d982e08

14 files changed

+1055
-84
lines changed

glib-macros/src/enum_derive.rs

Lines changed: 244 additions & 30 deletions
Large diffs are not rendered by default.

glib-macros/src/lib.rs

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ pub fn closure_local(item: TokenStream) -> TokenStream {
439439
closure::closure_inner(item, "new_local")
440440
}
441441

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

471+
/// Derive macro for register a Rust enum in the GLib type system as a dynamic
472+
/// type and derive the [`glib::Value`] traits.
473+
///
474+
/// An enum must be explicitly registered as a dynamic type when the system
475+
/// loads its implementation (see [`TypePlugin`] and [`TypeModule`].
476+
/// Therefore, whereas an enum can be registered only once as a static type,
477+
/// it can be registered several times as a dynamic type.
478+
///
479+
/// An enum registered as a dynamic type is never unregistered. The system
480+
/// calls [`TypePluginExt::unuse`] to unload its implementation. If the
481+
/// [`TypePlugin`] subclass is a [`TypeModule`], the enum registered as a
482+
/// dynamic type is marked as unloaded and must be registered again when the
483+
/// module is reloaded.
484+
///
485+
/// This macro provides two behaviors when registering an enum as a dynamic
486+
/// type:
487+
///
488+
/// By default an enum is registered as a dynamic type when the system loads
489+
/// its implementation (e.g. when the module is loaded):
490+
/// ```ignore
491+
/// use glib::prelude::*;
492+
/// use glib::subclass::prelude::*;
493+
///
494+
/// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::DynamicEnum)]
495+
/// #[enum_type(name = "MyEnum")]
496+
/// enum MyEnum {
497+
/// Val,
498+
/// #[enum_value(name = "My Val")]
499+
/// ValWithCustomName,
500+
/// #[enum_value(name = "My Other Val", nick = "other")]
501+
/// ValWithCustomNameAndNick,
502+
/// }
503+
/// ```
504+
///
505+
/// Optionally setting the macro attribute `lazy_registration` to `true`
506+
/// postpones registration on the first use (when `static_type()` is called for
507+
/// the first time), similarly to the [`macro@enum_derive`] macro:
508+
/// ```ignore
509+
/// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::DynamicEnum)]
510+
/// #[enum_type(name = "MyEnum", lazy_registration = true)]
511+
/// enum MyEnum {
512+
/// ...
513+
/// }
514+
/// ```
515+
///
516+
/// An enum is usually registered as a dynamic type within a [`TypeModule`]
517+
/// subclass:
518+
/// ```ignore
519+
/// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::DynamicEnum)]
520+
/// #[enum_type(name = "MyModuleEnum")]
521+
/// enum MyModuleEnum {
522+
/// ...
523+
/// }
524+
/// ...
525+
/// #[derive(Default)]
526+
/// pub struct MyModule;
527+
/// ...
528+
/// impl TypeModuleImpl for MyModule {
529+
/// fn load(&self) -> bool {
530+
/// // registers enums as dynamic types.
531+
/// let my_module = self.obj();
532+
/// let type_module: &glib::TypeModule = my_module.upcast_ref();
533+
/// MyModuleEnum::on_implementation_load(type_module)
534+
/// }
535+
/// ...
536+
/// }
537+
/// ```
538+
///
539+
/// Optionally setting the macro attribute `plugin_type` allows to register an
540+
/// enum as a dynamic type within a given [`TypePlugin`] subclass:
541+
/// ```ignore
542+
/// #[derive(Debug, Copy, Clone, PartialEq, Eq, glib::DynamicEnum)]
543+
/// #[enum_type(name = "MyPluginEnum", plugin_type = MyPlugin)]
544+
/// enum MyPluginEnum {
545+
/// ...
546+
/// }
547+
/// ...
548+
/// #[derive(Default)]
549+
/// pub struct MyPlugin;
550+
/// ...
551+
/// impl TypePluginImpl for MyPlugin {
552+
/// fn use_plugin(&self) {
553+
/// // register enums as dynamic types.
554+
/// let my_plugin = self.obj();
555+
/// MyPluginEnum::on_implementation_load(my_plugin.as_ref());
556+
/// }
557+
/// ...
558+
/// }
559+
/// ```
560+
///
561+
/// [`glib::Value`]: ../glib/value/struct.Value.html
562+
/// [`TypePlugin`]: ../glib/gobject/type_plugin/struct.TypePlugin.html
563+
/// [`TypeModule`]: ../glib/gobject/type_module/struct.TypeModule.html
564+
/// [`TypePluginExt::unuse`]: ../glib/gobject/type_plugin/trait.TypePluginExt.html#method.unuse
565+
#[proc_macro_derive(DynamicEnum, attributes(enum_type, enum_value))]
566+
#[proc_macro_error]
567+
pub fn dynamic_enum_derive(input: TokenStream) -> TokenStream {
568+
let input = parse_macro_input!(input as DeriveInput);
569+
let gen = enum_derive::impl_dynamic_enum(&input);
570+
gen.into()
571+
}
572+
471573
/// Attribute macro for defining flags using the `bitflags` crate.
472574
/// This macro will also define a `GFlags::type_` function and
473575
/// the [`glib::Value`] traits.
@@ -671,8 +773,7 @@ pub fn object_subclass(_attr: TokenStream, item: TokenStream) -> TokenStream {
671773
///
672774
/// Optionally setting the macro attribute `lazy_registration` to `true`
673775
/// postpones registration on the first use (when `type_()` is called for the
674-
/// first time), similarly to the [`macro@object_subclass`]
675-
/// macro:
776+
/// first time), similarly to the [`macro@object_subclass`] macro:
676777
/// ```ignore
677778
/// #[glib::dynamic_object_subclass(lazy_registration = true)]
678779
/// impl ObjectSubclass for MyType { ... }

glib-macros/src/object_interface_attribute.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,15 @@ pub fn impl_dynamic_object_interface(
8686
),
8787
};
8888

89-
// The following implementations follows the lifecycle of plugins and of dynamic types (see [`TypePluginExt::unuse`]).
90-
// An object interface can be reregistered as a dynamic type (see [`TypePluginExt::register_type`]).
89+
// The following implementations follows the lifecycle of plugins and of dynamic types (see [`TypePluginExt`] and [`TypeModuleExt`]).
90+
// An object interface can be reregistered as a dynamic type.
9191
let register_interface = if lazy_registration {
9292
// registers the object interface as a dynamic type on the first use (lazy registration).
9393
// a weak reference on the plugin is stored and will be used later on the first use of the object interface.
94-
// 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.
94+
// 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.
9595
quote! {
9696
impl #self_ty {
97-
/// Returns a mutable reference to the registration status: a tuple of the weak reference on the plugin and of the glib type.
97+
/// Returns a mutable reference to the registration status: a tuple of the weak reference on the plugin and of the GLib type.
9898
/// This is safe because the mutable reference guarantees that no other threads are concurrently accessing the data.
9999
#[inline]
100100
fn get_registration_status_ref_mut() -> &'static mut Option<(<#plugin_ty as #crate_ident::clone::Downgrade>::Weak, #crate_ident::Type)> {
@@ -171,7 +171,7 @@ pub fn impl_dynamic_object_interface(
171171
// registers immediately the object interface as a dynamic type.
172172
quote! {
173173
impl #self_ty {
174-
/// Returns a mutable reference to the glib type.
174+
/// Returns a mutable reference to the GLib type.
175175
/// This is safe because the mutable reference guarantees that no other threads are concurrently accessing the atomic data.
176176
#[inline]
177177
fn get_type_mut() -> &'static mut #crate_ident::ffi::GType {

glib-macros/src/object_subclass_attribute.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,15 @@ pub fn impl_dynamic_object_subclass(
8181
),
8282
};
8383

84-
// The following implementations follows the lifecycle of plugins and of dynamic types (see [`TypePluginExt::unuse`]).
85-
// An object subclass can be reregistered as a dynamic type (see [`TypePluginExt::register_type`]).
84+
// The following implementations follows the lifecycle of plugins and of dynamic types (see [`TypePluginExt`] and [`TypeModuleExt`]).
85+
// An object subclass can be reregistered as a dynamic type.
8686
let register_type = if lazy_registration {
8787
// registers the object subclass as a dynamic type on the first use (lazy registration).
8888
// a weak reference on the plugin is stored and will be used later on the first use of the object subclass.
89-
// 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.
89+
// 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.
9090
quote! {
9191
impl #self_ty {
92-
/// Returns a mutable reference to the registration status: a tuple of the weak reference on the plugin and of the glib type.
92+
/// Returns a mutable reference to the registration status: a tuple of the weak reference on the plugin and of the GLib type.
9393
/// This is safe because the mutable reference guarantees that no other threads are concurrently accessing the data.
9494
#[inline]
9595
fn get_registration_status_ref_mut() -> &'static mut Option<(<#plugin_ty as #crate_ident::clone::Downgrade>::Weak, #crate_ident::Type)> {

0 commit comments

Comments
 (0)