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