sourceview5/
file_loader.rs1use 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}