glib/subclass/
type_module.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::{Object, TypeModule, ffi, gobject_ffi, prelude::*, subclass::prelude::*, translate::*};
4
5pub trait TypeModuleImpl: ObjectImpl + ObjectSubclass<Type: IsA<Object> + IsA<TypeModule>> {
6    // rustdoc-stripper-ignore-next
7    /// Loads the module, registers one or more object subclasses using
8    /// [`register_dynamic_type`] and registers one or more object interfaces
9    /// using [`register_dynamic_interface`] (see [`TypeModule`]).
10    ///
11    /// [`register_dynamic_type`]: ../types/fn.register_dynamic_type.html
12    /// [`register_dynamic_interface`]: ../interface/fn.register_dynamic_interface.html
13    /// [`TypeModule`]: ../../gobject/auto/type_module/struct.TypeModule.html
14    fn load(&self) -> bool;
15
16    // rustdoc-stripper-ignore-next
17    /// Unloads the module (see [`TypeModuleExt::unuse`]).
18    ///
19    /// [`TypeModuleExt::unuse`]: ../../gobject/auto/type_module/trait.TypeModuleExt.html#method.unuse
20    // rustdoc-stripper-ignore-next-stop
21    fn unload(&self);
22}
23
24pub trait TypeModuleImplExt: TypeModuleImpl {
25    fn parent_load(&self) -> bool;
26    fn parent_unload(&self);
27}
28
29impl<T: TypeModuleImpl> TypeModuleImplExt for T {
30    fn parent_load(&self) -> bool {
31        unsafe {
32            let data = T::type_data();
33            let parent_class = data.as_ref().parent_class() as *const gobject_ffi::GTypeModuleClass;
34
35            let f = (*parent_class)
36                .load
37                .expect("No parent class implementation for \"load\"");
38
39            from_glib(f(self
40                .obj()
41                .unsafe_cast_ref::<TypeModule>()
42                .to_glib_none()
43                .0))
44        }
45    }
46
47    fn parent_unload(&self) {
48        unsafe {
49            let data = T::type_data();
50            let parent_class = data.as_ref().parent_class() as *const gobject_ffi::GTypeModuleClass;
51
52            let f = (*parent_class)
53                .unload
54                .expect("No parent class implementation for \"unload\"");
55
56            f(self.obj().unsafe_cast_ref::<TypeModule>().to_glib_none().0);
57        }
58    }
59}
60
61unsafe impl<T: TypeModuleImpl> IsSubclassable<T> for TypeModule {
62    fn class_init(class: &mut crate::Class<Self>) {
63        Self::parent_class_init::<T>(class);
64
65        let klass = class.as_mut();
66        klass.load = Some(load::<T>);
67        klass.unload = Some(unload::<T>);
68    }
69}
70
71unsafe extern "C" fn load<T: TypeModuleImpl>(
72    type_module: *mut gobject_ffi::GTypeModule,
73) -> ffi::gboolean {
74    unsafe {
75        let instance = &*(type_module as *mut T::Instance);
76        let imp = instance.imp();
77
78        let res = imp.load();
79        // GLib type system expects a module to never be disposed if types has been
80        // successfully loaded.
81        // The following code prevents the Rust wrapper (`glib::TypeModule` subclass)
82        // to dispose the module when dropped by ensuring the reference count is > 1.
83        // Nothing is done if loading types has failed, allowing application to drop
84        // and dispose the invalid module.
85        if res && (*(type_module as *const gobject_ffi::GObject)).ref_count == 1 {
86            gobject_ffi::g_object_ref(type_module as _);
87        }
88
89        res.into_glib()
90    }
91}
92
93unsafe extern "C" fn unload<T: TypeModuleImpl>(type_module: *mut gobject_ffi::GTypeModule) {
94    unsafe {
95        let instance = &*(type_module as *mut T::Instance);
96        let imp = instance.imp();
97
98        imp.unload();
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use crate as glib;
105
106    use super::*;
107
108    mod imp {
109        use super::*;
110
111        #[derive(Default)]
112        pub struct SimpleModule;
113
114        #[crate::object_subclass]
115        impl ObjectSubclass for SimpleModule {
116            const NAME: &'static str = "SimpleModule";
117            type Type = super::SimpleModule;
118            type ParentType = TypeModule;
119            type Interfaces = (crate::TypePlugin,);
120        }
121
122        impl ObjectImpl for SimpleModule {}
123
124        impl TypePluginImpl for SimpleModule {}
125
126        impl TypeModuleImpl for SimpleModule {
127            fn load(&self) -> bool {
128                // register types on implementation load
129                SimpleModuleType::on_implementation_load(self.obj().upcast_ref::<TypeModule>())
130            }
131
132            fn unload(&self) {
133                // unregister types on implementation unload
134                SimpleModuleType::on_implementation_unload(self.obj().upcast_ref::<TypeModule>());
135            }
136        }
137
138        #[derive(Default)]
139        pub struct SimpleModuleType;
140
141        #[crate::object_subclass]
142        #[object_subclass_dynamic]
143        impl ObjectSubclass for SimpleModuleType {
144            const NAME: &'static str = "SimpleModuleType";
145            type Type = super::SimpleModuleType;
146        }
147
148        impl ObjectImpl for SimpleModuleType {}
149    }
150
151    crate::wrapper! {
152        pub struct SimpleModule(ObjectSubclass<imp::SimpleModule>)
153        @extends TypeModule, @implements crate::TypePlugin;
154    }
155
156    crate::wrapper! {
157        pub struct SimpleModuleType(ObjectSubclass<imp::SimpleModuleType>);
158    }
159
160    #[test]
161    fn test_module() {
162        assert!(!imp::SimpleModuleType::type_().is_valid());
163        let simple_module = glib::Object::new::<SimpleModule>();
164        // simulates the GLib type system to load the module.
165        assert!(TypeModuleExt::use_(&simple_module));
166        assert!(imp::SimpleModuleType::type_().is_valid());
167        TypeModuleExt::unuse(&simple_module);
168    }
169}