Skip to main content

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