gio/subclass/
initable.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::ptr;
4
5use glib::{prelude::*, subclass::prelude::*, translate::*, Error};
6
7use crate::{ffi, Cancellable, Initable};
8
9pub trait InitableImpl: ObjectImpl {
10    fn init(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
11        self.parent_init(cancellable)
12    }
13}
14
15mod sealed {
16    pub trait Sealed {}
17    impl<T: super::InitableImplExt> Sealed for T {}
18}
19
20pub trait InitableImplExt: sealed::Sealed + ObjectSubclass {
21    fn parent_init(&self, cancellable: Option<&Cancellable>) -> Result<(), Error> {
22        unsafe {
23            let type_data = Self::type_data();
24            let parent_iface =
25                type_data.as_ref().parent_interface::<Initable>() as *const ffi::GInitableIface;
26
27            let func = (*parent_iface)
28                .init
29                .expect("no parent \"init\" implementation");
30
31            let mut err = ptr::null_mut();
32            func(
33                self.obj().unsafe_cast_ref::<Initable>().to_glib_none().0,
34                cancellable.to_glib_none().0,
35                &mut err,
36            );
37
38            if err.is_null() {
39                Ok(())
40            } else {
41                Err(from_glib_full(err))
42            }
43        }
44    }
45}
46
47impl<T: InitableImpl> InitableImplExt for T {}
48
49unsafe impl<T: InitableImpl> IsImplementable<T> for Initable {
50    fn interface_init(iface: &mut glib::Interface<Self>) {
51        let iface = iface.as_mut();
52        iface.init = Some(initable_init::<T>);
53    }
54}
55
56unsafe extern "C" fn initable_init<T: InitableImpl>(
57    initable: *mut ffi::GInitable,
58    cancellable: *mut ffi::GCancellable,
59    error: *mut *mut glib::ffi::GError,
60) -> glib::ffi::gboolean {
61    let instance = &*(initable as *mut T::Instance);
62    let imp = instance.imp();
63
64    match imp.init(
65        Option::<Cancellable>::from_glib_borrow(cancellable)
66            .as_ref()
67            .as_ref(),
68    ) {
69        Ok(()) => glib::ffi::GTRUE,
70        Err(e) => {
71            if !error.is_null() {
72                *error = e.into_glib_ptr();
73            }
74            glib::ffi::GFALSE
75        }
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use crate::{prelude::*, Cancellable, Initable};
83
84    pub mod imp {
85        use std::cell::Cell;
86
87        use super::*;
88
89        pub struct InitableTestType(pub Cell<u64>);
90
91        #[glib::object_subclass]
92        impl ObjectSubclass for InitableTestType {
93            const NAME: &'static str = "InitableTestType";
94            type Type = super::InitableTestType;
95            type Interfaces = (Initable,);
96
97            fn new() -> Self {
98                Self(Cell::new(0))
99            }
100        }
101
102        impl InitableImpl for InitableTestType {
103            fn init(&self, _cancellable: Option<&Cancellable>) -> Result<(), glib::Error> {
104                self.0.set(0x123456789abcdef);
105                Ok(())
106            }
107        }
108
109        impl ObjectImpl for InitableTestType {}
110    }
111
112    pub mod ffi {
113        use super::*;
114        pub type InitableTestType = <imp::InitableTestType as ObjectSubclass>::Instance;
115
116        pub unsafe extern "C" fn initable_test_type_get_value(this: *mut InitableTestType) -> u64 {
117            let this = super::InitableTestType::from_glib_borrow(this);
118            this.imp().0.get()
119        }
120    }
121
122    glib::wrapper! {
123        pub struct InitableTestType(ObjectSubclass<imp::InitableTestType>)
124            @implements Initable;
125    }
126
127    #[allow(clippy::new_without_default)]
128    impl InitableTestType {
129        pub fn new() -> Self {
130            Initable::new(Option::<&Cancellable>::None)
131                .expect("Failed creation/initialization of InitableTestType object")
132        }
133
134        pub unsafe fn new_uninit() -> Self {
135            // This creates an uninitialized InitableTestType object, for testing
136            // purposes. In real code, using Initable::new (like the new() method
137            // does) is recommended.
138            glib::Object::new_internal(Self::static_type(), &mut [])
139                .downcast()
140                .unwrap()
141        }
142
143        pub fn value(&self) -> u64 {
144            self.imp().0.get()
145        }
146    }
147
148    #[test]
149    fn test_initable_with_init() {
150        let res = unsafe {
151            let test = InitableTestType::new_uninit();
152
153            assert_ne!(0x123456789abcdef, test.value());
154
155            test.init(Option::<&Cancellable>::None).map(|_| test)
156        };
157        assert!(res.is_ok());
158        let test = res.unwrap();
159
160        assert_eq!(0x123456789abcdef, test.value());
161    }
162
163    #[test]
164    fn test_initable_with_initable_new() {
165        let test = InitableTestType::new();
166        assert_eq!(0x123456789abcdef, test.value());
167    }
168
169    #[test]
170    #[should_panic = ""]
171    fn test_initable_new_failure() {
172        let value: u32 = 2;
173        let _ = Initable::builder::<InitableTestType>()
174            .property("invalid-property", value)
175            .build(Option::<&Cancellable>::None);
176        unreachable!();
177    }
178
179    #[test]
180    fn test_initable_with_initable_with_type() {
181        let test = Initable::with_type(
182            InitableTestType::static_type(),
183            Option::<&Cancellable>::None,
184        )
185        .expect("Failed creation/initialization of InitableTestType object from type")
186        .downcast::<InitableTestType>()
187        .expect("Failed downcast of InitableTestType object");
188        assert_eq!(0x123456789abcdef, test.value());
189    }
190
191    #[test]
192    fn test_initable_with_initable_with_values() {
193        let test = Initable::with_type(
194            InitableTestType::static_type(),
195            Option::<&Cancellable>::None,
196        )
197        .expect("Failed creation/initialization of InitableTestType object from values")
198        .downcast::<InitableTestType>()
199        .expect("Failed downcast of InitableTestType object");
200        assert_eq!(0x123456789abcdef, test.value());
201    }
202
203    #[test]
204    fn test_initable_through_ffi() {
205        unsafe {
206            let test = InitableTestType::new_uninit();
207            let test: *mut ffi::InitableTestType = test.as_ptr();
208            let mut error: *mut glib::ffi::GError = std::ptr::null_mut();
209
210            assert_ne!(0x123456789abcdef, ffi::initable_test_type_get_value(test));
211
212            let result = crate::ffi::g_initable_init(
213                test as *mut crate::ffi::GInitable,
214                std::ptr::null_mut(),
215                &mut error,
216            );
217
218            assert_eq!(glib::ffi::GTRUE, result);
219            assert_eq!(error, ptr::null_mut());
220            assert_eq!(0x123456789abcdef, ffi::initable_test_type_get_value(test));
221        }
222    }
223}