1use std::{cell::RefCell, mem, pin::Pin, ptr};
4
5use glib::{prelude::*, translate::*};
6
7#[cfg(feature = "v2_74")]
8use crate::FileIOStream;
9use crate::{ffi, Cancellable, File, FileCreateFlags, FileEnumerator, FileQueryInfoFlags};
10
11impl File {
12 #[cfg(feature = "v2_74")]
13 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
14 #[doc(alias = "g_file_new_tmp_async")]
15 pub fn new_tmp_async<P: FnOnce(Result<(File, FileIOStream), glib::Error>) + 'static>(
16 tmpl: Option<impl AsRef<std::path::Path>>,
17 io_priority: glib::Priority,
18 cancellable: Option<&impl IsA<Cancellable>>,
19 callback: P,
20 ) {
21 let main_context = glib::MainContext::ref_thread_default();
22 let is_main_context_owner = main_context.is_owner();
23 let has_acquired_main_context = (!is_main_context_owner)
24 .then(|| main_context.acquire().ok())
25 .flatten();
26 assert!(
27 is_main_context_owner || has_acquired_main_context.is_some(),
28 "Async operations only allowed if the thread is owning the MainContext"
29 );
30
31 let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
32 Box::new(glib::thread_guard::ThreadGuard::new(callback));
33 unsafe extern "C" fn new_tmp_async_trampoline<
34 P: FnOnce(Result<(File, FileIOStream), glib::Error>) + 'static,
35 >(
36 _source_object: *mut glib::gobject_ffi::GObject,
37 res: *mut crate::ffi::GAsyncResult,
38 user_data: glib::ffi::gpointer,
39 ) {
40 let mut error = ptr::null_mut();
41 let mut iostream = ptr::null_mut();
42 let ret = ffi::g_file_new_tmp_finish(res, &mut iostream, &mut error);
43 let result = if error.is_null() {
44 Ok((from_glib_full(ret), from_glib_full(iostream)))
45 } else {
46 Err(from_glib_full(error))
47 };
48 let callback: Box<glib::thread_guard::ThreadGuard<P>> =
49 Box::from_raw(user_data as *mut _);
50 let callback: P = callback.into_inner();
51 callback(result);
52 }
53 let callback = new_tmp_async_trampoline::<P>;
54 unsafe {
55 ffi::g_file_new_tmp_async(
56 tmpl.as_ref().map(|p| p.as_ref()).to_glib_none().0,
57 io_priority.into_glib(),
58 cancellable.map(|p| p.as_ref()).to_glib_none().0,
59 Some(callback),
60 Box::into_raw(user_data) as *mut _,
61 );
62 }
63 }
64
65 #[cfg(feature = "v2_74")]
66 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
67 pub fn new_tmp_future(
68 tmpl: Option<impl AsRef<std::path::Path>>,
69 io_priority: glib::Priority,
70 ) -> Pin<
71 Box<dyn std::future::Future<Output = Result<(File, FileIOStream), glib::Error>> + 'static>,
72 > {
73 let tmpl = tmpl.map(|tmpl| tmpl.as_ref().to_owned());
74 Box::pin(crate::GioFuture::new(
75 &(),
76 move |_obj, cancellable, send| {
77 Self::new_tmp_async(
78 tmpl.as_ref()
79 .map(<std::path::PathBuf as std::borrow::Borrow<std::path::Path>>::borrow),
80 io_priority,
81 Some(cancellable),
82 move |res| {
83 send.resolve(res);
84 },
85 );
86 },
87 ))
88 }
89
90 #[cfg(feature = "v2_74")]
91 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
92 #[doc(alias = "g_file_new_tmp_dir_async")]
93 pub fn new_tmp_dir_async<P: FnOnce(Result<File, glib::Error>) + 'static>(
94 tmpl: Option<impl AsRef<std::path::Path>>,
95 io_priority: glib::Priority,
96 cancellable: Option<&impl IsA<Cancellable>>,
97 callback: P,
98 ) {
99 let main_context = glib::MainContext::ref_thread_default();
100 let is_main_context_owner = main_context.is_owner();
101 let has_acquired_main_context = (!is_main_context_owner)
102 .then(|| main_context.acquire().ok())
103 .flatten();
104 assert!(
105 is_main_context_owner || has_acquired_main_context.is_some(),
106 "Async operations only allowed if the thread is owning the MainContext"
107 );
108
109 let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
110 Box::new(glib::thread_guard::ThreadGuard::new(callback));
111 unsafe extern "C" fn new_tmp_dir_async_trampoline<
112 P: FnOnce(Result<File, glib::Error>) + 'static,
113 >(
114 _source_object: *mut glib::gobject_ffi::GObject,
115 res: *mut crate::ffi::GAsyncResult,
116 user_data: glib::ffi::gpointer,
117 ) {
118 let mut error = ptr::null_mut();
119 let ret = ffi::g_file_new_tmp_dir_finish(res, &mut error);
120 let result = if error.is_null() {
121 Ok(from_glib_full(ret))
122 } else {
123 Err(from_glib_full(error))
124 };
125 let callback: Box<glib::thread_guard::ThreadGuard<P>> =
126 Box::from_raw(user_data as *mut _);
127 let callback: P = callback.into_inner();
128 callback(result);
129 }
130 let callback = new_tmp_dir_async_trampoline::<P>;
131 unsafe {
132 ffi::g_file_new_tmp_dir_async(
133 tmpl.as_ref().map(|p| p.as_ref()).to_glib_none().0,
134 io_priority.into_glib(),
135 cancellable.map(|p| p.as_ref()).to_glib_none().0,
136 Some(callback),
137 Box::into_raw(user_data) as *mut _,
138 );
139 }
140 }
141
142 #[cfg(feature = "v2_74")]
143 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
144 pub fn new_tmp_dir_future(
145 tmpl: Option<impl AsRef<std::path::Path>>,
146 io_priority: glib::Priority,
147 ) -> Pin<Box<dyn std::future::Future<Output = Result<File, glib::Error>> + 'static>> {
148 let tmpl = tmpl.map(|tmpl| tmpl.as_ref().to_owned());
149 Box::pin(crate::GioFuture::new(
150 &(),
151 move |_obj, cancellable, send| {
152 Self::new_tmp_dir_async(
153 tmpl.as_ref()
154 .map(<std::path::PathBuf as std::borrow::Borrow<std::path::Path>>::borrow),
155 io_priority,
156 Some(cancellable),
157 move |res| {
158 send.resolve(res);
159 },
160 );
161 },
162 ))
163 }
164}
165
166mod sealed {
167 pub trait Sealed {}
168 impl<T: super::IsA<super::File>> Sealed for T {}
169}
170
171pub trait FileExtManual: sealed::Sealed + IsA<File> + Sized {
172 #[doc(alias = "g_file_replace_contents_async")]
173 fn replace_contents_async<
174 B: AsRef<[u8]> + Send + 'static,
175 R: FnOnce(Result<(B, glib::GString), (B, glib::Error)>) + 'static,
176 C: IsA<Cancellable>,
177 >(
178 &self,
179 contents: B,
180 etag: Option<&str>,
181 make_backup: bool,
182 flags: FileCreateFlags,
183 cancellable: Option<&C>,
184 callback: R,
185 ) {
186 let main_context = glib::MainContext::ref_thread_default();
187 let is_main_context_owner = main_context.is_owner();
188 let has_acquired_main_context = (!is_main_context_owner)
189 .then(|| main_context.acquire().ok())
190 .flatten();
191 assert!(
192 is_main_context_owner || has_acquired_main_context.is_some(),
193 "Async operations only allowed if the thread is owning the MainContext"
194 );
195
196 let etag = etag.to_glib_none();
197 let cancellable = cancellable.map(|c| c.as_ref());
198 let gcancellable = cancellable.to_glib_none();
199 let user_data: Box<(glib::thread_guard::ThreadGuard<R>, B)> =
200 Box::new((glib::thread_guard::ThreadGuard::new(callback), contents));
201 let (count, contents_ptr) = {
203 let contents = &user_data.1;
204 let slice = contents.as_ref();
205 (slice.len(), slice.as_ptr())
206 };
207 unsafe extern "C" fn replace_contents_async_trampoline<
208 B: AsRef<[u8]> + Send + 'static,
209 R: FnOnce(Result<(B, glib::GString), (B, glib::Error)>) + 'static,
210 >(
211 _source_object: *mut glib::gobject_ffi::GObject,
212 res: *mut ffi::GAsyncResult,
213 user_data: glib::ffi::gpointer,
214 ) {
215 let user_data: Box<(glib::thread_guard::ThreadGuard<R>, B)> =
216 Box::from_raw(user_data as *mut _);
217 let (callback, contents) = *user_data;
218 let callback = callback.into_inner();
219
220 let mut error = ptr::null_mut();
221 let mut new_etag = ptr::null_mut();
222 let _ = ffi::g_file_replace_contents_finish(
223 _source_object as *mut _,
224 res,
225 &mut new_etag,
226 &mut error,
227 );
228 let result = if error.is_null() {
229 Ok((contents, from_glib_full(new_etag)))
230 } else {
231 Err((contents, from_glib_full(error)))
232 };
233 callback(result);
234 }
235 let callback = replace_contents_async_trampoline::<B, R>;
236 unsafe {
237 ffi::g_file_replace_contents_async(
238 self.as_ref().to_glib_none().0,
239 mut_override(contents_ptr),
240 count,
241 etag.0,
242 make_backup.into_glib(),
243 flags.into_glib(),
244 gcancellable.0,
245 Some(callback),
246 Box::into_raw(user_data) as *mut _,
247 );
248 }
249 }
250
251 fn replace_contents_future<B: AsRef<[u8]> + Send + 'static>(
252 &self,
253 contents: B,
254 etag: Option<&str>,
255 make_backup: bool,
256 flags: FileCreateFlags,
257 ) -> Pin<
258 Box<
259 dyn std::future::Future<Output = Result<(B, glib::GString), (B, glib::Error)>>
260 + 'static,
261 >,
262 > {
263 let etag = etag.map(glib::GString::from);
264 Box::pin(crate::GioFuture::new(
265 self,
266 move |obj, cancellable, send| {
267 obj.replace_contents_async(
268 contents,
269 etag.as_ref().map(|s| s.as_str()),
270 make_backup,
271 flags,
272 Some(cancellable),
273 move |res| {
274 send.resolve(res);
275 },
276 );
277 },
278 ))
279 }
280
281 #[doc(alias = "g_file_enumerate_children_async")]
282 fn enumerate_children_async<
283 P: IsA<Cancellable>,
284 Q: FnOnce(Result<FileEnumerator, glib::Error>) + 'static,
285 >(
286 &self,
287 attributes: &str,
288 flags: FileQueryInfoFlags,
289 io_priority: glib::Priority,
290 cancellable: Option<&P>,
291 callback: Q,
292 ) {
293 let main_context = glib::MainContext::ref_thread_default();
294 let is_main_context_owner = main_context.is_owner();
295 let has_acquired_main_context = (!is_main_context_owner)
296 .then(|| main_context.acquire().ok())
297 .flatten();
298 assert!(
299 is_main_context_owner || has_acquired_main_context.is_some(),
300 "Async operations only allowed if the thread is owning the MainContext"
301 );
302
303 let user_data: Box<glib::thread_guard::ThreadGuard<Q>> =
304 Box::new(glib::thread_guard::ThreadGuard::new(callback));
305 unsafe extern "C" fn create_async_trampoline<
306 Q: FnOnce(Result<FileEnumerator, glib::Error>) + 'static,
307 >(
308 _source_object: *mut glib::gobject_ffi::GObject,
309 res: *mut crate::ffi::GAsyncResult,
310 user_data: glib::ffi::gpointer,
311 ) {
312 let mut error = ptr::null_mut();
313 let ret =
314 ffi::g_file_enumerate_children_finish(_source_object as *mut _, res, &mut error);
315 let result = if error.is_null() {
316 Ok(from_glib_full(ret))
317 } else {
318 Err(from_glib_full(error))
319 };
320 let callback: Box<glib::thread_guard::ThreadGuard<Q>> =
321 Box::from_raw(user_data as *mut _);
322 let callback = callback.into_inner();
323 callback(result);
324 }
325 let callback = create_async_trampoline::<Q>;
326 unsafe {
327 ffi::g_file_enumerate_children_async(
328 self.as_ref().to_glib_none().0,
329 attributes.to_glib_none().0,
330 flags.into_glib(),
331 io_priority.into_glib(),
332 cancellable.map(|p| p.as_ref()).to_glib_none().0,
333 Some(callback),
334 Box::into_raw(user_data) as *mut _,
335 );
336 }
337 }
338
339 fn enumerate_children_future(
340 &self,
341 attributes: &str,
342 flags: FileQueryInfoFlags,
343 io_priority: glib::Priority,
344 ) -> Pin<Box<dyn std::future::Future<Output = Result<FileEnumerator, glib::Error>> + 'static>>
345 {
346 let attributes = attributes.to_owned();
347 Box::pin(crate::GioFuture::new(
348 self,
349 move |obj, cancellable, send| {
350 obj.enumerate_children_async(
351 &attributes,
352 flags,
353 io_priority,
354 Some(cancellable),
355 move |res| {
356 send.resolve(res);
357 },
358 );
359 },
360 ))
361 }
362
363 #[doc(alias = "g_file_copy_async")]
364 fn copy_async<Q: FnOnce(Result<(), glib::Error>) + 'static>(
365 &self,
366 destination: &impl IsA<File>,
367 flags: crate::FileCopyFlags,
368 io_priority: glib::Priority,
369 cancellable: Option<&impl IsA<Cancellable>>,
370 progress_callback: Option<Box<dyn FnMut(i64, i64)>>,
371 callback: Q,
372 ) {
373 let main_context = glib::MainContext::ref_thread_default();
374 let is_main_context_owner = main_context.is_owner();
375 let has_acquired_main_context = (!is_main_context_owner)
376 .then(|| main_context.acquire().ok())
377 .flatten();
378 assert!(
379 is_main_context_owner || has_acquired_main_context.is_some(),
380 "Async operations only allowed if the thread is owning the MainContext"
381 );
382
383 let progress_trampoline = if progress_callback.is_some() {
384 Some(copy_async_progress_trampoline::<Q> as _)
385 } else {
386 None
387 };
388
389 let user_data: Box<(
390 glib::thread_guard::ThreadGuard<Q>,
391 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
392 )> = Box::new((
393 glib::thread_guard::ThreadGuard::new(callback),
394 RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
395 ));
396 unsafe extern "C" fn copy_async_trampoline<Q: FnOnce(Result<(), glib::Error>) + 'static>(
397 _source_object: *mut glib::gobject_ffi::GObject,
398 res: *mut crate::ffi::GAsyncResult,
399 user_data: glib::ffi::gpointer,
400 ) {
401 let mut error = ptr::null_mut();
402 ffi::g_file_copy_finish(_source_object as *mut _, res, &mut error);
403 let result = if error.is_null() {
404 Ok(())
405 } else {
406 Err(from_glib_full(error))
407 };
408 let callback: Box<(
409 glib::thread_guard::ThreadGuard<Q>,
410 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
411 )> = Box::from_raw(user_data as *mut _);
412 let callback = callback.0.into_inner();
413 callback(result);
414 }
415 unsafe extern "C" fn copy_async_progress_trampoline<
416 Q: FnOnce(Result<(), glib::Error>) + 'static,
417 >(
418 current_num_bytes: i64,
419 total_num_bytes: i64,
420 user_data: glib::ffi::gpointer,
421 ) {
422 let callback: &(
423 glib::thread_guard::ThreadGuard<Q>,
424 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
425 ) = &*(user_data as *const _);
426 (callback
427 .1
428 .borrow_mut()
429 .as_mut()
430 .expect("no closure")
431 .get_mut())(current_num_bytes, total_num_bytes);
432 }
433
434 let user_data = Box::into_raw(user_data) as *mut _;
435
436 unsafe {
437 ffi::g_file_copy_async(
438 self.as_ref().to_glib_none().0,
439 destination.as_ref().to_glib_none().0,
440 flags.into_glib(),
441 io_priority.into_glib(),
442 cancellable.map(|p| p.as_ref()).to_glib_none().0,
443 progress_trampoline,
444 user_data,
445 Some(copy_async_trampoline::<Q>),
446 user_data,
447 );
448 }
449 }
450
451 fn copy_future(
452 &self,
453 destination: &(impl IsA<File> + Clone + 'static),
454 flags: crate::FileCopyFlags,
455 io_priority: glib::Priority,
456 ) -> (
457 Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>>,
458 Pin<Box<dyn futures_core::stream::Stream<Item = (i64, i64)> + 'static>>,
459 ) {
460 let destination = destination.clone();
461
462 let (sender, receiver) = futures_channel::mpsc::unbounded();
463
464 let fut = Box::pin(crate::GioFuture::new(
465 self,
466 move |obj, cancellable, send| {
467 obj.copy_async(
468 &destination,
469 flags,
470 io_priority,
471 Some(cancellable),
472 Some(Box::new(move |current_num_bytes, total_num_bytes| {
473 let _ = sender.unbounded_send((current_num_bytes, total_num_bytes));
474 })),
475 move |res| {
476 send.resolve(res);
477 },
478 );
479 },
480 ));
481
482 (fut, Box::pin(receiver))
483 }
484
485 #[doc(alias = "g_file_load_contents")]
486 fn load_contents(
487 &self,
488 cancellable: Option<&impl IsA<Cancellable>>,
489 ) -> Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error> {
490 unsafe {
491 let mut contents = std::ptr::null_mut();
492 let mut length = std::mem::MaybeUninit::uninit();
493 let mut etag_out = std::ptr::null_mut();
494 let mut error = std::ptr::null_mut();
495 let is_ok = ffi::g_file_load_contents(
496 self.as_ref().to_glib_none().0,
497 cancellable.map(|p| p.as_ref()).to_glib_none().0,
498 &mut contents,
499 length.as_mut_ptr(),
500 &mut etag_out,
501 &mut error,
502 );
503 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
504 if error.is_null() {
505 Ok((
506 FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
507 from_glib_full(etag_out),
508 ))
509 } else {
510 Err(from_glib_full(error))
511 }
512 }
513 }
514
515 #[doc(alias = "g_file_load_contents_async")]
516 fn load_contents_async<
517 P: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
518 + 'static,
519 >(
520 &self,
521 cancellable: Option<&impl IsA<Cancellable>>,
522 callback: P,
523 ) {
524 let main_context = glib::MainContext::ref_thread_default();
525 let is_main_context_owner = main_context.is_owner();
526 let has_acquired_main_context = (!is_main_context_owner)
527 .then(|| main_context.acquire().ok())
528 .flatten();
529 assert!(
530 is_main_context_owner || has_acquired_main_context.is_some(),
531 "Async operations only allowed if the thread is owning the MainContext"
532 );
533
534 let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
535 Box::new(glib::thread_guard::ThreadGuard::new(callback));
536 unsafe extern "C" fn load_contents_async_trampoline<
537 P: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
538 + 'static,
539 >(
540 _source_object: *mut glib::gobject_ffi::GObject,
541 res: *mut crate::ffi::GAsyncResult,
542 user_data: glib::ffi::gpointer,
543 ) {
544 let mut error = std::ptr::null_mut();
545 let mut contents = std::ptr::null_mut();
546 let mut length = std::mem::MaybeUninit::uninit();
547 let mut etag_out = std::ptr::null_mut();
548 let _ = ffi::g_file_load_contents_finish(
549 _source_object as *mut _,
550 res,
551 &mut contents,
552 length.as_mut_ptr(),
553 &mut etag_out,
554 &mut error,
555 );
556 let result = if error.is_null() {
557 Ok((
558 FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
559 from_glib_full(etag_out),
560 ))
561 } else {
562 Err(from_glib_full(error))
563 };
564 let callback: Box<glib::thread_guard::ThreadGuard<P>> =
565 Box::from_raw(user_data as *mut _);
566 let callback: P = callback.into_inner();
567 callback(result);
568 }
569 let callback = load_contents_async_trampoline::<P>;
570 unsafe {
571 ffi::g_file_load_contents_async(
572 self.as_ref().to_glib_none().0,
573 cancellable.map(|p| p.as_ref()).to_glib_none().0,
574 Some(callback),
575 Box::into_raw(user_data) as *mut _,
576 );
577 }
578 }
579
580 fn load_contents_future(
581 &self,
582 ) -> Pin<
583 Box<
584 dyn std::future::Future<
585 Output = Result<
586 (glib::collections::Slice<u8>, Option<glib::GString>),
587 glib::Error,
588 >,
589 > + 'static,
590 >,
591 > {
592 Box::pin(crate::GioFuture::new(
593 self,
594 move |obj, cancellable, send| {
595 obj.load_contents_async(Some(cancellable), move |res| {
596 send.resolve(res);
597 });
598 },
599 ))
600 }
601
602 #[doc(alias = "g_file_load_partial_contents_async")]
603 fn load_partial_contents_async<
604 P: FnMut(&[u8]) -> bool + 'static,
605 Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
606 + 'static,
607 >(
608 &self,
609 cancellable: Option<&impl IsA<Cancellable>>,
610 read_more_callback: P,
611 callback: Q,
612 ) {
613 let main_context = glib::MainContext::ref_thread_default();
614 let is_main_context_owner = main_context.is_owner();
615 let has_acquired_main_context = (!is_main_context_owner)
616 .then(|| main_context.acquire().ok())
617 .flatten();
618 assert!(
619 is_main_context_owner || has_acquired_main_context.is_some(),
620 "Async operations only allowed if the thread is owning the MainContext"
621 );
622
623 let user_data: Box<(
624 glib::thread_guard::ThreadGuard<Q>,
625 RefCell<glib::thread_guard::ThreadGuard<P>>,
626 )> = Box::new((
627 glib::thread_guard::ThreadGuard::new(callback),
628 RefCell::new(glib::thread_guard::ThreadGuard::new(read_more_callback)),
629 ));
630 unsafe extern "C" fn load_partial_contents_async_trampoline<
631 P: FnMut(&[u8]) -> bool + 'static,
632 Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
633 + 'static,
634 >(
635 _source_object: *mut glib::gobject_ffi::GObject,
636 res: *mut crate::ffi::GAsyncResult,
637 user_data: glib::ffi::gpointer,
638 ) {
639 let mut contents = ptr::null_mut();
640 let mut length = mem::MaybeUninit::uninit();
641 let mut etag_out = ptr::null_mut();
642 let mut error = ptr::null_mut();
643 ffi::g_file_load_partial_contents_finish(
644 _source_object as *mut _,
645 res,
646 &mut contents,
647 length.as_mut_ptr(),
648 &mut etag_out,
649 &mut error,
650 );
651 let result = if error.is_null() {
652 Ok((
653 FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
654 from_glib_full(etag_out),
655 ))
656 } else {
657 Err(from_glib_full(error))
658 };
659 let callback: Box<(
660 glib::thread_guard::ThreadGuard<Q>,
661 RefCell<glib::thread_guard::ThreadGuard<P>>,
662 )> = Box::from_raw(user_data as *mut _);
663 let callback = callback.0.into_inner();
664 callback(result);
665 }
666 unsafe extern "C" fn load_partial_contents_async_read_more_trampoline<
667 P: FnMut(&[u8]) -> bool + 'static,
668 Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
669 + 'static,
670 >(
671 file_contents: *const libc::c_char,
672 file_size: i64,
673 user_data: glib::ffi::gpointer,
674 ) -> glib::ffi::gboolean {
675 use std::slice;
676
677 let callback: &(
678 glib::thread_guard::ThreadGuard<Q>,
679 RefCell<glib::thread_guard::ThreadGuard<P>>,
680 ) = &*(user_data as *const _);
681 let data = if file_size == 0 {
682 &[]
683 } else {
684 slice::from_raw_parts(file_contents as *const u8, file_size as usize)
685 };
686
687 (*callback.1.borrow_mut().get_mut())(data).into_glib()
688 }
689
690 let user_data = Box::into_raw(user_data) as *mut _;
691
692 unsafe {
693 ffi::g_file_load_partial_contents_async(
694 self.as_ref().to_glib_none().0,
695 cancellable.map(|p| p.as_ref()).to_glib_none().0,
696 Some(load_partial_contents_async_read_more_trampoline::<P, Q>),
697 Some(load_partial_contents_async_trampoline::<P, Q>),
698 user_data,
699 );
700 }
701 }
702
703 #[doc(alias = "g_file_measure_disk_usage")]
704 fn measure_disk_usage(
705 &self,
706 flags: crate::FileMeasureFlags,
707 cancellable: Option<&impl IsA<Cancellable>>,
708 progress_callback: Option<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
709 ) -> Result<(u64, u64, u64), glib::Error> {
710 let progress_callback_data: Box<
711 Option<RefCell<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>>,
712 > = Box::new(progress_callback.map(RefCell::new));
713 unsafe extern "C" fn progress_callback_func(
714 reporting: glib::ffi::gboolean,
715 current_size: u64,
716 num_dirs: u64,
717 num_files: u64,
718 user_data: glib::ffi::gpointer,
719 ) {
720 let reporting = from_glib(reporting);
721 let callback: &Option<RefCell<Box<dyn Fn(bool, u64, u64, u64) + 'static>>> =
722 &*(user_data as *mut _);
723 if let Some(ref callback) = *callback {
724 (*callback.borrow_mut())(reporting, current_size, num_dirs, num_files)
725 } else {
726 panic!("cannot get closure...")
727 };
728 }
729 let progress_callback = if progress_callback_data.is_some() {
730 Some(progress_callback_func as _)
731 } else {
732 None
733 };
734 let super_callback0: Box<Option<RefCell<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>>> =
735 progress_callback_data;
736 unsafe {
737 let mut disk_usage = mem::MaybeUninit::uninit();
738 let mut num_dirs = mem::MaybeUninit::uninit();
739 let mut num_files = mem::MaybeUninit::uninit();
740 let mut error = ptr::null_mut();
741 let _ = ffi::g_file_measure_disk_usage(
742 self.as_ref().to_glib_none().0,
743 flags.into_glib(),
744 cancellable.map(|p| p.as_ref()).to_glib_none().0,
745 progress_callback,
746 Box::into_raw(super_callback0) as *mut _,
747 disk_usage.as_mut_ptr(),
748 num_dirs.as_mut_ptr(),
749 num_files.as_mut_ptr(),
750 &mut error,
751 );
752 let disk_usage = disk_usage.assume_init();
753 let num_dirs = num_dirs.assume_init();
754 let num_files = num_files.assume_init();
755 if error.is_null() {
756 Ok((disk_usage, num_dirs, num_files))
757 } else {
758 Err(from_glib_full(error))
759 }
760 }
761 }
762
763 #[doc(alias = "g_file_measure_disk_usage_async")]
764 fn measure_disk_usage_async<P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static>(
765 &self,
766 flags: crate::FileMeasureFlags,
767 io_priority: glib::Priority,
768 cancellable: Option<&impl IsA<Cancellable>>,
769 progress_callback: Option<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
770 callback: P,
771 ) {
772 let main_context = glib::MainContext::ref_thread_default();
773 let is_main_context_owner = main_context.is_owner();
774 let has_acquired_main_context = (!is_main_context_owner)
775 .then(|| main_context.acquire().ok())
776 .flatten();
777 assert!(
778 is_main_context_owner || has_acquired_main_context.is_some(),
779 "Async operations only allowed if the thread is owning the MainContext"
780 );
781
782 let progress_callback_trampoline = if progress_callback.is_some() {
783 Some(measure_disk_usage_async_progress_trampoline::<P> as _)
784 } else {
785 None
786 };
787
788 let user_data: Box<(
789 glib::thread_guard::ThreadGuard<P>,
790 RefCell<
791 Option<
792 glib::thread_guard::ThreadGuard<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
793 >,
794 >,
795 )> = Box::new((
796 glib::thread_guard::ThreadGuard::new(callback),
797 RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
798 ));
799 unsafe extern "C" fn measure_disk_usage_async_trampoline<
800 P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static,
801 >(
802 _source_object: *mut glib::gobject_ffi::GObject,
803 res: *mut crate::ffi::GAsyncResult,
804 user_data: glib::ffi::gpointer,
805 ) {
806 let mut disk_usage = mem::MaybeUninit::uninit();
807 let mut num_dirs = mem::MaybeUninit::uninit();
808 let mut num_files = mem::MaybeUninit::uninit();
809 let mut error = ptr::null_mut();
810 ffi::g_file_measure_disk_usage_finish(
811 _source_object as *mut _,
812 res,
813 disk_usage.as_mut_ptr(),
814 num_dirs.as_mut_ptr(),
815 num_files.as_mut_ptr(),
816 &mut error,
817 );
818 let result = if error.is_null() {
819 Ok((
820 disk_usage.assume_init(),
821 num_dirs.assume_init(),
822 num_files.assume_init(),
823 ))
824 } else {
825 Err(from_glib_full(error))
826 };
827 let callback: Box<(
828 glib::thread_guard::ThreadGuard<P>,
829 RefCell<
830 Option<
831 glib::thread_guard::ThreadGuard<
832 Box<dyn FnMut(bool, u64, u64, u64) + 'static>,
833 >,
834 >,
835 >,
836 )> = Box::from_raw(user_data as *mut _);
837 let callback = callback.0.into_inner();
838 callback(result);
839 }
840 unsafe extern "C" fn measure_disk_usage_async_progress_trampoline<
841 P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static,
842 >(
843 reporting: glib::ffi::gboolean,
844 disk_usage: u64,
845 num_dirs: u64,
846 num_files: u64,
847 user_data: glib::ffi::gpointer,
848 ) {
849 let callback: &(
850 glib::thread_guard::ThreadGuard<P>,
851 RefCell<
852 Option<
853 glib::thread_guard::ThreadGuard<
854 Box<dyn FnMut(bool, u64, u64, u64) + 'static>,
855 >,
856 >,
857 >,
858 ) = &*(user_data as *const _);
859 (callback
860 .1
861 .borrow_mut()
862 .as_mut()
863 .expect("can't get callback")
864 .get_mut())(from_glib(reporting), disk_usage, num_dirs, num_files);
865 }
866
867 let user_data = Box::into_raw(user_data) as *mut _;
868
869 unsafe {
870 ffi::g_file_measure_disk_usage_async(
871 self.as_ref().to_glib_none().0,
872 flags.into_glib(),
873 io_priority.into_glib(),
874 cancellable.map(|p| p.as_ref()).to_glib_none().0,
875 progress_callback_trampoline,
876 user_data,
877 Some(measure_disk_usage_async_trampoline::<P>),
878 user_data,
879 );
880 }
881 }
882
883 fn measure_disk_usage_future(
884 &self,
885 flags: crate::FileMeasureFlags,
886 io_priority: glib::Priority,
887 ) -> (
888 Pin<Box<dyn std::future::Future<Output = Result<(u64, u64, u64), glib::Error>> + 'static>>,
889 Pin<Box<dyn futures_core::stream::Stream<Item = (bool, u64, u64, u64)> + 'static>>,
890 ) {
891 let (sender, receiver) = futures_channel::mpsc::unbounded();
892
893 let fut = Box::pin(crate::GioFuture::new(
894 self,
895 move |obj, cancellable, send| {
896 obj.measure_disk_usage_async(
897 flags,
898 io_priority,
899 Some(cancellable),
900 Some(Box::new(
901 move |reporting, disk_usage, num_dirs, num_files| {
902 let _ =
903 sender.unbounded_send((reporting, disk_usage, num_dirs, num_files));
904 },
905 )),
906 move |res| {
907 send.resolve(res);
908 },
909 );
910 },
911 ));
912
913 (fut, Box::pin(receiver))
914 }
915
916 #[cfg(feature = "v2_72")]
917 #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))]
918 #[doc(alias = "g_file_move_async")]
919 fn move_async<Q: FnOnce(Result<(), glib::Error>) + 'static>(
920 &self,
921 destination: &impl IsA<File>,
922 flags: crate::FileCopyFlags,
923 io_priority: glib::Priority,
924 cancellable: Option<&impl IsA<Cancellable>>,
925 progress_callback: Option<Box<dyn FnMut(i64, i64)>>,
926 callback: Q,
927 ) {
928 let main_context = glib::MainContext::ref_thread_default();
929 let is_main_context_owner = main_context.is_owner();
930 let has_acquired_main_context = (!is_main_context_owner)
931 .then(|| main_context.acquire().ok())
932 .flatten();
933 assert!(
934 is_main_context_owner || has_acquired_main_context.is_some(),
935 "Async operations only allowed if the thread is owning the MainContext"
936 );
937
938 let progress_trampoline = if progress_callback.is_some() {
939 Some(move_async_progress_trampoline::<Q> as _)
940 } else {
941 None
942 };
943
944 let user_data: Box<(
945 glib::thread_guard::ThreadGuard<Q>,
946 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
947 )> = Box::new((
948 glib::thread_guard::ThreadGuard::new(callback),
949 RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
950 ));
951 unsafe extern "C" fn move_async_trampoline<Q: FnOnce(Result<(), glib::Error>) + 'static>(
952 _source_object: *mut glib::gobject_ffi::GObject,
953 res: *mut crate::ffi::GAsyncResult,
954 user_data: glib::ffi::gpointer,
955 ) {
956 let mut error = ptr::null_mut();
957 ffi::g_file_move_finish(_source_object as *mut _, res, &mut error);
958 let result = if error.is_null() {
959 Ok(())
960 } else {
961 Err(from_glib_full(error))
962 };
963 let callback: Box<(
964 glib::thread_guard::ThreadGuard<Q>,
965 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
966 )> = Box::from_raw(user_data as *mut _);
967 let callback = callback.0.into_inner();
968 callback(result);
969 }
970 unsafe extern "C" fn move_async_progress_trampoline<
971 Q: FnOnce(Result<(), glib::Error>) + 'static,
972 >(
973 current_num_bytes: i64,
974 total_num_bytes: i64,
975 user_data: glib::ffi::gpointer,
976 ) {
977 let callback: &(
978 glib::thread_guard::ThreadGuard<Q>,
979 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
980 ) = &*(user_data as *const _);
981 (callback
982 .1
983 .borrow_mut()
984 .as_mut()
985 .expect("no closure")
986 .get_mut())(current_num_bytes, total_num_bytes);
987 }
988
989 let user_data = Box::into_raw(user_data) as *mut _;
990
991 unsafe {
992 ffi::g_file_move_async(
993 self.as_ref().to_glib_none().0,
994 destination.as_ref().to_glib_none().0,
995 flags.into_glib(),
996 io_priority.into_glib(),
997 cancellable.map(|p| p.as_ref()).to_glib_none().0,
998 progress_trampoline,
999 user_data,
1000 Some(move_async_trampoline::<Q>),
1001 user_data,
1002 );
1003 }
1004 }
1005
1006 #[cfg(feature = "v2_74")]
1007 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
1008 #[doc(alias = "g_file_make_symbolic_link_async")]
1009 fn make_symbolic_link_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
1010 &self,
1011 symlink_value: impl AsRef<std::path::Path>,
1012 io_priority: glib::Priority,
1013 cancellable: Option<&impl IsA<Cancellable>>,
1014 callback: P,
1015 ) {
1016 let main_context = glib::MainContext::ref_thread_default();
1017 let is_main_context_owner = main_context.is_owner();
1018 let has_acquired_main_context = (!is_main_context_owner)
1019 .then(|| main_context.acquire().ok())
1020 .flatten();
1021 assert!(
1022 is_main_context_owner || has_acquired_main_context.is_some(),
1023 "Async operations only allowed if the thread is owning the MainContext"
1024 );
1025
1026 let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
1027 Box::new(glib::thread_guard::ThreadGuard::new(callback));
1028 unsafe extern "C" fn make_symbolic_link_async_trampoline<
1029 P: FnOnce(Result<(), glib::Error>) + 'static,
1030 >(
1031 _source_object: *mut glib::gobject_ffi::GObject,
1032 res: *mut crate::ffi::GAsyncResult,
1033 user_data: glib::ffi::gpointer,
1034 ) {
1035 let mut error = ptr::null_mut();
1036 let _ =
1037 ffi::g_file_make_symbolic_link_finish(_source_object as *mut _, res, &mut error);
1038 let result = if error.is_null() {
1039 Ok(())
1040 } else {
1041 Err(from_glib_full(error))
1042 };
1043 let callback: Box<glib::thread_guard::ThreadGuard<P>> =
1044 Box::from_raw(user_data as *mut _);
1045 let callback: P = callback.into_inner();
1046 callback(result);
1047 }
1048 let callback = make_symbolic_link_async_trampoline::<P>;
1049 unsafe {
1050 ffi::g_file_make_symbolic_link_async(
1051 self.as_ref().to_glib_none().0,
1052 symlink_value.as_ref().to_glib_none().0,
1053 io_priority.into_glib(),
1054 cancellable.map(|p| p.as_ref()).to_glib_none().0,
1055 Some(callback),
1056 Box::into_raw(user_data) as *mut _,
1057 );
1058 }
1059 }
1060
1061 #[cfg(feature = "v2_74")]
1062 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
1063 fn make_symbolic_link_future(
1064 &self,
1065 symlink_value: impl AsRef<std::path::Path>,
1066 io_priority: glib::Priority,
1067 ) -> Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
1068 let symlink_value = symlink_value.as_ref().to_owned();
1069 Box::pin(crate::GioFuture::new(
1070 self,
1071 move |obj, cancellable, send| {
1072 obj.make_symbolic_link_async(
1073 &symlink_value,
1074 io_priority,
1075 Some(cancellable),
1076 move |res| {
1077 send.resolve(res);
1078 },
1079 );
1080 },
1081 ))
1082 }
1083
1084 #[cfg(feature = "v2_72")]
1085 #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))]
1086 fn move_future(
1087 &self,
1088 destination: &(impl IsA<File> + Clone + 'static),
1089 flags: crate::FileCopyFlags,
1090 io_priority: glib::Priority,
1091 ) -> (
1092 Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>>,
1093 Pin<Box<dyn futures_core::stream::Stream<Item = (i64, i64)> + 'static>>,
1094 ) {
1095 let destination = destination.clone();
1096
1097 let (sender, receiver) = futures_channel::mpsc::unbounded();
1098
1099 let fut = Box::pin(crate::GioFuture::new(
1100 self,
1101 move |obj, cancellable, send| {
1102 obj.move_async(
1103 &destination,
1104 flags,
1105 io_priority,
1106 Some(cancellable),
1107 Some(Box::new(move |current_num_bytes, total_num_bytes| {
1108 let _ = sender.unbounded_send((current_num_bytes, total_num_bytes));
1109 })),
1110 move |res| {
1111 send.resolve(res);
1112 },
1113 );
1114 },
1115 ));
1116
1117 (fut, Box::pin(receiver))
1118 }
1119}
1120
1121impl<O: IsA<File>> FileExtManual for O {}