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