sourceview5/
file_loader.rs

1use std::{cell::RefCell, pin::Pin, ptr};
2
3use glib::translate::{from_glib_full, IntoGlib, ToGlibPtr};
4
5use crate::{prelude::*, FileLoader};
6
7impl FileLoader {
8    #[doc(alias = "gtk_source_file_loader_load_async")]
9    pub fn load_async_with_callback<
10        P: FnMut(i64, i64) + Send + 'static,
11        Q: FnOnce(Result<(), glib::Error>) + Send + 'static,
12    >(
13        &self,
14        io_priority: glib::Priority,
15        cancellable: Option<&impl IsA<gio::Cancellable>>,
16        progress_callback: P,
17        callback: Q,
18    ) {
19        self.load_async_impl(
20            io_priority,
21            cancellable,
22            Some(Box::new(progress_callback)),
23            callback,
24        )
25    }
26
27    #[doc(alias = "gtk_source_file_loader_load_async")]
28    pub fn load_async<Q: FnOnce(Result<(), glib::Error>) + Send + 'static>(
29        &self,
30        io_priority: glib::Priority,
31        cancellable: Option<&impl IsA<gio::Cancellable>>,
32        callback: Q,
33    ) {
34        self.load_async_impl(io_priority, cancellable, None, callback)
35    }
36
37    fn load_async_impl<Q: FnOnce(Result<(), glib::Error>) + Send + 'static>(
38        &self,
39        io_priority: glib::Priority,
40        cancellable: Option<&impl IsA<gio::Cancellable>>,
41        progress_callback: Option<Box<dyn FnMut(i64, i64) + Send>>,
42        callback: Q,
43    ) {
44        let progress_trampoline = if progress_callback.is_some() {
45            Some(load_async_progress_trampoline::<Q> as _)
46        } else {
47            None
48        };
49
50        let user_data: Box<(Q, RefCell<Option<Box<dyn FnMut(i64, i64) + Send>>>)> =
51            Box::new((callback, RefCell::new(progress_callback)));
52        unsafe extern "C" fn load_async_trampoline<
53            Q: FnOnce(Result<(), glib::Error>) + Send + 'static,
54        >(
55            _source_object: *mut glib::gobject_ffi::GObject,
56            res: *mut gio::ffi::GAsyncResult,
57            user_data: glib::ffi::gpointer,
58        ) {
59            let mut error = ptr::null_mut();
60            ffi::gtk_source_file_loader_load_finish(_source_object as *mut _, res, &mut error);
61            let result = if error.is_null() {
62                Ok(())
63            } else {
64                Err(from_glib_full(error))
65            };
66            let callback: Box<(Q, RefCell<Option<Box<dyn FnMut(i64, i64) + Send>>>)> =
67                Box::from_raw(user_data as *mut _);
68            callback.0(result);
69        }
70        unsafe extern "C" fn load_async_progress_trampoline<
71            Q: FnOnce(Result<(), glib::Error>) + Send + 'static,
72        >(
73            current_num_bytes: i64,
74            total_num_bytes: i64,
75            user_data: glib::ffi::gpointer,
76        ) {
77            let callback: &(Q, RefCell<Option<Box<dyn FnMut(i64, i64) + Send>>>) =
78                &*(user_data as *const _);
79            (callback.1.borrow_mut().as_mut().expect("no closure"))(
80                current_num_bytes,
81                total_num_bytes,
82            );
83        }
84
85        let user_data = Box::into_raw(user_data) as *mut _;
86
87        unsafe {
88            ffi::gtk_source_file_loader_load_async(
89                self.to_glib_none().0,
90                io_priority.into_glib(),
91                cancellable.map(|p| p.as_ref()).to_glib_none().0,
92                progress_trampoline,
93                user_data,
94                None,
95                Some(load_async_trampoline::<Q>),
96                user_data,
97            );
98        }
99    }
100
101    pub fn load_future(
102        &self,
103        io_priority: glib::Priority,
104    ) -> (
105        Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>>,
106        Pin<Box<dyn futures_core::stream::Stream<Item = (i64, i64)> + 'static>>,
107    ) {
108        let (sender, receiver) = futures_channel::mpsc::unbounded();
109
110        let fut = Box::pin(gtk::gio::GioFuture::new(
111            self,
112            move |obj, cancellable, send| {
113                obj.load_async_with_callback(
114                    io_priority,
115                    Some(cancellable),
116                    move |current_num_bytes, total_num_bytes| {
117                        let _ = sender.unbounded_send((current_num_bytes, total_num_bytes));
118                    },
119                    move |res| {
120                        send.resolve(res);
121                    },
122                );
123            },
124        ));
125
126        (fut, Box::pin(receiver))
127    }
128}