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::{ffi, gobject_ffi, prelude::*, subclass::prelude::*, translate::*, Object, TypeModule};
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 let instance = &*(type_module as *mut T::Instance);
75 let imp = instance.imp();
76
77 let res = imp.load();
78 // GLib type system expects a module to never be disposed if types has been
79 // successfully loaded.
80 // The following code prevents the Rust wrapper (`glib::TypeModule` subclass)
81 // to dispose the module when dropped by ensuring the reference count is > 1.
82 // Nothing is done if loading types has failed, allowing application to drop
83 // and dispose the invalid module.
84 if res && (*(type_module as *const gobject_ffi::GObject)).ref_count == 1 {
85 unsafe {
86 gobject_ffi::g_object_ref(type_module as _);
87 }
88 }
89
90 res.into_glib()
91}
92
93unsafe extern "C" fn unload<T: TypeModuleImpl>(type_module: *mut gobject_ffi::GTypeModule) {
94 let instance = &*(type_module as *mut T::Instance);
95 let imp = instance.imp();
96
97 imp.unload();
98}
99
100#[cfg(test)]
101mod tests {
102 use crate as glib;
103
104 use super::*;
105
106 mod imp {
107 use super::*;
108
109 #[derive(Default)]
110 pub struct SimpleModule;
111
112 #[crate::object_subclass]
113 impl ObjectSubclass for SimpleModule {
114 const NAME: &'static str = "SimpleModule";
115 type Type = super::SimpleModule;
116 type ParentType = TypeModule;
117 type Interfaces = (crate::TypePlugin,);
118 }
119
120 impl ObjectImpl for SimpleModule {}
121
122 impl TypePluginImpl for SimpleModule {}
123
124 impl TypeModuleImpl for SimpleModule {
125 fn load(&self) -> bool {
126 // register types on implementation load
127 SimpleModuleType::on_implementation_load(self.obj().upcast_ref::<TypeModule>())
128 }
129
130 fn unload(&self) {
131 // unregister types on implementation unload
132 SimpleModuleType::on_implementation_unload(self.obj().upcast_ref::<TypeModule>());
133 }
134 }
135
136 #[derive(Default)]
137 pub struct SimpleModuleType;
138
139 #[crate::object_subclass]
140 #[object_subclass_dynamic]
141 impl ObjectSubclass for SimpleModuleType {
142 const NAME: &'static str = "SimpleModuleType";
143 type Type = super::SimpleModuleType;
144 }
145
146 impl ObjectImpl for SimpleModuleType {}
147 }
148
149 crate::wrapper! {
150 pub struct SimpleModule(ObjectSubclass<imp::SimpleModule>)
151 @extends TypeModule, @implements crate::TypePlugin;
152 }
153
154 crate::wrapper! {
155 pub struct SimpleModuleType(ObjectSubclass<imp::SimpleModuleType>);
156 }
157
158 #[test]
159 fn test_module() {
160 assert!(!imp::SimpleModuleType::type_().is_valid());
161 let simple_module = glib::Object::new::<SimpleModule>();
162 // simulates the GLib type system to load the module.
163 assert!(TypeModuleExt::use_(&simple_module));
164 assert!(imp::SimpleModuleType::type_().is_valid());
165 TypeModuleExt::unuse(&simple_module);
166 }
167}