libpanel/subclass/
save_delegate.rs

1use 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}