1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use crate::{ffi, gobject_ffi, prelude::*, subclass::prelude::*, translate::*, TypeModule}; |
4 | |
5 | pub 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 | 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 | |
24 | pub trait TypeModuleImplExt: ObjectSubclass { |
25 | fn parent_load(&self) -> bool; |
26 | fn parent_unload(&self); |
27 | } |
28 | |
29 | impl<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 | |
61 | unsafe 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: &mut GTypeModuleClass = class.as_mut(); |
66 | klass.load = Some(load::<T>); |
67 | klass.unload = Some(unload::<T>); |
68 | } |
69 | } |
70 | |
71 | unsafe extern "C" fn load<T: TypeModuleImpl>( |
72 | type_module: *mut gobject_ffi::GTypeModule, |
73 | ) -> ffi::gboolean { |
74 | let instance: &::Instance = &*(type_module as *mut T::Instance); |
75 | let imp: &T = instance.imp(); |
76 | |
77 | let res: bool = 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(object:type_module as _); |
87 | } |
88 | } |
89 | |
90 | res.into_glib() |
91 | } |
92 | |
93 | unsafe extern "C" fn unload<T: TypeModuleImpl>(type_module: *mut gobject_ffi::GTypeModule) { |
94 | let instance: &::Instance = &*(type_module as *mut T::Instance); |
95 | let imp: &T = instance.imp(); |
96 | |
97 | imp.unload(); |
98 | } |
99 | |
100 | #[cfg (test)] |
101 | mod 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 | } |
168 | |