glib/subclass/
type_plugin.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use crate::enums::{EnumValues, FlagsValues};
4use crate::{
5    Interface, InterfaceInfo, Object, Type, TypeFlags, TypeInfo, TypePlugin, TypeValueTable, ffi,
6    gobject_ffi, prelude::*, subclass::prelude::*, translate::*,
7};
8
9pub trait TypePluginImpl: ObjectImpl + ObjectSubclass<Type: IsA<Object> + IsA<TypePlugin>> {
10    fn use_plugin(&self) {
11        self.parent_use_plugin();
12    }
13
14    fn unuse_plugin(&self) {
15        self.parent_unuse_plugin();
16    }
17
18    fn complete_type_info(&self, type_: Type) -> (TypeInfo, TypeValueTable) {
19        self.parent_complete_type_info(type_)
20    }
21
22    fn complete_interface_info(&self, instance_type: Type, interface_type: Type) -> InterfaceInfo {
23        self.parent_complete_interface_info(instance_type, interface_type)
24    }
25}
26
27pub trait TypePluginImplExt: TypePluginImpl {
28    fn parent_use_plugin(&self);
29    fn parent_unuse_plugin(&self);
30    fn parent_complete_type_info(&self, type_: Type) -> (TypeInfo, TypeValueTable);
31    fn parent_complete_interface_info(
32        &self,
33        instance_type: Type,
34        interface_type: Type,
35    ) -> InterfaceInfo;
36}
37
38impl<T: TypePluginImpl> TypePluginImplExt for T {
39    fn parent_use_plugin(&self) {
40        unsafe {
41            let type_data = Self::type_data();
42            let parent_iface = type_data.as_ref().parent_interface::<TypePlugin>()
43                as *const gobject_ffi::GTypePluginClass;
44
45            let f = (*parent_iface)
46                .use_plugin
47                .expect("no parent \"use_plugin\" implementation");
48
49            f(self.obj().unsafe_cast_ref::<TypePlugin>().to_glib_none().0)
50        }
51    }
52
53    fn parent_unuse_plugin(&self) {
54        unsafe {
55            let type_data = Self::type_data();
56            let parent_iface = type_data.as_ref().parent_interface::<TypePlugin>()
57                as *const gobject_ffi::GTypePluginClass;
58
59            let f = (*parent_iface)
60                .unuse_plugin
61                .expect("no parent \"unuse_plugin\" implementation");
62
63            f(self.obj().unsafe_cast_ref::<TypePlugin>().to_glib_none().0)
64        }
65    }
66
67    fn parent_complete_type_info(&self, type_: Type) -> (TypeInfo, TypeValueTable) {
68        unsafe {
69            let type_data = Self::type_data();
70            let parent_iface = type_data.as_ref().parent_interface::<TypePlugin>()
71                as *const gobject_ffi::GTypePluginClass;
72
73            let f = (*parent_iface)
74                .complete_type_info
75                .expect("no parent \"complete_type_info\" implementation");
76
77            let info = TypeInfo::default();
78            let value_table = TypeValueTable::default();
79            f(
80                self.obj().unsafe_cast_ref::<TypePlugin>().to_glib_none().0,
81                type_.into_glib(),
82                info.as_ptr(),
83                value_table.as_ptr(),
84            );
85
86            (info, value_table)
87        }
88    }
89
90    fn parent_complete_interface_info(
91        &self,
92        instance_type: Type,
93        interface_type: Type,
94    ) -> InterfaceInfo {
95        let info = InterfaceInfo::default();
96        unsafe {
97            let type_data = Self::type_data();
98            let parent_iface = type_data.as_ref().parent_interface::<TypePlugin>()
99                as *const gobject_ffi::GTypePluginClass;
100
101            let f = (*parent_iface)
102                .complete_interface_info
103                .expect("no parent \"complete_interface_info\" implementation");
104
105            f(
106                self.obj().unsafe_cast_ref::<TypePlugin>().to_glib_none().0,
107                instance_type.into_glib(),
108                interface_type.into_glib(),
109                info.as_ptr(),
110            )
111        }
112        info
113    }
114}
115
116unsafe impl<T: TypePluginImpl> IsImplementable<T> for TypePlugin {
117    fn interface_init(iface: &mut Interface<Self>) {
118        let iface = iface.as_mut();
119
120        iface.use_plugin = Some(use_plugin::<T>);
121        iface.unuse_plugin = Some(unuse_plugin::<T>);
122        iface.complete_type_info = Some(complete_type_info::<T>);
123        iface.complete_interface_info = Some(complete_interface_info::<T>);
124    }
125}
126
127unsafe extern "C" fn use_plugin<T: TypePluginImpl>(type_plugin: *mut gobject_ffi::GTypePlugin) {
128    unsafe {
129        let instance = &*(type_plugin as *mut T::Instance);
130        let imp = instance.imp();
131
132        imp.use_plugin();
133    }
134}
135
136unsafe extern "C" fn unuse_plugin<T: TypePluginImpl>(type_plugin: *mut gobject_ffi::GTypePlugin) {
137    unsafe {
138        let instance = &*(type_plugin as *mut T::Instance);
139        let imp = instance.imp();
140
141        imp.unuse_plugin();
142    }
143}
144
145unsafe extern "C" fn complete_type_info<T: TypePluginImpl>(
146    type_plugin: *mut gobject_ffi::GTypePlugin,
147    gtype: ffi::GType,
148    info_ptr: *mut gobject_ffi::GTypeInfo,
149    value_table_ptr: *mut gobject_ffi::GTypeValueTable,
150) {
151    unsafe {
152        assert!(!info_ptr.is_null());
153        assert!(!value_table_ptr.is_null());
154        let instance = &*(type_plugin as *mut T::Instance);
155        let imp = instance.imp();
156        let type_ = Type::from_glib(gtype);
157        let info = TypeInfo::from_glib_ptr_borrow_mut(info_ptr);
158        let value_table = TypeValueTable::from_glib_ptr_borrow_mut(value_table_ptr);
159
160        let (info_, value_table_) = imp.complete_type_info(type_);
161
162        *info = info_;
163        *value_table = value_table_;
164    }
165}
166
167unsafe extern "C" fn complete_interface_info<T: TypePluginImpl>(
168    type_plugin: *mut gobject_ffi::GTypePlugin,
169    instance_gtype: ffi::GType,
170    interface_gtype: ffi::GType,
171    info_ptr: *mut gobject_ffi::GInterfaceInfo,
172) {
173    unsafe {
174        assert!(!info_ptr.is_null());
175        let instance = &*(type_plugin as *mut T::Instance);
176        let imp = instance.imp();
177        let instance_type = Type::from_glib(instance_gtype);
178        let interface_type = Type::from_glib(interface_gtype);
179        let info = InterfaceInfo::from_glib_ptr_borrow_mut(info_ptr);
180
181        let info_ = imp.complete_interface_info(instance_type, interface_type);
182        *info = info_;
183    }
184}
185
186pub trait TypePluginRegisterImpl:
187    TypePluginImpl + ObjectSubclass<Type: IsA<Object> + IsA<TypePlugin>>
188{
189    fn add_dynamic_interface(
190        &self,
191        _instance_type: Type,
192        _interface_type: Type,
193        _interface_info: &InterfaceInfo,
194    ) {
195        unimplemented!()
196    }
197    fn register_dynamic_enum(
198        &self,
199        _name: &str,
200        _const_static_values: &'static EnumValues,
201    ) -> Type {
202        unimplemented!()
203    }
204    fn register_dynamic_flags(
205        &self,
206        _name: &str,
207        _const_static_values: &'static FlagsValues,
208    ) -> Type {
209        unimplemented!()
210    }
211    fn register_dynamic_type(
212        &self,
213        _parent_type: Type,
214        _type_name: &str,
215        _type_info: &TypeInfo,
216        _flags: TypeFlags,
217    ) -> Type {
218        unimplemented!()
219    }
220}
221
222#[cfg(test)]
223mod tests {
224    use crate::{self as glib, prelude::TypePluginExt};
225
226    use super::*;
227
228    mod imp {
229        use super::*;
230
231        #[derive(Default)]
232        pub struct SimplePlugin {
233            type_info: std::cell::Cell<Option<TypeInfo>>,
234        }
235
236        #[crate::object_subclass]
237        impl ObjectSubclass for SimplePlugin {
238            const NAME: &'static str = "SimplePlugin";
239            type Type = super::SimplePlugin;
240            type Interfaces = (TypePlugin,);
241        }
242
243        impl ObjectImpl for SimplePlugin {}
244
245        impl TypePluginImpl for SimplePlugin {
246            fn use_plugin(&self) {
247                // registers types on implementation load
248                SimplePluginType::on_implementation_load(self.obj().as_ref());
249            }
250
251            fn unuse_plugin(&self) {
252                // unregisters types on implementation unload
253                SimplePluginType::on_implementation_unload(self.obj().as_ref());
254            }
255
256            fn complete_type_info(&self, _type_: Type) -> (TypeInfo, TypeValueTable) {
257                assert!(self.type_info.get().is_some());
258                // returns type info
259                (self.type_info.get().unwrap(), TypeValueTable::default())
260            }
261        }
262
263        impl TypePluginRegisterImpl for SimplePlugin {
264            fn register_dynamic_type(
265                &self,
266                parent_type: Type,
267                type_name: &str,
268                type_info: &TypeInfo,
269                flags: TypeFlags,
270            ) -> Type {
271                let type_ = Type::from_name(type_name).unwrap_or_else(|| {
272                    Type::register_dynamic(
273                        parent_type,
274                        type_name,
275                        self.obj().upcast_ref::<TypePlugin>(),
276                        flags,
277                    )
278                });
279                if type_.is_valid() {
280                    // save type info
281                    self.type_info.set(Some(*type_info));
282                }
283                type_
284            }
285        }
286
287        #[derive(Default)]
288        pub struct SimplePluginType;
289
290        #[crate::object_subclass]
291        #[object_subclass_dynamic(plugin_type = super::SimplePlugin)]
292        impl ObjectSubclass for SimplePluginType {
293            const NAME: &'static str = "SimplePluginType";
294            type Type = super::SimplePluginType;
295        }
296
297        impl ObjectImpl for SimplePluginType {}
298    }
299
300    crate::wrapper! {
301        pub struct SimplePlugin(ObjectSubclass<imp::SimplePlugin>)
302        @implements TypePlugin;
303    }
304
305    crate::wrapper! {
306        pub struct SimplePluginType(ObjectSubclass<imp::SimplePluginType>);
307    }
308
309    #[test]
310    fn test_plugin() {
311        assert!(!imp::SimplePluginType::type_().is_valid());
312        let simple_plugin = crate::Object::new::<SimplePlugin>();
313        // simulates the GLib type system to use the plugin.
314        TypePluginExt::use_(&simple_plugin);
315        assert!(imp::SimplePluginType::type_().is_valid());
316        TypePluginExt::unuse(&simple_plugin);
317    }
318}