libpanel/subclass/
save_delegate.rs1use crate::{prelude::*, SaveDelegate};
2use glib::subclass::prelude::*;
3use glib::thread_guard::ThreadGuard;
4use glib::translate::*;
5use std::{future::Future, pin::Pin};
6
7pub trait SaveDelegateImpl: ObjectImpl {
8 fn save_future(&self) -> Pin<Box<dyn Future<Output = Result<(), glib::Error>> + 'static>> {
9 self.parent_save_future()
10 }
11}
12
13pub trait SaveDelegateImplExt: ObjectSubclass {
14 fn parent_save_future(
15 &self,
16 ) -> Pin<Box<dyn Future<Output = Result<(), glib::Error>> + 'static>>;
17}
18
19impl<T: SaveDelegateImpl> SaveDelegateImplExt for T {
20 fn parent_save_future(
21 &self,
22 ) -> Pin<Box<dyn Future<Output = Result<(), glib::Error>> + 'static>> {
23 unsafe {
24 let type_data = T::type_data();
25 let parent_class =
26 type_data.as_ref().parent_class() as *mut ffi::PanelSaveDelegateClass;
27 let save_async = (*parent_class)
28 .save_async
29 .expect("No parent class implementation for \"save_async\"");
30
31 unsafe extern "C" fn parent_save_async_callback<T>(
32 source_object: *mut glib::gobject_ffi::GObject,
33 res: *mut gio::ffi::GAsyncResult,
34 user_data: glib::ffi::gpointer,
35 ) where
36 T: SaveDelegateImpl,
37 {
38 let type_data = T::type_data();
39 let parent_class =
40 type_data.as_ref().parent_class() as *mut ffi::PanelSaveDelegateClass;
41 let save_finish = (*parent_class)
42 .save_finish
43 .expect("No parent class implementation for \"save_finish\"");
44
45 let ret: Box<ThreadGuard<gio::GioFutureResult<Result<(), glib::Error>>>> =
46 Box::from_raw(user_data as *mut _);
47 let ret = ret.into_inner();
48
49 let mut error = std::ptr::null_mut();
50 save_finish(source_object as *mut _, res, &mut error);
51 let result = if error.is_null() {
52 Ok(())
53 } else {
54 Err(from_glib_full(error))
55 };
56
57 ret.resolve(result);
58 }
59
60 Box::pin(gio::GioFuture::new(
61 &*self.obj(),
62 move |obj, cancellable, res| {
63 let user_data = Box::new(ThreadGuard::new(res));
64 save_async(
65 obj.unsafe_cast_ref::<SaveDelegate>().to_glib_none().0,
66 cancellable.to_glib_none().0,
67 Some(parent_save_async_callback::<T>),
68 Box::into_raw(user_data) as *mut _,
69 );
70 },
71 ))
72 }
73 }
74}
75
76unsafe impl<T: SaveDelegateImpl> IsSubclassable<T> for SaveDelegate {
77 fn class_init(class: &mut ::glib::Class<Self>) {
78 Self::parent_class_init::<T>(class);
79 let klass = class.as_mut();
80 klass.save_async = Some(panel_save_delegate_save_async::<T>);
81 klass.save_finish = Some(panel_save_delegate_save_finish);
82 }
83}
84
85unsafe extern "C" fn panel_save_delegate_save_async<T: SaveDelegateImpl>(
86 delegate: *mut ffi::PanelSaveDelegate,
87 cancellable: *mut gio::ffi::GCancellable,
88 callback: gio::ffi::GAsyncReadyCallback,
89 user_data: glib::ffi::gpointer,
90) {
91 let instance = &*(delegate as *mut T::Instance);
92 let imp = instance.imp();
93 let cancellable: Option<gio::Cancellable> = from_glib_none(cancellable);
94 let delegate: Option<SaveDelegate> = callback.map(|_| from_glib_none(delegate));
95
96 let fut = imp.save_future();
97 glib::MainContext::default().spawn_local(async move {
98 let res = fut.await;
99 if let Some(callback) = callback {
100 let t = gio::LocalTask::new(
101 Some(delegate.unwrap_unchecked().upcast_ref::<glib::Object>()),
102 cancellable.as_ref(),
103 move |task: gio::LocalTask<bool>, source_object: Option<&glib::Object>| {
104 let result: *mut gio::ffi::GAsyncResult =
105 task.upcast_ref::<gio::AsyncResult>().to_glib_none().0;
106 let source_object: *mut glib::gobject_ffi::GObject =
107 source_object.to_glib_none().0;
108 callback(source_object, result, user_data)
109 },
110 );
111 t.return_result(res.map(|_| true));
112 }
113 });
114}
115
116unsafe extern "C" fn panel_save_delegate_save_finish(
117 delegate: *mut ffi::PanelSaveDelegate,
118 res: *mut gio::ffi::GAsyncResult,
119 error: *mut *mut glib::ffi::GError,
120) -> glib::ffi::gboolean {
121 let delegate = from_glib_borrow::<_, SaveDelegate>(delegate);
122 let res: gio::AsyncResult = from_glib_none(res);
123 let t = res.downcast::<gio::LocalTask<bool>>().unwrap();
124 assert!(gio::LocalTask::<bool>::is_valid(
125 &t,
126 Some(delegate.as_ref())
127 ));
128 let ret = t.propagate();
129 match ret {
130 Ok(v) => {
131 assert!(v);
132 true.into_glib()
133 }
134 Err(e) => {
135 if !error.is_null() {
136 *error = e.into_glib_ptr();
137 }
138 false.into_glib()
139 }
140 }
141}