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")]
901 fn measure_disk_usage(
902 &self,
903 flags: crate::FileMeasureFlags,
904 cancellable: Option<&impl IsA<Cancellable>>,
905 progress_callback: Option<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
906 ) -> Result<(u64, u64, u64), glib::Error> {
907 let progress_callback_data: Box<
908 Option<RefCell<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>>,
909 > = Box::new(progress_callback.map(RefCell::new));
910 unsafe extern "C" fn progress_callback_func(
911 reporting: glib::ffi::gboolean,
912 current_size: u64,
913 num_dirs: u64,
914 num_files: u64,
915 user_data: glib::ffi::gpointer,
916 ) {
917 unsafe {
918 let reporting = from_glib(reporting);
919 let callback: &Option<RefCell<Box<dyn Fn(bool, u64, u64, u64) + 'static>>> =
920 &*(user_data as *mut _);
921 if let Some(ref callback) = *callback {
922 (*callback.borrow_mut())(reporting, current_size, num_dirs, num_files)
923 } else {
924 panic!("cannot get closure...")
925 };
926 }
927 }
928 let progress_callback = if progress_callback_data.is_some() {
929 Some(progress_callback_func as _)
930 } else {
931 None
932 };
933 let super_callback0: Box<Option<RefCell<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>>> =
934 progress_callback_data;
935 unsafe {
936 let mut disk_usage = mem::MaybeUninit::uninit();
937 let mut num_dirs = mem::MaybeUninit::uninit();
938 let mut num_files = mem::MaybeUninit::uninit();
939 let mut error = ptr::null_mut();
940 let _ = ffi::g_file_measure_disk_usage(
941 self.as_ref().to_glib_none().0,
942 flags.into_glib(),
943 cancellable.map(|p| p.as_ref()).to_glib_none().0,
944 progress_callback,
945 Box::into_raw(super_callback0) as *mut _,
946 disk_usage.as_mut_ptr(),
947 num_dirs.as_mut_ptr(),
948 num_files.as_mut_ptr(),
949 &mut error,
950 );
951 let disk_usage = disk_usage.assume_init();
952 let num_dirs = num_dirs.assume_init();
953 let num_files = num_files.assume_init();
954 if error.is_null() {
955 Ok((disk_usage, num_dirs, num_files))
956 } else {
957 Err(from_glib_full(error))
958 }
959 }
960 }
961
962 #[doc(alias = "g_file_measure_disk_usage_async")]
979 fn measure_disk_usage_async<P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static>(
980 &self,
981 flags: crate::FileMeasureFlags,
982 io_priority: glib::Priority,
983 cancellable: Option<&impl IsA<Cancellable>>,
984 progress_callback: Option<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
985 callback: P,
986 ) {
987 let main_context = glib::MainContext::ref_thread_default();
988 let is_main_context_owner = main_context.is_owner();
989 let has_acquired_main_context = (!is_main_context_owner)
990 .then(|| main_context.acquire().ok())
991 .flatten();
992 assert!(
993 is_main_context_owner || has_acquired_main_context.is_some(),
994 "Async operations only allowed if the thread is owning the MainContext"
995 );
996
997 let progress_callback_trampoline = if progress_callback.is_some() {
998 Some(measure_disk_usage_async_progress_trampoline::<P> as _)
999 } else {
1000 None
1001 };
1002
1003 let user_data: Box<(
1004 glib::thread_guard::ThreadGuard<P>,
1005 RefCell<
1006 Option<
1007 glib::thread_guard::ThreadGuard<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
1008 >,
1009 >,
1010 )> = Box::new((
1011 glib::thread_guard::ThreadGuard::new(callback),
1012 RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
1013 ));
1014 unsafe extern "C" fn measure_disk_usage_async_trampoline<
1015 P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static,
1016 >(
1017 _source_object: *mut glib::gobject_ffi::GObject,
1018 res: *mut crate::ffi::GAsyncResult,
1019 user_data: glib::ffi::gpointer,
1020 ) {
1021 unsafe {
1022 let mut disk_usage = mem::MaybeUninit::uninit();
1023 let mut num_dirs = mem::MaybeUninit::uninit();
1024 let mut num_files = mem::MaybeUninit::uninit();
1025 let mut error = ptr::null_mut();
1026 ffi::g_file_measure_disk_usage_finish(
1027 _source_object as *mut _,
1028 res,
1029 disk_usage.as_mut_ptr(),
1030 num_dirs.as_mut_ptr(),
1031 num_files.as_mut_ptr(),
1032 &mut error,
1033 );
1034 let result = if error.is_null() {
1035 Ok((
1036 disk_usage.assume_init(),
1037 num_dirs.assume_init(),
1038 num_files.assume_init(),
1039 ))
1040 } else {
1041 Err(from_glib_full(error))
1042 };
1043 let callback: Box<(
1044 glib::thread_guard::ThreadGuard<P>,
1045 RefCell<
1046 Option<
1047 glib::thread_guard::ThreadGuard<
1048 Box<dyn FnMut(bool, u64, u64, u64) + 'static>,
1049 >,
1050 >,
1051 >,
1052 )> = Box::from_raw(user_data as *mut _);
1053 let callback = callback.0.into_inner();
1054 callback(result);
1055 }
1056 }
1057 unsafe extern "C" fn measure_disk_usage_async_progress_trampoline<
1058 P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static,
1059 >(
1060 reporting: glib::ffi::gboolean,
1061 disk_usage: u64,
1062 num_dirs: u64,
1063 num_files: u64,
1064 user_data: glib::ffi::gpointer,
1065 ) {
1066 unsafe {
1067 let callback: &(
1068 glib::thread_guard::ThreadGuard<P>,
1069 RefCell<
1070 Option<
1071 glib::thread_guard::ThreadGuard<
1072 Box<dyn FnMut(bool, u64, u64, u64) + 'static>,
1073 >,
1074 >,
1075 >,
1076 ) = &*(user_data as *const _);
1077 (callback
1078 .1
1079 .borrow_mut()
1080 .as_mut()
1081 .expect("can't get callback")
1082 .get_mut())(
1083 from_glib(reporting), disk_usage, num_dirs, num_files
1084 );
1085 }
1086 }
1087
1088 let user_data = Box::into_raw(user_data) as *mut _;
1089
1090 unsafe {
1091 ffi::g_file_measure_disk_usage_async(
1092 self.as_ref().to_glib_none().0,
1093 flags.into_glib(),
1094 io_priority.into_glib(),
1095 cancellable.map(|p| p.as_ref()).to_glib_none().0,
1096 progress_callback_trampoline,
1097 user_data,
1098 Some(measure_disk_usage_async_trampoline::<P>),
1099 user_data,
1100 );
1101 }
1102 }
1103
1104 fn measure_disk_usage_future(
1105 &self,
1106 flags: crate::FileMeasureFlags,
1107 io_priority: glib::Priority,
1108 ) -> (
1109 Pin<Box<dyn std::future::Future<Output = Result<(u64, u64, u64), glib::Error>> + 'static>>,
1110 Pin<Box<dyn futures_core::stream::Stream<Item = (bool, u64, u64, u64)> + 'static>>,
1111 ) {
1112 let (sender, receiver) = futures_channel::mpsc::unbounded();
1113
1114 let fut = Box::pin(crate::GioFuture::new(
1115 self,
1116 move |obj, cancellable, send| {
1117 obj.measure_disk_usage_async(
1118 flags,
1119 io_priority,
1120 Some(cancellable),
1121 Some(Box::new(
1122 move |reporting, disk_usage, num_dirs, num_files| {
1123 let _ =
1124 sender.unbounded_send((reporting, disk_usage, num_dirs, num_files));
1125 },
1126 )),
1127 move |res| {
1128 send.resolve(res);
1129 },
1130 );
1131 },
1132 ));
1133
1134 (fut, Box::pin(receiver))
1135 }
1136
1137 #[cfg(feature = "v2_72")]
1164 #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))]
1165 #[doc(alias = "g_file_move_async")]
1166 fn move_async<Q: FnOnce(Result<(), glib::Error>) + 'static>(
1167 &self,
1168 destination: &impl IsA<File>,
1169 flags: crate::FileCopyFlags,
1170 io_priority: glib::Priority,
1171 cancellable: Option<&impl IsA<Cancellable>>,
1172 progress_callback: Option<Box<dyn FnMut(i64, i64)>>,
1173 callback: Q,
1174 ) {
1175 let main_context = glib::MainContext::ref_thread_default();
1176 let is_main_context_owner = main_context.is_owner();
1177 let has_acquired_main_context = (!is_main_context_owner)
1178 .then(|| main_context.acquire().ok())
1179 .flatten();
1180 assert!(
1181 is_main_context_owner || has_acquired_main_context.is_some(),
1182 "Async operations only allowed if the thread is owning the MainContext"
1183 );
1184
1185 let progress_trampoline = if progress_callback.is_some() {
1186 Some(move_async_progress_trampoline::<Q> as _)
1187 } else {
1188 None
1189 };
1190
1191 let user_data: Box<(
1192 glib::thread_guard::ThreadGuard<Q>,
1193 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
1194 )> = Box::new((
1195 glib::thread_guard::ThreadGuard::new(callback),
1196 RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
1197 ));
1198 unsafe extern "C" fn move_async_trampoline<Q: FnOnce(Result<(), glib::Error>) + 'static>(
1199 _source_object: *mut glib::gobject_ffi::GObject,
1200 res: *mut crate::ffi::GAsyncResult,
1201 user_data: glib::ffi::gpointer,
1202 ) {
1203 unsafe {
1204 let mut error = ptr::null_mut();
1205 ffi::g_file_move_finish(_source_object as *mut _, res, &mut error);
1206 let result = if error.is_null() {
1207 Ok(())
1208 } else {
1209 Err(from_glib_full(error))
1210 };
1211 let callback: Box<(
1212 glib::thread_guard::ThreadGuard<Q>,
1213 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
1214 )> = Box::from_raw(user_data as *mut _);
1215 let callback = callback.0.into_inner();
1216 callback(result);
1217 }
1218 }
1219 unsafe extern "C" fn move_async_progress_trampoline<
1220 Q: FnOnce(Result<(), glib::Error>) + 'static,
1221 >(
1222 current_num_bytes: i64,
1223 total_num_bytes: i64,
1224 user_data: glib::ffi::gpointer,
1225 ) {
1226 unsafe {
1227 let callback: &(
1228 glib::thread_guard::ThreadGuard<Q>,
1229 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
1230 ) = &*(user_data as *const _);
1231 (callback
1232 .1
1233 .borrow_mut()
1234 .as_mut()
1235 .expect("no closure")
1236 .get_mut())(current_num_bytes, total_num_bytes);
1237 }
1238 }
1239
1240 let user_data = Box::into_raw(user_data) as *mut _;
1241
1242 unsafe {
1243 ffi::g_file_move_async(
1244 self.as_ref().to_glib_none().0,
1245 destination.as_ref().to_glib_none().0,
1246 flags.into_glib(),
1247 io_priority.into_glib(),
1248 cancellable.map(|p| p.as_ref()).to_glib_none().0,
1249 progress_trampoline,
1250 user_data,
1251 Some(move_async_trampoline::<Q>),
1252 user_data,
1253 );
1254 }
1255 }
1256
1257 #[cfg(feature = "v2_74")]
1271 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
1272 #[doc(alias = "g_file_make_symbolic_link_async")]
1273 fn make_symbolic_link_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
1274 &self,
1275 symlink_value: impl AsRef<std::path::Path>,
1276 io_priority: glib::Priority,
1277 cancellable: Option<&impl IsA<Cancellable>>,
1278 callback: P,
1279 ) {
1280 let main_context = glib::MainContext::ref_thread_default();
1281 let is_main_context_owner = main_context.is_owner();
1282 let has_acquired_main_context = (!is_main_context_owner)
1283 .then(|| main_context.acquire().ok())
1284 .flatten();
1285 assert!(
1286 is_main_context_owner || has_acquired_main_context.is_some(),
1287 "Async operations only allowed if the thread is owning the MainContext"
1288 );
1289
1290 let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
1291 Box::new(glib::thread_guard::ThreadGuard::new(callback));
1292 unsafe extern "C" fn make_symbolic_link_async_trampoline<
1293 P: FnOnce(Result<(), glib::Error>) + 'static,
1294 >(
1295 _source_object: *mut glib::gobject_ffi::GObject,
1296 res: *mut crate::ffi::GAsyncResult,
1297 user_data: glib::ffi::gpointer,
1298 ) {
1299 unsafe {
1300 let mut error = ptr::null_mut();
1301 let _ = ffi::g_file_make_symbolic_link_finish(
1302 _source_object as *mut _,
1303 res,
1304 &mut error,
1305 );
1306 let result = if error.is_null() {
1307 Ok(())
1308 } else {
1309 Err(from_glib_full(error))
1310 };
1311 let callback: Box<glib::thread_guard::ThreadGuard<P>> =
1312 Box::from_raw(user_data as *mut _);
1313 let callback: P = callback.into_inner();
1314 callback(result);
1315 }
1316 }
1317 let callback = make_symbolic_link_async_trampoline::<P>;
1318 unsafe {
1319 ffi::g_file_make_symbolic_link_async(
1320 self.as_ref().to_glib_none().0,
1321 symlink_value.as_ref().to_glib_none().0,
1322 io_priority.into_glib(),
1323 cancellable.map(|p| p.as_ref()).to_glib_none().0,
1324 Some(callback),
1325 Box::into_raw(user_data) as *mut _,
1326 );
1327 }
1328 }
1329
1330 #[cfg(feature = "v2_74")]
1331 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
1332 fn make_symbolic_link_future(
1333 &self,
1334 symlink_value: impl AsRef<std::path::Path>,
1335 io_priority: glib::Priority,
1336 ) -> Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
1337 let symlink_value = symlink_value.as_ref().to_owned();
1338 Box::pin(crate::GioFuture::new(
1339 self,
1340 move |obj, cancellable, send| {
1341 obj.make_symbolic_link_async(
1342 &symlink_value,
1343 io_priority,
1344 Some(cancellable),
1345 move |res| {
1346 send.resolve(res);
1347 },
1348 );
1349 },
1350 ))
1351 }
1352
1353 #[cfg(feature = "v2_72")]
1354 #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))]
1355 fn move_future(
1356 &self,
1357 destination: &(impl IsA<File> + Clone + 'static),
1358 flags: crate::FileCopyFlags,
1359 io_priority: glib::Priority,
1360 ) -> (
1361 Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>>,
1362 Pin<Box<dyn futures_core::stream::Stream<Item = (i64, i64)> + 'static>>,
1363 ) {
1364 let destination = destination.clone();
1365
1366 let (sender, receiver) = futures_channel::mpsc::unbounded();
1367
1368 let fut = Box::pin(crate::GioFuture::new(
1369 self,
1370 move |obj, cancellable, send| {
1371 obj.move_async(
1372 &destination,
1373 flags,
1374 io_priority,
1375 Some(cancellable),
1376 Some(Box::new(move |current_num_bytes, total_num_bytes| {
1377 let _ = sender.unbounded_send((current_num_bytes, total_num_bytes));
1378 })),
1379 move |res| {
1380 send.resolve(res);
1381 },
1382 );
1383 },
1384 ));
1385
1386 (fut, Box::pin(receiver))
1387 }
1388
1389 #[doc(alias = "g_file_set_attribute")]
1390 fn set_attribute<'a>(
1391 &self,
1392 attribute: &str,
1393 value: impl Into<FileAttributeValue<'a>>,
1394 flags: FileQueryInfoFlags,
1395 cancellable: Option<&impl IsA<Cancellable>>,
1396 ) -> Result<(), glib::Error> {
1397 unsafe {
1398 let mut error = std::ptr::null_mut();
1399 let value: FileAttributeValue<'a> = value.into();
1400 let is_ok = ffi::g_file_set_attribute(
1401 self.as_ref().to_glib_none().0,
1402 attribute.to_glib_none().0,
1403 value.type_().into_glib(),
1404 value.as_ptr(),
1405 flags.into_glib(),
1406 cancellable.map(|p| p.as_ref()).to_glib_none().0,
1407 &mut error,
1408 );
1409 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
1410 if error.is_null() {
1411 Ok(())
1412 } else {
1413 Err(from_glib_full(error))
1414 }
1415 }
1416 }
1417}
1418
1419impl<O: IsA<File>> FileExtManual for O {}