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