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