1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 use crate::AsyncResult;
4 use crate::Cancellable;
5 use crate::Task;
6 use glib::object::IsA;
7 use glib::translate::*;
8 use libc::c_void;
9 use std::boxed::Box as Box_;
10 use std::ptr;
11 
12 impl Task {
13     #[doc(alias = "g_task_new")]
new<P: IsA<Cancellable>, Q: FnOnce(&AsyncResult, Option<&glib::Object>) + 'static>( source_object: Option<&glib::Object>, cancellable: Option<&P>, callback: Q, ) -> Task14     pub fn new<P: IsA<Cancellable>, Q: FnOnce(&AsyncResult, Option<&glib::Object>) + 'static>(
15         source_object: Option<&glib::Object>,
16         cancellable: Option<&P>,
17         callback: Q,
18     ) -> Task {
19         let callback_data = Box_::new(callback);
20         unsafe extern "C" fn trampoline<
21             Q: FnOnce(&AsyncResult, Option<&glib::Object>) + 'static,
22         >(
23             source_object: *mut glib::gobject_ffi::GObject,
24             res: *mut ffi::GAsyncResult,
25             user_data: glib::ffi::gpointer,
26         ) {
27             let source_object = Option::<glib::Object>::from_glib_borrow(source_object);
28             let res = AsyncResult::from_glib_borrow(res);
29             let callback: Box_<Q> = Box::from_raw(user_data as *mut _);
30             callback(&res, source_object.as_ref().as_ref());
31         }
32         let callback = trampoline::<Q>;
33         unsafe {
34             from_glib_full(ffi::g_task_new(
35                 source_object.to_glib_none().0,
36                 cancellable.map(|p| p.as_ref()).to_glib_none().0,
37                 Some(callback),
38                 Box_::into_raw(callback_data) as *mut _,
39             ))
40         }
41     }
42 
43     #[doc(alias = "g_task_return_error")]
return_error(&self, error: glib::Error)44     pub fn return_error(&self, error: glib::Error) {
45         unsafe {
46             ffi::g_task_return_error(self.to_glib_none().0, error.to_glib_full() as *mut _);
47         }
48     }
49 
50     #[doc(alias = "get_priority")]
51     #[doc(alias = "g_task_get_priority")]
priority(&self) -> glib::source::Priority52     pub fn priority(&self) -> glib::source::Priority {
53         unsafe { FromGlib::from_glib(ffi::g_task_get_priority(self.to_glib_none().0)) }
54     }
55 
56     #[doc(alias = "g_task_set_priority")]
set_priority(&self, priority: glib::source::Priority)57     pub fn set_priority(&self, priority: glib::source::Priority) {
58         unsafe {
59             ffi::g_task_set_priority(self.to_glib_none().0, priority.into_glib());
60         }
61     }
62 
return_value(&self, result: &glib::Value)63     pub fn return_value(&self, result: &glib::Value) {
64         unsafe extern "C" fn value_free(value: *mut c_void) {
65             glib::gobject_ffi::g_value_unset(value as *mut glib::gobject_ffi::GValue);
66             glib::ffi::g_free(value);
67         }
68         unsafe {
69             let value: *mut glib::gobject_ffi::GValue =
70                 <&glib::Value>::to_glib_full_from_slice(&[result]);
71             ffi::g_task_return_pointer(
72                 self.to_glib_none().0,
73                 value as *mut c_void,
74                 Some(value_free),
75             )
76         }
77     }
78 
propagate_value(&self) -> Result<glib::Value, glib::Error>79     pub fn propagate_value(&self) -> Result<glib::Value, glib::Error> {
80         unsafe {
81             let mut error = ptr::null_mut();
82             let value = ffi::g_task_propagate_pointer(self.to_glib_none().0, &mut error);
83             if !error.is_null() {
84                 return Err(from_glib_full(error));
85             }
86             let value = from_glib_full(value as *mut glib::gobject_ffi::GValue);
87             match value {
88                 Some(value) => Ok(value),
89                 None => Ok(glib::Value::from_type(glib::types::Type::UNIT)),
90             }
91         }
92     }
93 }
94 
95 #[cfg(test)]
96 mod test {
97     use super::*;
98     use crate::prelude::*;
99     use crate::test_util::run_async_local;
100 
101     #[test]
test_int_async_result()102     fn test_int_async_result() {
103         match run_async_local(|tx, l| {
104             let c = crate::Cancellable::new();
105             let t = crate::Task::new(
106                 None,
107                 Some(&c),
108                 move |a: &AsyncResult, _b: Option<&glib::Object>| {
109                     let t = a.downcast_ref::<crate::Task>().unwrap();
110                     tx.send(t.propagate_value()).unwrap();
111                     l.quit();
112                 },
113             );
114             t.return_value(&100_i32.to_value());
115         }) {
116             Err(_) => panic!(),
117             Ok(i) => {
118                 assert_eq!(i.get::<i32>().unwrap(), 100);
119             }
120         }
121     }
122 
123     #[test]
test_object_async_result()124     fn test_object_async_result() {
125         use glib::subclass::prelude::*;
126         pub struct MySimpleObjectPrivate {
127             pub size: std::cell::RefCell<Option<i64>>,
128         }
129 
130         #[glib::object_subclass]
131         impl ObjectSubclass for MySimpleObjectPrivate {
132             const NAME: &'static str = "MySimpleObjectPrivate";
133             type ParentType = glib::Object;
134             type Type = MySimpleObject;
135 
136             fn new() -> Self {
137                 Self {
138                     size: std::cell::RefCell::new(Some(100)),
139                 }
140             }
141         }
142 
143         impl ObjectImpl for MySimpleObjectPrivate {}
144 
145         glib::wrapper! {
146             pub struct MySimpleObject(ObjectSubclass<MySimpleObjectPrivate>);
147         }
148 
149         impl MySimpleObject {
150             pub fn new() -> Self {
151                 glib::Object::new(&[]).expect("Failed to create MySimpleObject")
152             }
153 
154             #[doc(alias = "get_size")]
155             pub fn size(&self) -> Option<i64> {
156                 let imp = MySimpleObjectPrivate::from_instance(self);
157                 *imp.size.borrow()
158             }
159 
160             pub fn set_size(&self, size: i64) {
161                 let imp = MySimpleObjectPrivate::from_instance(self);
162                 imp.size.borrow_mut().replace(size);
163             }
164         }
165 
166         impl Default for MySimpleObject {
167             fn default() -> Self {
168                 Self::new()
169             }
170         }
171 
172         match run_async_local(|tx, l| {
173             let c = crate::Cancellable::new();
174             let t = crate::Task::new(
175                 None,
176                 Some(&c),
177                 move |a: &AsyncResult, _b: Option<&glib::Object>| {
178                     let t = a.downcast_ref::<crate::Task>().unwrap();
179                     tx.send(t.propagate_value()).unwrap();
180                     l.quit();
181                 },
182             );
183             let my_object = MySimpleObject::new();
184             my_object.set_size(100);
185             t.return_value(&my_object.upcast::<glib::Object>().to_value());
186         }) {
187             Err(_) => panic!(),
188             Ok(o) => {
189                 let o = o
190                     .get::<glib::Object>()
191                     .unwrap()
192                     .downcast::<MySimpleObject>()
193                     .unwrap();
194 
195                 assert_eq!(o.size(), Some(100));
196             }
197         }
198     }
199 
200     #[test]
test_error()201     fn test_error() {
202         match run_async_local(|tx, l| {
203             let c = crate::Cancellable::new();
204             let t = crate::Task::new(
205                 None,
206                 Some(&c),
207                 move |a: &AsyncResult, _b: Option<&glib::Object>| {
208                     let t = a.downcast_ref::<crate::Task>().unwrap();
209                     tx.send(t.propagate_value()).unwrap();
210                     l.quit();
211                 },
212             );
213             t.return_error(glib::Error::new(
214                 crate::IOErrorEnum::WouldBlock,
215                 "WouldBlock",
216             ));
217         }) {
218             Err(e) => match e.kind().unwrap() {
219                 crate::IOErrorEnum::WouldBlock => {}
220                 _ => panic!(),
221             },
222             Ok(_) => panic!(),
223         }
224     }
225 
226     #[test]
test_cancelled()227     fn test_cancelled() {
228         match run_async_local(|tx, l| {
229             let c = crate::Cancellable::new();
230             let t = crate::Task::new(
231                 None,
232                 Some(&c),
233                 move |a: &AsyncResult, _b: Option<&glib::Object>| {
234                     let t = a.downcast_ref::<crate::Task>().unwrap();
235                     tx.send(t.propagate_value()).unwrap();
236                     l.quit();
237                 },
238             );
239             c.cancel();
240             t.return_error_if_cancelled();
241         }) {
242             Err(e) => match e.kind().unwrap() {
243                 crate::IOErrorEnum::Cancelled => {}
244                 _ => panic!(),
245             },
246             Ok(_) => panic!(),
247         }
248     }
249 }
250