glib/subclass/
type_module.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// Take a look at the license at the top of the repository in the LICENSE file.

use crate::{ffi, gobject_ffi, prelude::*, subclass::prelude::*, translate::*, Object, TypeModule};

pub trait TypeModuleImpl: ObjectImpl
where
    <Self as ObjectSubclass>::Type: IsA<Object>,
    <Self as ObjectSubclass>::Type: IsA<TypeModule>,
{
    // rustdoc-stripper-ignore-next
    /// Loads the module, registers one or more object subclasses using
    /// [`register_dynamic_type`] and registers one or more object interfaces
    /// using [`register_dynamic_interface`] (see [`TypeModule`]).
    ///
    /// [`register_dynamic_type`]: ../types/fn.register_dynamic_type.html
    /// [`register_dynamic_interface`]: ../interface/fn.register_dynamic_interface.html
    /// [`TypeModule`]: ../../gobject/auto/type_module/struct.TypeModule.html
    // rustdoc-stripper-ignore-next-stop
    /// loads the module and registers one or more types using
    ///  [`TypeModuleExtManual::register_type()`][crate::prelude::TypeModuleExtManual::register_type()].
    fn load(&self) -> bool;

    // rustdoc-stripper-ignore-next
    /// Unloads the module (see [`TypeModuleExt::unuse`]).
    ///
    /// [`TypeModuleExt::unuse`]: ../../gobject/auto/type_module/trait.TypeModuleExt.html#method.unuse
    // rustdoc-stripper-ignore-next-stop
    /// unloads the module
    fn unload(&self);
}

pub trait TypeModuleImplExt: ObjectSubclass + TypeModuleImpl
where
    <Self as ObjectSubclass>::Type: IsA<Object>,
    <Self as ObjectSubclass>::Type: IsA<TypeModule>,
{
    fn parent_load(&self) -> bool;
    fn parent_unload(&self);
}

impl<T: TypeModuleImpl> TypeModuleImplExt for T
where
    <Self as ObjectSubclass>::Type: IsA<Object>,
    <Self as ObjectSubclass>::Type: IsA<TypeModule>,
{
    fn parent_load(&self) -> bool {
        unsafe {
            let data = T::type_data();
            let parent_class = data.as_ref().parent_class() as *const gobject_ffi::GTypeModuleClass;

            let f = (*parent_class)
                .load
                .expect("No parent class implementation for \"load\"");

            from_glib(f(self
                .obj()
                .unsafe_cast_ref::<TypeModule>()
                .to_glib_none()
                .0))
        }
    }

    fn parent_unload(&self) {
        unsafe {
            let data = T::type_data();
            let parent_class = data.as_ref().parent_class() as *const gobject_ffi::GTypeModuleClass;

            let f = (*parent_class)
                .unload
                .expect("No parent class implementation for \"unload\"");

            f(self.obj().unsafe_cast_ref::<TypeModule>().to_glib_none().0);
        }
    }
}

unsafe impl<T: TypeModuleImpl> IsSubclassable<T> for TypeModule
where
    <T as ObjectSubclass>::Type: IsA<Object>,
    <T as ObjectSubclass>::Type: IsA<TypeModule>,
{
    fn class_init(class: &mut crate::Class<Self>) {
        Self::parent_class_init::<T>(class);

        let klass = class.as_mut();
        klass.load = Some(load::<T>);
        klass.unload = Some(unload::<T>);
    }
}

unsafe extern "C" fn load<T: TypeModuleImpl>(
    type_module: *mut gobject_ffi::GTypeModule,
) -> ffi::gboolean
where
    <T as ObjectSubclass>::Type: IsA<Object>,
    <T as ObjectSubclass>::Type: IsA<TypeModule>,
{
    let instance = &*(type_module as *mut T::Instance);
    let imp = instance.imp();

    let res = imp.load();
    // GLib type system expects a module to never be disposed if types has been
    // successfully loaded.
    // The following code prevents the Rust wrapper (`glib::TypeModule` subclass)
    // to dispose the module when dropped by ensuring the reference count is > 1.
    // Nothing is done if loading types has failed, allowing application to drop
    // and dispose the invalid module.
    if res && (*(type_module as *const gobject_ffi::GObject)).ref_count == 1 {
        unsafe {
            gobject_ffi::g_object_ref(type_module as _);
        }
    }

    res.into_glib()
}

unsafe extern "C" fn unload<T: TypeModuleImpl>(type_module: *mut gobject_ffi::GTypeModule)
where
    <T as ObjectSubclass>::Type: IsA<Object>,
    <T as ObjectSubclass>::Type: IsA<TypeModule>,
{
    let instance = &*(type_module as *mut T::Instance);
    let imp = instance.imp();

    imp.unload();
}

#[cfg(test)]
mod tests {
    use crate as glib;

    use super::*;

    mod imp {
        use super::*;

        #[derive(Default)]
        pub struct SimpleModule;

        #[crate::object_subclass]
        impl ObjectSubclass for SimpleModule {
            const NAME: &'static str = "SimpleModule";
            type Type = super::SimpleModule;
            type ParentType = TypeModule;
            type Interfaces = (crate::TypePlugin,);
        }

        impl ObjectImpl for SimpleModule {}

        impl TypePluginImpl for SimpleModule {}

        impl TypeModuleImpl for SimpleModule {
            fn load(&self) -> bool {
                // register types on implementation load
                SimpleModuleType::on_implementation_load(self.obj().upcast_ref::<TypeModule>())
            }

            fn unload(&self) {
                // unregister types on implementation unload
                SimpleModuleType::on_implementation_unload(self.obj().upcast_ref::<TypeModule>());
            }
        }

        #[derive(Default)]
        pub struct SimpleModuleType;

        #[crate::object_subclass]
        #[object_subclass_dynamic]
        impl ObjectSubclass for SimpleModuleType {
            const NAME: &'static str = "SimpleModuleType";
            type Type = super::SimpleModuleType;
        }

        impl ObjectImpl for SimpleModuleType {}
    }

    crate::wrapper! {
        pub struct SimpleModule(ObjectSubclass<imp::SimpleModule>)
        @extends TypeModule, @implements crate::TypePlugin;
    }

    crate::wrapper! {
        pub struct SimpleModuleType(ObjectSubclass<imp::SimpleModuleType>);
    }

    #[test]
    fn test_module() {
        assert!(!imp::SimpleModuleType::type_().is_valid());
        let simple_module = glib::Object::new::<SimpleModule>();
        // simulates the GLib type system to load the module.
        assert!(TypeModuleExt::use_(&simple_module));
        assert!(imp::SimpleModuleType::type_().is_valid());
        TypeModuleExt::unuse(&simple_module);
    }
}