gio/subclass/
initable.rs
1use 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 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}