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    ffi, gobject_ffi, prelude::*, subclass::prelude::*, translate::*, Interface, InterfaceInfo,
6    Object, Type, TypeFlags, TypeInfo, TypePlugin, TypeValueTable,
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    let instance = &*(type_plugin as *mut T::Instance);
129    let imp = instance.imp();
130
131    imp.use_plugin();
132}
133
134unsafe extern "C" fn unuse_plugin<T: TypePluginImpl>(type_plugin: *mut gobject_ffi::GTypePlugin) {
135    let instance = &*(type_plugin as *mut T::Instance);
136    let imp = instance.imp();
137
138    imp.unuse_plugin();
139}
140
141unsafe extern "C" fn complete_type_info<T: TypePluginImpl>(
142    type_plugin: *mut gobject_ffi::GTypePlugin,
143    gtype: ffi::GType,
144    info_ptr: *mut gobject_ffi::GTypeInfo,
145    value_table_ptr: *mut gobject_ffi::GTypeValueTable,
146) {
147    assert!(!info_ptr.is_null());
148    assert!(!value_table_ptr.is_null());
149    let instance = &*(type_plugin as *mut T::Instance);
150    let imp = instance.imp();
151    let type_ = Type::from_glib(gtype);
152    let info = TypeInfo::from_glib_ptr_borrow_mut(info_ptr);
153    let value_table = TypeValueTable::from_glib_ptr_borrow_mut(value_table_ptr);
154
155    let (info_, value_table_) = imp.complete_type_info(type_);
156
157    *info = info_;
158    *value_table = value_table_;
159}
160
161unsafe extern "C" fn complete_interface_info<T: TypePluginImpl>(
162    type_plugin: *mut gobject_ffi::GTypePlugin,
163    instance_gtype: ffi::GType,
164    interface_gtype: ffi::GType,
165    info_ptr: *mut gobject_ffi::GInterfaceInfo,
166) {
167    assert!(!info_ptr.is_null());
168    let instance = &*(type_plugin as *mut T::Instance);
169    let imp = instance.imp();
170    let instance_type = Type::from_glib(instance_gtype);
171    let interface_type = Type::from_glib(interface_gtype);
172    let info = InterfaceInfo::from_glib_ptr_borrow_mut(info_ptr);
173
174    let info_ = imp.complete_interface_info(instance_type, interface_type);
175    *info = info_;
176}
177
178pub trait TypePluginRegisterImpl:
179    TypePluginImpl + ObjectSubclass<Type: IsA<Object> + IsA<TypePlugin>>
180{
181    fn add_dynamic_interface(
182        &self,
183        _instance_type: Type,
184        _interface_type: Type,
185        _interface_info: &InterfaceInfo,
186    ) {
187        unimplemented!()
188    }
189    fn register_dynamic_enum(
190        &self,
191        _name: &str,
192        _const_static_values: &'static EnumValues,
193    ) -> Type {
194        unimplemented!()
195    }
196    fn register_dynamic_flags(
197        &self,
198        _name: &str,
199        _const_static_values: &'static FlagsValues,
200    ) -> Type {
201        unimplemented!()
202    }
203    fn register_dynamic_type(
204        &self,
205        _parent_type: Type,
206        _type_name: &str,
207        _type_info: &TypeInfo,
208        _flags: TypeFlags,
209    ) -> Type {
210        unimplemented!()
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use crate::{self as glib, prelude::TypePluginExt};
217
218    use super::*;
219
220    mod imp {
221        use super::*;
222
223        #[derive(Default)]
224        pub struct SimplePlugin {
225            type_info: std::cell::Cell<Option<TypeInfo>>,
226        }
227
228        #[crate::object_subclass]
229        impl ObjectSubclass for SimplePlugin {
230            const NAME: &'static str = "SimplePlugin";
231            type Type = super::SimplePlugin;
232            type Interfaces = (TypePlugin,);
233        }
234
235        impl ObjectImpl for SimplePlugin {}
236
237        impl TypePluginImpl for SimplePlugin {
238            fn use_plugin(&self) {
239                // registers types on implementation load
240                SimplePluginType::on_implementation_load(self.obj().as_ref());
241            }
242
243            fn unuse_plugin(&self) {
244                // unregisters types on implementation unload
245                SimplePluginType::on_implementation_unload(self.obj().as_ref());
246            }
247
248            fn complete_type_info(&self, _type_: Type) -> (TypeInfo, TypeValueTable) {
249                assert!(self.type_info.get().is_some());
250                // returns type info
251                (self.type_info.get().unwrap(), TypeValueTable::default())
252            }
253        }
254
255        impl TypePluginRegisterImpl for SimplePlugin {
256            fn register_dynamic_type(
257                &self,
258                parent_type: Type,
259                type_name: &str,
260                type_info: &TypeInfo,
261                flags: TypeFlags,
262            ) -> Type {
263                let type_ = Type::from_name(type_name).unwrap_or_else(|| {
264                    Type::register_dynamic(
265                        parent_type,
266                        type_name,
267                        self.obj().upcast_ref::<TypePlugin>(),
268                        flags,
269                    )
270                });
271                if type_.is_valid() {
272                    // save type info
273                    self.type_info.set(Some(*type_info));
274                }
275                type_
276            }
277        }
278
279        #[derive(Default)]
280        pub struct SimplePluginType;
281
282        #[crate::object_subclass]
283        #[object_subclass_dynamic(plugin_type = super::SimplePlugin)]
284        impl ObjectSubclass for SimplePluginType {
285            const NAME: &'static str = "SimplePluginType";
286            type Type = super::SimplePluginType;
287        }
288
289        impl ObjectImpl for SimplePluginType {}
290    }
291
292    crate::wrapper! {
293        pub struct SimplePlugin(ObjectSubclass<imp::SimplePlugin>)
294        @implements TypePlugin;
295    }
296
297    crate::wrapper! {
298        pub struct SimplePluginType(ObjectSubclass<imp::SimplePluginType>);
299    }
300
301    #[test]
302    fn test_plugin() {
303        assert!(!imp::SimplePluginType::type_().is_valid());
304        let simple_plugin = crate::Object::new::<SimplePlugin>();
305        // simulates the GLib type system to use the plugin.
306        TypePluginExt::use_(&simple_plugin);
307        assert!(imp::SimplePluginType::type_().is_valid());
308        TypePluginExt::unuse(&simple_plugin);
309    }
310}