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