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")]
28 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
29 #[doc(alias = "g_file_new_tmp_async")]
30 pub fn new_tmp_async<P: FnOnce(Result<(File, FileIOStream), glib::Error>) + 'static>(
31 tmpl: Option<impl AsRef<std::path::Path>>,
32 io_priority: glib::Priority,
33 cancellable: Option<&impl IsA<Cancellable>>,
34 callback: P,
35 ) {
36 let main_context = glib::MainContext::ref_thread_default();
37 let is_main_context_owner = main_context.is_owner();
38 let has_acquired_main_context = (!is_main_context_owner)
39 .then(|| main_context.acquire().ok())
40 .flatten();
41 assert!(
42 is_main_context_owner || has_acquired_main_context.is_some(),
43 "Async operations only allowed if the thread is owning the MainContext"
44 );
45
46 let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
47 Box::new(glib::thread_guard::ThreadGuard::new(callback));
48 unsafe extern "C" fn new_tmp_async_trampoline<
49 P: FnOnce(Result<(File, FileIOStream), glib::Error>) + 'static,
50 >(
51 _source_object: *mut glib::gobject_ffi::GObject,
52 res: *mut crate::ffi::GAsyncResult,
53 user_data: glib::ffi::gpointer,
54 ) {
55 let mut error = ptr::null_mut();
56 let mut iostream = ptr::null_mut();
57 let ret = ffi::g_file_new_tmp_finish(res, &mut iostream, &mut error);
58 let result = if error.is_null() {
59 Ok((from_glib_full(ret), from_glib_full(iostream)))
60 } else {
61 Err(from_glib_full(error))
62 };
63 let callback: Box<glib::thread_guard::ThreadGuard<P>> =
64 Box::from_raw(user_data as *mut _);
65 let callback: P = callback.into_inner();
66 callback(result);
67 }
68 let callback = new_tmp_async_trampoline::<P>;
69 unsafe {
70 ffi::g_file_new_tmp_async(
71 tmpl.as_ref().map(|p| p.as_ref()).to_glib_none().0,
72 io_priority.into_glib(),
73 cancellable.map(|p| p.as_ref()).to_glib_none().0,
74 Some(callback),
75 Box::into_raw(user_data) as *mut _,
76 );
77 }
78 }
79
80 #[cfg(feature = "v2_74")]
81 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
82 pub fn new_tmp_future(
83 tmpl: Option<impl AsRef<std::path::Path>>,
84 io_priority: glib::Priority,
85 ) -> Pin<
86 Box<dyn std::future::Future<Output = Result<(File, FileIOStream), glib::Error>> + 'static>,
87 > {
88 let tmpl = tmpl.map(|tmpl| tmpl.as_ref().to_owned());
89 Box::pin(crate::GioFuture::new(
90 &(),
91 move |_obj, cancellable, send| {
92 Self::new_tmp_async(
93 tmpl.as_ref()
94 .map(<std::path::PathBuf as std::borrow::Borrow<std::path::Path>>::borrow),
95 io_priority,
96 Some(cancellable),
97 move |res| {
98 send.resolve(res);
99 },
100 );
101 },
102 ))
103 }
104
105 #[cfg(feature = "v2_74")]
121 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
122 #[doc(alias = "g_file_new_tmp_dir_async")]
123 pub fn new_tmp_dir_async<P: FnOnce(Result<File, glib::Error>) + 'static>(
124 tmpl: Option<impl AsRef<std::path::Path>>,
125 io_priority: glib::Priority,
126 cancellable: Option<&impl IsA<Cancellable>>,
127 callback: P,
128 ) {
129 let main_context = glib::MainContext::ref_thread_default();
130 let is_main_context_owner = main_context.is_owner();
131 let has_acquired_main_context = (!is_main_context_owner)
132 .then(|| main_context.acquire().ok())
133 .flatten();
134 assert!(
135 is_main_context_owner || has_acquired_main_context.is_some(),
136 "Async operations only allowed if the thread is owning the MainContext"
137 );
138
139 let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
140 Box::new(glib::thread_guard::ThreadGuard::new(callback));
141 unsafe extern "C" fn new_tmp_dir_async_trampoline<
142 P: FnOnce(Result<File, glib::Error>) + 'static,
143 >(
144 _source_object: *mut glib::gobject_ffi::GObject,
145 res: *mut crate::ffi::GAsyncResult,
146 user_data: glib::ffi::gpointer,
147 ) {
148 let mut error = ptr::null_mut();
149 let ret = ffi::g_file_new_tmp_dir_finish(res, &mut error);
150 let result = if error.is_null() {
151 Ok(from_glib_full(ret))
152 } else {
153 Err(from_glib_full(error))
154 };
155 let callback: Box<glib::thread_guard::ThreadGuard<P>> =
156 Box::from_raw(user_data as *mut _);
157 let callback: P = callback.into_inner();
158 callback(result);
159 }
160 let callback = new_tmp_dir_async_trampoline::<P>;
161 unsafe {
162 ffi::g_file_new_tmp_dir_async(
163 tmpl.as_ref().map(|p| p.as_ref()).to_glib_none().0,
164 io_priority.into_glib(),
165 cancellable.map(|p| p.as_ref()).to_glib_none().0,
166 Some(callback),
167 Box::into_raw(user_data) as *mut _,
168 );
169 }
170 }
171
172 #[cfg(feature = "v2_74")]
173 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
174 pub fn new_tmp_dir_future(
175 tmpl: Option<impl AsRef<std::path::Path>>,
176 io_priority: glib::Priority,
177 ) -> Pin<Box<dyn std::future::Future<Output = Result<File, glib::Error>> + 'static>> {
178 let tmpl = tmpl.map(|tmpl| tmpl.as_ref().to_owned());
179 Box::pin(crate::GioFuture::new(
180 &(),
181 move |_obj, cancellable, send| {
182 Self::new_tmp_dir_async(
183 tmpl.as_ref()
184 .map(<std::path::PathBuf as std::borrow::Borrow<std::path::Path>>::borrow),
185 io_priority,
186 Some(cancellable),
187 move |res| {
188 send.resolve(res);
189 },
190 );
191 },
192 ))
193 }
194}
195
196mod sealed {
197 pub trait Sealed {}
198 impl<T: super::IsA<super::File>> Sealed for T {}
199}
200
201pub trait FileExtManual: sealed::Sealed + IsA<File> + Sized {
202 #[doc(alias = "g_file_replace_contents_async")]
234 fn replace_contents_async<
235 B: AsRef<[u8]> + Send + 'static,
236 R: FnOnce(Result<(B, glib::GString), (B, glib::Error)>) + 'static,
237 C: IsA<Cancellable>,
238 >(
239 &self,
240 contents: B,
241 etag: Option<&str>,
242 make_backup: bool,
243 flags: FileCreateFlags,
244 cancellable: Option<&C>,
245 callback: R,
246 ) {
247 let main_context = glib::MainContext::ref_thread_default();
248 let is_main_context_owner = main_context.is_owner();
249 let has_acquired_main_context = (!is_main_context_owner)
250 .then(|| main_context.acquire().ok())
251 .flatten();
252 assert!(
253 is_main_context_owner || has_acquired_main_context.is_some(),
254 "Async operations only allowed if the thread is owning the MainContext"
255 );
256
257 let etag = etag.to_glib_none();
258 let cancellable = cancellable.map(|c| c.as_ref());
259 let gcancellable = cancellable.to_glib_none();
260 let user_data: Box<(glib::thread_guard::ThreadGuard<R>, B)> =
261 Box::new((glib::thread_guard::ThreadGuard::new(callback), contents));
262 let (count, contents_ptr) = {
264 let contents = &user_data.1;
265 let slice = contents.as_ref();
266 (slice.len(), slice.as_ptr())
267 };
268 unsafe extern "C" fn replace_contents_async_trampoline<
269 B: AsRef<[u8]> + Send + 'static,
270 R: FnOnce(Result<(B, glib::GString), (B, glib::Error)>) + 'static,
271 >(
272 _source_object: *mut glib::gobject_ffi::GObject,
273 res: *mut ffi::GAsyncResult,
274 user_data: glib::ffi::gpointer,
275 ) {
276 let user_data: Box<(glib::thread_guard::ThreadGuard<R>, B)> =
277 Box::from_raw(user_data as *mut _);
278 let (callback, contents) = *user_data;
279 let callback = callback.into_inner();
280
281 let mut error = ptr::null_mut();
282 let mut new_etag = ptr::null_mut();
283 let _ = ffi::g_file_replace_contents_finish(
284 _source_object as *mut _,
285 res,
286 &mut new_etag,
287 &mut error,
288 );
289 let result = if error.is_null() {
290 Ok((contents, from_glib_full(new_etag)))
291 } else {
292 Err((contents, from_glib_full(error)))
293 };
294 callback(result);
295 }
296 let callback = replace_contents_async_trampoline::<B, R>;
297 unsafe {
298 ffi::g_file_replace_contents_async(
299 self.as_ref().to_glib_none().0,
300 mut_override(contents_ptr),
301 count,
302 etag.0,
303 make_backup.into_glib(),
304 flags.into_glib(),
305 gcancellable.0,
306 Some(callback),
307 Box::into_raw(user_data) as *mut _,
308 );
309 }
310 }
311
312 fn replace_contents_future<B: AsRef<[u8]> + Send + 'static>(
313 &self,
314 contents: B,
315 etag: Option<&str>,
316 make_backup: bool,
317 flags: FileCreateFlags,
318 ) -> Pin<
319 Box<
320 dyn std::future::Future<Output = Result<(B, glib::GString), (B, glib::Error)>>
321 + 'static,
322 >,
323 > {
324 let etag = etag.map(glib::GString::from);
325 Box::pin(crate::GioFuture::new(
326 self,
327 move |obj, cancellable, send| {
328 obj.replace_contents_async(
329 contents,
330 etag.as_ref().map(|s| s.as_str()),
331 make_backup,
332 flags,
333 Some(cancellable),
334 move |res| {
335 send.resolve(res);
336 },
337 );
338 },
339 ))
340 }
341
342 #[doc(alias = "g_file_enumerate_children_async")]
343 fn enumerate_children_async<
344 P: IsA<Cancellable>,
345 Q: FnOnce(Result<FileEnumerator, glib::Error>) + 'static,
346 >(
347 &self,
348 attributes: &str,
349 flags: FileQueryInfoFlags,
350 io_priority: glib::Priority,
351 cancellable: Option<&P>,
352 callback: Q,
353 ) {
354 let main_context = glib::MainContext::ref_thread_default();
355 let is_main_context_owner = main_context.is_owner();
356 let has_acquired_main_context = (!is_main_context_owner)
357 .then(|| main_context.acquire().ok())
358 .flatten();
359 assert!(
360 is_main_context_owner || has_acquired_main_context.is_some(),
361 "Async operations only allowed if the thread is owning the MainContext"
362 );
363
364 let user_data: Box<glib::thread_guard::ThreadGuard<Q>> =
365 Box::new(glib::thread_guard::ThreadGuard::new(callback));
366 unsafe extern "C" fn create_async_trampoline<
367 Q: FnOnce(Result<FileEnumerator, glib::Error>) + 'static,
368 >(
369 _source_object: *mut glib::gobject_ffi::GObject,
370 res: *mut crate::ffi::GAsyncResult,
371 user_data: glib::ffi::gpointer,
372 ) {
373 let mut error = ptr::null_mut();
374 let ret =
375 ffi::g_file_enumerate_children_finish(_source_object as *mut _, res, &mut error);
376 let result = if error.is_null() {
377 Ok(from_glib_full(ret))
378 } else {
379 Err(from_glib_full(error))
380 };
381 let callback: Box<glib::thread_guard::ThreadGuard<Q>> =
382 Box::from_raw(user_data as *mut _);
383 let callback = callback.into_inner();
384 callback(result);
385 }
386 let callback = create_async_trampoline::<Q>;
387 unsafe {
388 ffi::g_file_enumerate_children_async(
389 self.as_ref().to_glib_none().0,
390 attributes.to_glib_none().0,
391 flags.into_glib(),
392 io_priority.into_glib(),
393 cancellable.map(|p| p.as_ref()).to_glib_none().0,
394 Some(callback),
395 Box::into_raw(user_data) as *mut _,
396 );
397 }
398 }
399
400 fn enumerate_children_future(
401 &self,
402 attributes: &str,
403 flags: FileQueryInfoFlags,
404 io_priority: glib::Priority,
405 ) -> Pin<Box<dyn std::future::Future<Output = Result<FileEnumerator, glib::Error>> + 'static>>
406 {
407 let attributes = attributes.to_owned();
408 Box::pin(crate::GioFuture::new(
409 self,
410 move |obj, cancellable, send| {
411 obj.enumerate_children_async(
412 &attributes,
413 flags,
414 io_priority,
415 Some(cancellable),
416 move |res| {
417 send.resolve(res);
418 },
419 );
420 },
421 ))
422 }
423
424 #[doc(alias = "g_file_copy_async")]
453 fn copy_async<Q: FnOnce(Result<(), glib::Error>) + 'static>(
454 &self,
455 destination: &impl IsA<File>,
456 flags: crate::FileCopyFlags,
457 io_priority: glib::Priority,
458 cancellable: Option<&impl IsA<Cancellable>>,
459 progress_callback: Option<Box<dyn FnMut(i64, i64)>>,
460 callback: Q,
461 ) {
462 let main_context = glib::MainContext::ref_thread_default();
463 let is_main_context_owner = main_context.is_owner();
464 let has_acquired_main_context = (!is_main_context_owner)
465 .then(|| main_context.acquire().ok())
466 .flatten();
467 assert!(
468 is_main_context_owner || has_acquired_main_context.is_some(),
469 "Async operations only allowed if the thread is owning the MainContext"
470 );
471
472 let progress_trampoline = if progress_callback.is_some() {
473 Some(copy_async_progress_trampoline::<Q> as _)
474 } else {
475 None
476 };
477
478 let user_data: Box<(
479 glib::thread_guard::ThreadGuard<Q>,
480 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
481 )> = Box::new((
482 glib::thread_guard::ThreadGuard::new(callback),
483 RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
484 ));
485 unsafe extern "C" fn copy_async_trampoline<Q: FnOnce(Result<(), glib::Error>) + 'static>(
486 _source_object: *mut glib::gobject_ffi::GObject,
487 res: *mut crate::ffi::GAsyncResult,
488 user_data: glib::ffi::gpointer,
489 ) {
490 let mut error = ptr::null_mut();
491 ffi::g_file_copy_finish(_source_object as *mut _, res, &mut error);
492 let result = if error.is_null() {
493 Ok(())
494 } else {
495 Err(from_glib_full(error))
496 };
497 let callback: Box<(
498 glib::thread_guard::ThreadGuard<Q>,
499 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
500 )> = Box::from_raw(user_data as *mut _);
501 let callback = callback.0.into_inner();
502 callback(result);
503 }
504 unsafe extern "C" fn copy_async_progress_trampoline<
505 Q: FnOnce(Result<(), glib::Error>) + 'static,
506 >(
507 current_num_bytes: i64,
508 total_num_bytes: i64,
509 user_data: glib::ffi::gpointer,
510 ) {
511 let callback: &(
512 glib::thread_guard::ThreadGuard<Q>,
513 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
514 ) = &*(user_data as *const _);
515 (callback
516 .1
517 .borrow_mut()
518 .as_mut()
519 .expect("no closure")
520 .get_mut())(current_num_bytes, total_num_bytes);
521 }
522
523 let user_data = Box::into_raw(user_data) as *mut _;
524
525 unsafe {
526 ffi::g_file_copy_async(
527 self.as_ref().to_glib_none().0,
528 destination.as_ref().to_glib_none().0,
529 flags.into_glib(),
530 io_priority.into_glib(),
531 cancellable.map(|p| p.as_ref()).to_glib_none().0,
532 progress_trampoline,
533 user_data,
534 Some(copy_async_trampoline::<Q>),
535 user_data,
536 );
537 }
538 }
539
540 fn copy_future(
541 &self,
542 destination: &(impl IsA<File> + Clone + 'static),
543 flags: crate::FileCopyFlags,
544 io_priority: glib::Priority,
545 ) -> (
546 Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>>,
547 Pin<Box<dyn futures_core::stream::Stream<Item = (i64, i64)> + 'static>>,
548 ) {
549 let destination = destination.clone();
550
551 let (sender, receiver) = futures_channel::mpsc::unbounded();
552
553 let fut = Box::pin(crate::GioFuture::new(
554 self,
555 move |obj, cancellable, send| {
556 obj.copy_async(
557 &destination,
558 flags,
559 io_priority,
560 Some(cancellable),
561 Some(Box::new(move |current_num_bytes, total_num_bytes| {
562 let _ = sender.unbounded_send((current_num_bytes, total_num_bytes));
563 })),
564 move |res| {
565 send.resolve(res);
566 },
567 );
568 },
569 ));
570
571 (fut, Box::pin(receiver))
572 }
573
574 #[doc(alias = "g_file_load_contents")]
597 fn load_contents(
598 &self,
599 cancellable: Option<&impl IsA<Cancellable>>,
600 ) -> Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error> {
601 unsafe {
602 let mut contents = std::ptr::null_mut();
603 let mut length = std::mem::MaybeUninit::uninit();
604 let mut etag_out = std::ptr::null_mut();
605 let mut error = std::ptr::null_mut();
606 let is_ok = ffi::g_file_load_contents(
607 self.as_ref().to_glib_none().0,
608 cancellable.map(|p| p.as_ref()).to_glib_none().0,
609 &mut contents,
610 length.as_mut_ptr(),
611 &mut etag_out,
612 &mut error,
613 );
614 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
615 if error.is_null() {
616 Ok((
617 FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
618 from_glib_full(etag_out),
619 ))
620 } else {
621 Err(from_glib_full(error))
622 }
623 }
624 }
625
626 #[doc(alias = "g_file_load_contents_async")]
644 fn load_contents_async<
645 P: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
646 + 'static,
647 >(
648 &self,
649 cancellable: Option<&impl IsA<Cancellable>>,
650 callback: P,
651 ) {
652 let main_context = glib::MainContext::ref_thread_default();
653 let is_main_context_owner = main_context.is_owner();
654 let has_acquired_main_context = (!is_main_context_owner)
655 .then(|| main_context.acquire().ok())
656 .flatten();
657 assert!(
658 is_main_context_owner || has_acquired_main_context.is_some(),
659 "Async operations only allowed if the thread is owning the MainContext"
660 );
661
662 let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
663 Box::new(glib::thread_guard::ThreadGuard::new(callback));
664 unsafe extern "C" fn load_contents_async_trampoline<
665 P: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
666 + 'static,
667 >(
668 _source_object: *mut glib::gobject_ffi::GObject,
669 res: *mut crate::ffi::GAsyncResult,
670 user_data: glib::ffi::gpointer,
671 ) {
672 let mut error = std::ptr::null_mut();
673 let mut contents = std::ptr::null_mut();
674 let mut length = std::mem::MaybeUninit::uninit();
675 let mut etag_out = std::ptr::null_mut();
676 let _ = ffi::g_file_load_contents_finish(
677 _source_object as *mut _,
678 res,
679 &mut contents,
680 length.as_mut_ptr(),
681 &mut etag_out,
682 &mut error,
683 );
684 let result = if error.is_null() {
685 Ok((
686 FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
687 from_glib_full(etag_out),
688 ))
689 } else {
690 Err(from_glib_full(error))
691 };
692 let callback: Box<glib::thread_guard::ThreadGuard<P>> =
693 Box::from_raw(user_data as *mut _);
694 let callback: P = callback.into_inner();
695 callback(result);
696 }
697 let callback = load_contents_async_trampoline::<P>;
698 unsafe {
699 ffi::g_file_load_contents_async(
700 self.as_ref().to_glib_none().0,
701 cancellable.map(|p| p.as_ref()).to_glib_none().0,
702 Some(callback),
703 Box::into_raw(user_data) as *mut _,
704 );
705 }
706 }
707
708 fn load_contents_future(
709 &self,
710 ) -> Pin<
711 Box<
712 dyn std::future::Future<
713 Output = Result<
714 (glib::collections::Slice<u8>, Option<glib::GString>),
715 glib::Error,
716 >,
717 > + 'static,
718 >,
719 > {
720 Box::pin(crate::GioFuture::new(
721 self,
722 move |obj, cancellable, send| {
723 obj.load_contents_async(Some(cancellable), move |res| {
724 send.resolve(res);
725 });
726 },
727 ))
728 }
729
730 #[doc(alias = "g_file_load_partial_contents_async")]
751 fn load_partial_contents_async<
752 P: FnMut(&[u8]) -> bool + 'static,
753 Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
754 + 'static,
755 >(
756 &self,
757 cancellable: Option<&impl IsA<Cancellable>>,
758 read_more_callback: P,
759 callback: Q,
760 ) {
761 let main_context = glib::MainContext::ref_thread_default();
762 let is_main_context_owner = main_context.is_owner();
763 let has_acquired_main_context = (!is_main_context_owner)
764 .then(|| main_context.acquire().ok())
765 .flatten();
766 assert!(
767 is_main_context_owner || has_acquired_main_context.is_some(),
768 "Async operations only allowed if the thread is owning the MainContext"
769 );
770
771 let user_data: Box<(
772 glib::thread_guard::ThreadGuard<Q>,
773 RefCell<glib::thread_guard::ThreadGuard<P>>,
774 )> = Box::new((
775 glib::thread_guard::ThreadGuard::new(callback),
776 RefCell::new(glib::thread_guard::ThreadGuard::new(read_more_callback)),
777 ));
778 unsafe extern "C" fn load_partial_contents_async_trampoline<
779 P: FnMut(&[u8]) -> bool + 'static,
780 Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
781 + 'static,
782 >(
783 _source_object: *mut glib::gobject_ffi::GObject,
784 res: *mut crate::ffi::GAsyncResult,
785 user_data: glib::ffi::gpointer,
786 ) {
787 let mut contents = ptr::null_mut();
788 let mut length = mem::MaybeUninit::uninit();
789 let mut etag_out = ptr::null_mut();
790 let mut error = ptr::null_mut();
791 ffi::g_file_load_partial_contents_finish(
792 _source_object as *mut _,
793 res,
794 &mut contents,
795 length.as_mut_ptr(),
796 &mut etag_out,
797 &mut error,
798 );
799 let result = if error.is_null() {
800 Ok((
801 FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
802 from_glib_full(etag_out),
803 ))
804 } else {
805 Err(from_glib_full(error))
806 };
807 let callback: Box<(
808 glib::thread_guard::ThreadGuard<Q>,
809 RefCell<glib::thread_guard::ThreadGuard<P>>,
810 )> = Box::from_raw(user_data as *mut _);
811 let callback = callback.0.into_inner();
812 callback(result);
813 }
814 unsafe extern "C" fn load_partial_contents_async_read_more_trampoline<
815 P: FnMut(&[u8]) -> bool + 'static,
816 Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
817 + 'static,
818 >(
819 file_contents: *const libc::c_char,
820 file_size: i64,
821 user_data: glib::ffi::gpointer,
822 ) -> glib::ffi::gboolean {
823 use std::slice;
824
825 let callback: &(
826 glib::thread_guard::ThreadGuard<Q>,
827 RefCell<glib::thread_guard::ThreadGuard<P>>,
828 ) = &*(user_data as *const _);
829 let data = if file_size == 0 {
830 &[]
831 } else {
832 slice::from_raw_parts(file_contents as *const u8, file_size as usize)
833 };
834
835 (*callback.1.borrow_mut().get_mut())(data).into_glib()
836 }
837
838 let user_data = Box::into_raw(user_data) as *mut _;
839
840 unsafe {
841 ffi::g_file_load_partial_contents_async(
842 self.as_ref().to_glib_none().0,
843 cancellable.map(|p| p.as_ref()).to_glib_none().0,
844 Some(load_partial_contents_async_read_more_trampoline::<P, Q>),
845 Some(load_partial_contents_async_trampoline::<P, Q>),
846 user_data,
847 );
848 }
849 }
850
851 #[doc(alias = "g_file_measure_disk_usage")]
892 fn measure_disk_usage(
893 &self,
894 flags: crate::FileMeasureFlags,
895 cancellable: Option<&impl IsA<Cancellable>>,
896 progress_callback: Option<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
897 ) -> Result<(u64, u64, u64), glib::Error> {
898 let progress_callback_data: Box<
899 Option<RefCell<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>>,
900 > = Box::new(progress_callback.map(RefCell::new));
901 unsafe extern "C" fn progress_callback_func(
902 reporting: glib::ffi::gboolean,
903 current_size: u64,
904 num_dirs: u64,
905 num_files: u64,
906 user_data: glib::ffi::gpointer,
907 ) {
908 let reporting = from_glib(reporting);
909 let callback: &Option<RefCell<Box<dyn Fn(bool, u64, u64, u64) + 'static>>> =
910 &*(user_data as *mut _);
911 if let Some(ref callback) = *callback {
912 (*callback.borrow_mut())(reporting, current_size, num_dirs, num_files)
913 } else {
914 panic!("cannot get closure...")
915 };
916 }
917 let progress_callback = if progress_callback_data.is_some() {
918 Some(progress_callback_func as _)
919 } else {
920 None
921 };
922 let super_callback0: Box<Option<RefCell<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>>> =
923 progress_callback_data;
924 unsafe {
925 let mut disk_usage = mem::MaybeUninit::uninit();
926 let mut num_dirs = mem::MaybeUninit::uninit();
927 let mut num_files = mem::MaybeUninit::uninit();
928 let mut error = ptr::null_mut();
929 let _ = ffi::g_file_measure_disk_usage(
930 self.as_ref().to_glib_none().0,
931 flags.into_glib(),
932 cancellable.map(|p| p.as_ref()).to_glib_none().0,
933 progress_callback,
934 Box::into_raw(super_callback0) as *mut _,
935 disk_usage.as_mut_ptr(),
936 num_dirs.as_mut_ptr(),
937 num_files.as_mut_ptr(),
938 &mut error,
939 );
940 let disk_usage = disk_usage.assume_init();
941 let num_dirs = num_dirs.assume_init();
942 let num_files = num_files.assume_init();
943 if error.is_null() {
944 Ok((disk_usage, num_dirs, num_files))
945 } else {
946 Err(from_glib_full(error))
947 }
948 }
949 }
950
951 #[doc(alias = "g_file_measure_disk_usage_async")]
968 fn measure_disk_usage_async<P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static>(
969 &self,
970 flags: crate::FileMeasureFlags,
971 io_priority: glib::Priority,
972 cancellable: Option<&impl IsA<Cancellable>>,
973 progress_callback: Option<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
974 callback: P,
975 ) {
976 let main_context = glib::MainContext::ref_thread_default();
977 let is_main_context_owner = main_context.is_owner();
978 let has_acquired_main_context = (!is_main_context_owner)
979 .then(|| main_context.acquire().ok())
980 .flatten();
981 assert!(
982 is_main_context_owner || has_acquired_main_context.is_some(),
983 "Async operations only allowed if the thread is owning the MainContext"
984 );
985
986 let progress_callback_trampoline = if progress_callback.is_some() {
987 Some(measure_disk_usage_async_progress_trampoline::<P> as _)
988 } else {
989 None
990 };
991
992 let user_data: Box<(
993 glib::thread_guard::ThreadGuard<P>,
994 RefCell<
995 Option<
996 glib::thread_guard::ThreadGuard<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
997 >,
998 >,
999 )> = Box::new((
1000 glib::thread_guard::ThreadGuard::new(callback),
1001 RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
1002 ));
1003 unsafe extern "C" fn measure_disk_usage_async_trampoline<
1004 P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static,
1005 >(
1006 _source_object: *mut glib::gobject_ffi::GObject,
1007 res: *mut crate::ffi::GAsyncResult,
1008 user_data: glib::ffi::gpointer,
1009 ) {
1010 let mut disk_usage = mem::MaybeUninit::uninit();
1011 let mut num_dirs = mem::MaybeUninit::uninit();
1012 let mut num_files = mem::MaybeUninit::uninit();
1013 let mut error = ptr::null_mut();
1014 ffi::g_file_measure_disk_usage_finish(
1015 _source_object as *mut _,
1016 res,
1017 disk_usage.as_mut_ptr(),
1018 num_dirs.as_mut_ptr(),
1019 num_files.as_mut_ptr(),
1020 &mut error,
1021 );
1022 let result = if error.is_null() {
1023 Ok((
1024 disk_usage.assume_init(),
1025 num_dirs.assume_init(),
1026 num_files.assume_init(),
1027 ))
1028 } else {
1029 Err(from_glib_full(error))
1030 };
1031 let callback: Box<(
1032 glib::thread_guard::ThreadGuard<P>,
1033 RefCell<
1034 Option<
1035 glib::thread_guard::ThreadGuard<
1036 Box<dyn FnMut(bool, u64, u64, u64) + 'static>,
1037 >,
1038 >,
1039 >,
1040 )> = Box::from_raw(user_data as *mut _);
1041 let callback = callback.0.into_inner();
1042 callback(result);
1043 }
1044 unsafe extern "C" fn measure_disk_usage_async_progress_trampoline<
1045 P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static,
1046 >(
1047 reporting: glib::ffi::gboolean,
1048 disk_usage: u64,
1049 num_dirs: u64,
1050 num_files: u64,
1051 user_data: glib::ffi::gpointer,
1052 ) {
1053 let callback: &(
1054 glib::thread_guard::ThreadGuard<P>,
1055 RefCell<
1056 Option<
1057 glib::thread_guard::ThreadGuard<
1058 Box<dyn FnMut(bool, u64, u64, u64) + 'static>,
1059 >,
1060 >,
1061 >,
1062 ) = &*(user_data as *const _);
1063 (callback
1064 .1
1065 .borrow_mut()
1066 .as_mut()
1067 .expect("can't get callback")
1068 .get_mut())(from_glib(reporting), disk_usage, num_dirs, num_files);
1069 }
1070
1071 let user_data = Box::into_raw(user_data) as *mut _;
1072
1073 unsafe {
1074 ffi::g_file_measure_disk_usage_async(
1075 self.as_ref().to_glib_none().0,
1076 flags.into_glib(),
1077 io_priority.into_glib(),
1078 cancellable.map(|p| p.as_ref()).to_glib_none().0,
1079 progress_callback_trampoline,
1080 user_data,
1081 Some(measure_disk_usage_async_trampoline::<P>),
1082 user_data,
1083 );
1084 }
1085 }
1086
1087 fn measure_disk_usage_future(
1088 &self,
1089 flags: crate::FileMeasureFlags,
1090 io_priority: glib::Priority,
1091 ) -> (
1092 Pin<Box<dyn std::future::Future<Output = Result<(u64, u64, u64), glib::Error>> + 'static>>,
1093 Pin<Box<dyn futures_core::stream::Stream<Item = (bool, u64, u64, u64)> + 'static>>,
1094 ) {
1095 let (sender, receiver) = futures_channel::mpsc::unbounded();
1096
1097 let fut = Box::pin(crate::GioFuture::new(
1098 self,
1099 move |obj, cancellable, send| {
1100 obj.measure_disk_usage_async(
1101 flags,
1102 io_priority,
1103 Some(cancellable),
1104 Some(Box::new(
1105 move |reporting, disk_usage, num_dirs, num_files| {
1106 let _ =
1107 sender.unbounded_send((reporting, disk_usage, num_dirs, num_files));
1108 },
1109 )),
1110 move |res| {
1111 send.resolve(res);
1112 },
1113 );
1114 },
1115 ));
1116
1117 (fut, Box::pin(receiver))
1118 }
1119
1120 #[cfg(feature = "v2_72")]
1147 #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))]
1148 #[doc(alias = "g_file_move_async")]
1149 fn move_async<Q: FnOnce(Result<(), glib::Error>) + 'static>(
1150 &self,
1151 destination: &impl IsA<File>,
1152 flags: crate::FileCopyFlags,
1153 io_priority: glib::Priority,
1154 cancellable: Option<&impl IsA<Cancellable>>,
1155 progress_callback: Option<Box<dyn FnMut(i64, i64)>>,
1156 callback: Q,
1157 ) {
1158 let main_context = glib::MainContext::ref_thread_default();
1159 let is_main_context_owner = main_context.is_owner();
1160 let has_acquired_main_context = (!is_main_context_owner)
1161 .then(|| main_context.acquire().ok())
1162 .flatten();
1163 assert!(
1164 is_main_context_owner || has_acquired_main_context.is_some(),
1165 "Async operations only allowed if the thread is owning the MainContext"
1166 );
1167
1168 let progress_trampoline = if progress_callback.is_some() {
1169 Some(move_async_progress_trampoline::<Q> as _)
1170 } else {
1171 None
1172 };
1173
1174 let user_data: Box<(
1175 glib::thread_guard::ThreadGuard<Q>,
1176 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
1177 )> = Box::new((
1178 glib::thread_guard::ThreadGuard::new(callback),
1179 RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
1180 ));
1181 unsafe extern "C" fn move_async_trampoline<Q: FnOnce(Result<(), glib::Error>) + 'static>(
1182 _source_object: *mut glib::gobject_ffi::GObject,
1183 res: *mut crate::ffi::GAsyncResult,
1184 user_data: glib::ffi::gpointer,
1185 ) {
1186 let mut error = ptr::null_mut();
1187 ffi::g_file_move_finish(_source_object as *mut _, res, &mut error);
1188 let result = if error.is_null() {
1189 Ok(())
1190 } else {
1191 Err(from_glib_full(error))
1192 };
1193 let callback: Box<(
1194 glib::thread_guard::ThreadGuard<Q>,
1195 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
1196 )> = Box::from_raw(user_data as *mut _);
1197 let callback = callback.0.into_inner();
1198 callback(result);
1199 }
1200 unsafe extern "C" fn move_async_progress_trampoline<
1201 Q: FnOnce(Result<(), glib::Error>) + 'static,
1202 >(
1203 current_num_bytes: i64,
1204 total_num_bytes: i64,
1205 user_data: glib::ffi::gpointer,
1206 ) {
1207 let callback: &(
1208 glib::thread_guard::ThreadGuard<Q>,
1209 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
1210 ) = &*(user_data as *const _);
1211 (callback
1212 .1
1213 .borrow_mut()
1214 .as_mut()
1215 .expect("no closure")
1216 .get_mut())(current_num_bytes, total_num_bytes);
1217 }
1218
1219 let user_data = Box::into_raw(user_data) as *mut _;
1220
1221 unsafe {
1222 ffi::g_file_move_async(
1223 self.as_ref().to_glib_none().0,
1224 destination.as_ref().to_glib_none().0,
1225 flags.into_glib(),
1226 io_priority.into_glib(),
1227 cancellable.map(|p| p.as_ref()).to_glib_none().0,
1228 progress_trampoline,
1229 user_data,
1230 Some(move_async_trampoline::<Q>),
1231 user_data,
1232 );
1233 }
1234 }
1235
1236 #[cfg(feature = "v2_74")]
1250 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
1251 #[doc(alias = "g_file_make_symbolic_link_async")]
1252 fn make_symbolic_link_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
1253 &self,
1254 symlink_value: impl AsRef<std::path::Path>,
1255 io_priority: glib::Priority,
1256 cancellable: Option<&impl IsA<Cancellable>>,
1257 callback: P,
1258 ) {
1259 let main_context = glib::MainContext::ref_thread_default();
1260 let is_main_context_owner = main_context.is_owner();
1261 let has_acquired_main_context = (!is_main_context_owner)
1262 .then(|| main_context.acquire().ok())
1263 .flatten();
1264 assert!(
1265 is_main_context_owner || has_acquired_main_context.is_some(),
1266 "Async operations only allowed if the thread is owning the MainContext"
1267 );
1268
1269 let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
1270 Box::new(glib::thread_guard::ThreadGuard::new(callback));
1271 unsafe extern "C" fn make_symbolic_link_async_trampoline<
1272 P: FnOnce(Result<(), glib::Error>) + 'static,
1273 >(
1274 _source_object: *mut glib::gobject_ffi::GObject,
1275 res: *mut crate::ffi::GAsyncResult,
1276 user_data: glib::ffi::gpointer,
1277 ) {
1278 let mut error = ptr::null_mut();
1279 let _ =
1280 ffi::g_file_make_symbolic_link_finish(_source_object as *mut _, res, &mut error);
1281 let result = if error.is_null() {
1282 Ok(())
1283 } else {
1284 Err(from_glib_full(error))
1285 };
1286 let callback: Box<glib::thread_guard::ThreadGuard<P>> =
1287 Box::from_raw(user_data as *mut _);
1288 let callback: P = callback.into_inner();
1289 callback(result);
1290 }
1291 let callback = make_symbolic_link_async_trampoline::<P>;
1292 unsafe {
1293 ffi::g_file_make_symbolic_link_async(
1294 self.as_ref().to_glib_none().0,
1295 symlink_value.as_ref().to_glib_none().0,
1296 io_priority.into_glib(),
1297 cancellable.map(|p| p.as_ref()).to_glib_none().0,
1298 Some(callback),
1299 Box::into_raw(user_data) as *mut _,
1300 );
1301 }
1302 }
1303
1304 #[cfg(feature = "v2_74")]
1305 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
1306 fn make_symbolic_link_future(
1307 &self,
1308 symlink_value: impl AsRef<std::path::Path>,
1309 io_priority: glib::Priority,
1310 ) -> Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
1311 let symlink_value = symlink_value.as_ref().to_owned();
1312 Box::pin(crate::GioFuture::new(
1313 self,
1314 move |obj, cancellable, send| {
1315 obj.make_symbolic_link_async(
1316 &symlink_value,
1317 io_priority,
1318 Some(cancellable),
1319 move |res| {
1320 send.resolve(res);
1321 },
1322 );
1323 },
1324 ))
1325 }
1326
1327 #[cfg(feature = "v2_72")]
1328 #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))]
1329 fn move_future(
1330 &self,
1331 destination: &(impl IsA<File> + Clone + 'static),
1332 flags: crate::FileCopyFlags,
1333 io_priority: glib::Priority,
1334 ) -> (
1335 Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>>,
1336 Pin<Box<dyn futures_core::stream::Stream<Item = (i64, i64)> + 'static>>,
1337 ) {
1338 let destination = destination.clone();
1339
1340 let (sender, receiver) = futures_channel::mpsc::unbounded();
1341
1342 let fut = Box::pin(crate::GioFuture::new(
1343 self,
1344 move |obj, cancellable, send| {
1345 obj.move_async(
1346 &destination,
1347 flags,
1348 io_priority,
1349 Some(cancellable),
1350 Some(Box::new(move |current_num_bytes, total_num_bytes| {
1351 let _ = sender.unbounded_send((current_num_bytes, total_num_bytes));
1352 })),
1353 move |res| {
1354 send.resolve(res);
1355 },
1356 );
1357 },
1358 ));
1359
1360 (fut, Box::pin(receiver))
1361 }
1362}
1363
1364impl<O: IsA<File>> FileExtManual for O {}