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