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")]
456 fn copy_async<Q: FnOnce(Result<(), glib::Error>) + 'static>(
457 &self,
458 destination: &impl IsA<File>,
459 flags: crate::FileCopyFlags,
460 io_priority: glib::Priority,
461 cancellable: Option<&impl IsA<Cancellable>>,
462 progress_callback: Option<Box<dyn FnMut(i64, i64)>>,
463 callback: Q,
464 ) {
465 let main_context = glib::MainContext::ref_thread_default();
466 let is_main_context_owner = main_context.is_owner();
467 let has_acquired_main_context = (!is_main_context_owner)
468 .then(|| main_context.acquire().ok())
469 .flatten();
470 assert!(
471 is_main_context_owner || has_acquired_main_context.is_some(),
472 "Async operations only allowed if the thread is owning the MainContext"
473 );
474
475 let progress_trampoline = if progress_callback.is_some() {
476 Some(copy_async_progress_trampoline::<Q> as _)
477 } else {
478 None
479 };
480
481 let user_data: Box<(
482 glib::thread_guard::ThreadGuard<Q>,
483 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
484 )> = Box::new((
485 glib::thread_guard::ThreadGuard::new(callback),
486 RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
487 ));
488 unsafe extern "C" fn copy_async_trampoline<Q: FnOnce(Result<(), glib::Error>) + 'static>(
489 _source_object: *mut glib::gobject_ffi::GObject,
490 res: *mut crate::ffi::GAsyncResult,
491 user_data: glib::ffi::gpointer,
492 ) {
493 unsafe {
494 let mut error = ptr::null_mut();
495 ffi::g_file_copy_finish(_source_object as *mut _, res, &mut error);
496 let result = if error.is_null() {
497 Ok(())
498 } else {
499 Err(from_glib_full(error))
500 };
501 let callback: Box<(
502 glib::thread_guard::ThreadGuard<Q>,
503 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
504 )> = Box::from_raw(user_data as *mut _);
505 let callback = callback.0.into_inner();
506 callback(result);
507 }
508 }
509 unsafe extern "C" fn copy_async_progress_trampoline<
510 Q: FnOnce(Result<(), glib::Error>) + 'static,
511 >(
512 current_num_bytes: i64,
513 total_num_bytes: i64,
514 user_data: glib::ffi::gpointer,
515 ) {
516 unsafe {
517 let callback: &(
518 glib::thread_guard::ThreadGuard<Q>,
519 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
520 ) = &*(user_data as *const _);
521 (callback
522 .1
523 .borrow_mut()
524 .as_mut()
525 .expect("no closure")
526 .get_mut())(current_num_bytes, total_num_bytes);
527 }
528 }
529
530 let user_data = Box::into_raw(user_data) as *mut _;
531
532 unsafe {
533 ffi::g_file_copy_async(
534 self.as_ref().to_glib_none().0,
535 destination.as_ref().to_glib_none().0,
536 flags.into_glib(),
537 io_priority.into_glib(),
538 cancellable.map(|p| p.as_ref()).to_glib_none().0,
539 progress_trampoline,
540 user_data,
541 Some(copy_async_trampoline::<Q>),
542 user_data,
543 );
544 }
545 }
546
547 fn copy_future(
548 &self,
549 destination: &(impl IsA<File> + Clone + 'static),
550 flags: crate::FileCopyFlags,
551 io_priority: glib::Priority,
552 ) -> (
553 Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>>,
554 Pin<Box<dyn futures_core::stream::Stream<Item = (i64, i64)> + 'static>>,
555 ) {
556 let destination = destination.clone();
557
558 let (sender, receiver) = futures_channel::mpsc::unbounded();
559
560 let fut = Box::pin(crate::GioFuture::new(
561 self,
562 move |obj, cancellable, send| {
563 obj.copy_async(
564 &destination,
565 flags,
566 io_priority,
567 Some(cancellable),
568 Some(Box::new(move |current_num_bytes, total_num_bytes| {
569 let _ = sender.unbounded_send((current_num_bytes, total_num_bytes));
570 })),
571 move |res| {
572 send.resolve(res);
573 },
574 );
575 },
576 ));
577
578 (fut, Box::pin(receiver))
579 }
580
581 #[doc(alias = "g_file_load_contents")]
604 fn load_contents(
605 &self,
606 cancellable: Option<&impl IsA<Cancellable>>,
607 ) -> Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error> {
608 unsafe {
609 let mut contents = std::ptr::null_mut();
610 let mut length = std::mem::MaybeUninit::uninit();
611 let mut etag_out = std::ptr::null_mut();
612 let mut error = std::ptr::null_mut();
613 let is_ok = ffi::g_file_load_contents(
614 self.as_ref().to_glib_none().0,
615 cancellable.map(|p| p.as_ref()).to_glib_none().0,
616 &mut contents,
617 length.as_mut_ptr(),
618 &mut etag_out,
619 &mut error,
620 );
621 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
622 if error.is_null() {
623 Ok((
624 FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
625 from_glib_full(etag_out),
626 ))
627 } else {
628 Err(from_glib_full(error))
629 }
630 }
631 }
632
633 #[doc(alias = "g_file_load_contents_async")]
651 fn load_contents_async<
652 P: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
653 + 'static,
654 >(
655 &self,
656 cancellable: Option<&impl IsA<Cancellable>>,
657 callback: P,
658 ) {
659 let main_context = glib::MainContext::ref_thread_default();
660 let is_main_context_owner = main_context.is_owner();
661 let has_acquired_main_context = (!is_main_context_owner)
662 .then(|| main_context.acquire().ok())
663 .flatten();
664 assert!(
665 is_main_context_owner || has_acquired_main_context.is_some(),
666 "Async operations only allowed if the thread is owning the MainContext"
667 );
668
669 let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
670 Box::new(glib::thread_guard::ThreadGuard::new(callback));
671 unsafe extern "C" fn load_contents_async_trampoline<
672 P: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
673 + 'static,
674 >(
675 _source_object: *mut glib::gobject_ffi::GObject,
676 res: *mut crate::ffi::GAsyncResult,
677 user_data: glib::ffi::gpointer,
678 ) {
679 unsafe {
680 let mut error = std::ptr::null_mut();
681 let mut contents = std::ptr::null_mut();
682 let mut length = std::mem::MaybeUninit::uninit();
683 let mut etag_out = std::ptr::null_mut();
684 let _ = ffi::g_file_load_contents_finish(
685 _source_object as *mut _,
686 res,
687 &mut contents,
688 length.as_mut_ptr(),
689 &mut etag_out,
690 &mut error,
691 );
692 let result = if error.is_null() {
693 Ok((
694 FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
695 from_glib_full(etag_out),
696 ))
697 } else {
698 Err(from_glib_full(error))
699 };
700 let callback: Box<glib::thread_guard::ThreadGuard<P>> =
701 Box::from_raw(user_data as *mut _);
702 let callback: P = callback.into_inner();
703 callback(result);
704 }
705 }
706 let callback = load_contents_async_trampoline::<P>;
707 unsafe {
708 ffi::g_file_load_contents_async(
709 self.as_ref().to_glib_none().0,
710 cancellable.map(|p| p.as_ref()).to_glib_none().0,
711 Some(callback),
712 Box::into_raw(user_data) as *mut _,
713 );
714 }
715 }
716
717 fn load_contents_future(
718 &self,
719 ) -> impl std::future::Future<
720 Output = Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>,
721 > + Unpin
722 + 'static {
723 crate::GioFuture::new(self, move |obj, cancellable, send| {
724 obj.load_contents_async(Some(cancellable), move |res| {
725 send.resolve(res);
726 });
727 })
728 }
729
730 #[doc(alias = "g_file_load_partial_contents_async")]
751 fn load_partial_contents_async<
752 P: FnMut(&[u8]) -> bool + 'static,
753 Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
754 + 'static,
755 >(
756 &self,
757 cancellable: Option<&impl IsA<Cancellable>>,
758 read_more_callback: P,
759 callback: Q,
760 ) {
761 let main_context = glib::MainContext::ref_thread_default();
762 let is_main_context_owner = main_context.is_owner();
763 let has_acquired_main_context = (!is_main_context_owner)
764 .then(|| main_context.acquire().ok())
765 .flatten();
766 assert!(
767 is_main_context_owner || has_acquired_main_context.is_some(),
768 "Async operations only allowed if the thread is owning the MainContext"
769 );
770
771 let user_data: Box<(
772 glib::thread_guard::ThreadGuard<Q>,
773 RefCell<glib::thread_guard::ThreadGuard<P>>,
774 )> = Box::new((
775 glib::thread_guard::ThreadGuard::new(callback),
776 RefCell::new(glib::thread_guard::ThreadGuard::new(read_more_callback)),
777 ));
778 unsafe extern "C" fn load_partial_contents_async_trampoline<
779 P: FnMut(&[u8]) -> bool + 'static,
780 Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
781 + 'static,
782 >(
783 _source_object: *mut glib::gobject_ffi::GObject,
784 res: *mut crate::ffi::GAsyncResult,
785 user_data: glib::ffi::gpointer,
786 ) {
787 unsafe {
788 let mut contents = ptr::null_mut();
789 let mut length = mem::MaybeUninit::uninit();
790 let mut etag_out = ptr::null_mut();
791 let mut error = ptr::null_mut();
792 ffi::g_file_load_partial_contents_finish(
793 _source_object as *mut _,
794 res,
795 &mut contents,
796 length.as_mut_ptr(),
797 &mut etag_out,
798 &mut error,
799 );
800 let result = if error.is_null() {
801 Ok((
802 FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
803 from_glib_full(etag_out),
804 ))
805 } else {
806 Err(from_glib_full(error))
807 };
808 let callback: Box<(
809 glib::thread_guard::ThreadGuard<Q>,
810 RefCell<glib::thread_guard::ThreadGuard<P>>,
811 )> = Box::from_raw(user_data as *mut _);
812 let callback = callback.0.into_inner();
813 callback(result);
814 }
815 }
816 unsafe extern "C" fn load_partial_contents_async_read_more_trampoline<
817 P: FnMut(&[u8]) -> bool + 'static,
818 Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
819 + 'static,
820 >(
821 file_contents: *const libc::c_char,
822 file_size: i64,
823 user_data: glib::ffi::gpointer,
824 ) -> glib::ffi::gboolean {
825 unsafe {
826 use std::slice;
827
828 let callback: &(
829 glib::thread_guard::ThreadGuard<Q>,
830 RefCell<glib::thread_guard::ThreadGuard<P>>,
831 ) = &*(user_data as *const _);
832 let data = if file_size == 0 {
833 &[]
834 } else {
835 slice::from_raw_parts(file_contents as *const u8, file_size as usize)
836 };
837
838 (*callback.1.borrow_mut().get_mut())(data).into_glib()
839 }
840 }
841
842 let user_data = Box::into_raw(user_data) as *mut _;
843
844 unsafe {
845 ffi::g_file_load_partial_contents_async(
846 self.as_ref().to_glib_none().0,
847 cancellable.map(|p| p.as_ref()).to_glib_none().0,
848 Some(load_partial_contents_async_read_more_trampoline::<P, Q>),
849 Some(load_partial_contents_async_trampoline::<P, Q>),
850 user_data,
851 );
852 }
853 }
854
855 #[doc(alias = "g_file_measure_disk_usage_async")]
872 fn measure_disk_usage_async<P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static>(
873 &self,
874 flags: crate::FileMeasureFlags,
875 io_priority: glib::Priority,
876 cancellable: Option<&impl IsA<Cancellable>>,
877 progress_callback: Option<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
878 callback: P,
879 ) {
880 let main_context = glib::MainContext::ref_thread_default();
881 let is_main_context_owner = main_context.is_owner();
882 let has_acquired_main_context = (!is_main_context_owner)
883 .then(|| main_context.acquire().ok())
884 .flatten();
885 assert!(
886 is_main_context_owner || has_acquired_main_context.is_some(),
887 "Async operations only allowed if the thread is owning the MainContext"
888 );
889
890 let progress_callback_trampoline = if progress_callback.is_some() {
891 Some(measure_disk_usage_async_progress_trampoline::<P> as _)
892 } else {
893 None
894 };
895
896 let user_data: Box<(
897 glib::thread_guard::ThreadGuard<P>,
898 RefCell<
899 Option<
900 glib::thread_guard::ThreadGuard<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
901 >,
902 >,
903 )> = Box::new((
904 glib::thread_guard::ThreadGuard::new(callback),
905 RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
906 ));
907 unsafe extern "C" fn measure_disk_usage_async_trampoline<
908 P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static,
909 >(
910 _source_object: *mut glib::gobject_ffi::GObject,
911 res: *mut crate::ffi::GAsyncResult,
912 user_data: glib::ffi::gpointer,
913 ) {
914 unsafe {
915 let mut disk_usage = mem::MaybeUninit::uninit();
916 let mut num_dirs = mem::MaybeUninit::uninit();
917 let mut num_files = mem::MaybeUninit::uninit();
918 let mut error = ptr::null_mut();
919 ffi::g_file_measure_disk_usage_finish(
920 _source_object as *mut _,
921 res,
922 disk_usage.as_mut_ptr(),
923 num_dirs.as_mut_ptr(),
924 num_files.as_mut_ptr(),
925 &mut error,
926 );
927 let result = if error.is_null() {
928 Ok((
929 disk_usage.assume_init(),
930 num_dirs.assume_init(),
931 num_files.assume_init(),
932 ))
933 } else {
934 Err(from_glib_full(error))
935 };
936 let callback: Box<(
937 glib::thread_guard::ThreadGuard<P>,
938 RefCell<
939 Option<
940 glib::thread_guard::ThreadGuard<
941 Box<dyn FnMut(bool, u64, u64, u64) + 'static>,
942 >,
943 >,
944 >,
945 )> = Box::from_raw(user_data as *mut _);
946 let callback = callback.0.into_inner();
947 callback(result);
948 }
949 }
950 unsafe extern "C" fn measure_disk_usage_async_progress_trampoline<
951 P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static,
952 >(
953 reporting: glib::ffi::gboolean,
954 disk_usage: u64,
955 num_dirs: u64,
956 num_files: u64,
957 user_data: glib::ffi::gpointer,
958 ) {
959 unsafe {
960 let callback: &(
961 glib::thread_guard::ThreadGuard<P>,
962 RefCell<
963 Option<
964 glib::thread_guard::ThreadGuard<
965 Box<dyn FnMut(bool, u64, u64, u64) + 'static>,
966 >,
967 >,
968 >,
969 ) = &*(user_data as *const _);
970 (callback
971 .1
972 .borrow_mut()
973 .as_mut()
974 .expect("can't get callback")
975 .get_mut())(
976 from_glib(reporting), disk_usage, num_dirs, num_files
977 );
978 }
979 }
980
981 let user_data = Box::into_raw(user_data) as *mut _;
982
983 unsafe {
984 ffi::g_file_measure_disk_usage_async(
985 self.as_ref().to_glib_none().0,
986 flags.into_glib(),
987 io_priority.into_glib(),
988 cancellable.map(|p| p.as_ref()).to_glib_none().0,
989 progress_callback_trampoline,
990 user_data,
991 Some(measure_disk_usage_async_trampoline::<P>),
992 user_data,
993 );
994 }
995 }
996
997 fn measure_disk_usage_future(
998 &self,
999 flags: crate::FileMeasureFlags,
1000 io_priority: glib::Priority,
1001 ) -> (
1002 Pin<Box<dyn std::future::Future<Output = Result<(u64, u64, u64), glib::Error>> + 'static>>,
1003 Pin<Box<dyn futures_core::stream::Stream<Item = (bool, u64, u64, u64)> + 'static>>,
1004 ) {
1005 let (sender, receiver) = futures_channel::mpsc::unbounded();
1006
1007 let fut = Box::pin(crate::GioFuture::new(
1008 self,
1009 move |obj, cancellable, send| {
1010 obj.measure_disk_usage_async(
1011 flags,
1012 io_priority,
1013 Some(cancellable),
1014 Some(Box::new(
1015 move |reporting, disk_usage, num_dirs, num_files| {
1016 let _ =
1017 sender.unbounded_send((reporting, disk_usage, num_dirs, num_files));
1018 },
1019 )),
1020 move |res| {
1021 send.resolve(res);
1022 },
1023 );
1024 },
1025 ));
1026
1027 (fut, Box::pin(receiver))
1028 }
1029
1030 #[cfg(feature = "v2_72")]
1053 #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))]
1054 #[doc(alias = "g_file_move_async")]
1055 fn move_async<Q: FnOnce(Result<(), glib::Error>) + 'static>(
1056 &self,
1057 destination: &impl IsA<File>,
1058 flags: crate::FileCopyFlags,
1059 io_priority: glib::Priority,
1060 cancellable: Option<&impl IsA<Cancellable>>,
1061 progress_callback: Option<Box<dyn FnMut(i64, i64)>>,
1062 callback: Q,
1063 ) {
1064 let main_context = glib::MainContext::ref_thread_default();
1065 let is_main_context_owner = main_context.is_owner();
1066 let has_acquired_main_context = (!is_main_context_owner)
1067 .then(|| main_context.acquire().ok())
1068 .flatten();
1069 assert!(
1070 is_main_context_owner || has_acquired_main_context.is_some(),
1071 "Async operations only allowed if the thread is owning the MainContext"
1072 );
1073
1074 let progress_trampoline = if progress_callback.is_some() {
1075 Some(move_async_progress_trampoline::<Q> as _)
1076 } else {
1077 None
1078 };
1079
1080 let user_data: Box<(
1081 glib::thread_guard::ThreadGuard<Q>,
1082 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
1083 )> = Box::new((
1084 glib::thread_guard::ThreadGuard::new(callback),
1085 RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
1086 ));
1087 unsafe extern "C" fn move_async_trampoline<Q: FnOnce(Result<(), glib::Error>) + 'static>(
1088 _source_object: *mut glib::gobject_ffi::GObject,
1089 res: *mut crate::ffi::GAsyncResult,
1090 user_data: glib::ffi::gpointer,
1091 ) {
1092 unsafe {
1093 let mut error = ptr::null_mut();
1094 ffi::g_file_move_finish(_source_object as *mut _, res, &mut error);
1095 let result = if error.is_null() {
1096 Ok(())
1097 } else {
1098 Err(from_glib_full(error))
1099 };
1100 let callback: Box<(
1101 glib::thread_guard::ThreadGuard<Q>,
1102 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
1103 )> = Box::from_raw(user_data as *mut _);
1104 let callback = callback.0.into_inner();
1105 callback(result);
1106 }
1107 }
1108 unsafe extern "C" fn move_async_progress_trampoline<
1109 Q: FnOnce(Result<(), glib::Error>) + 'static,
1110 >(
1111 current_num_bytes: i64,
1112 total_num_bytes: i64,
1113 user_data: glib::ffi::gpointer,
1114 ) {
1115 unsafe {
1116 let callback: &(
1117 glib::thread_guard::ThreadGuard<Q>,
1118 RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
1119 ) = &*(user_data as *const _);
1120 (callback
1121 .1
1122 .borrow_mut()
1123 .as_mut()
1124 .expect("no closure")
1125 .get_mut())(current_num_bytes, total_num_bytes);
1126 }
1127 }
1128
1129 let user_data = Box::into_raw(user_data) as *mut _;
1130
1131 unsafe {
1132 ffi::g_file_move_async(
1133 self.as_ref().to_glib_none().0,
1134 destination.as_ref().to_glib_none().0,
1135 flags.into_glib(),
1136 io_priority.into_glib(),
1137 cancellable.map(|p| p.as_ref()).to_glib_none().0,
1138 progress_trampoline,
1139 user_data,
1140 Some(move_async_trampoline::<Q>),
1141 user_data,
1142 );
1143 }
1144 }
1145
1146 #[cfg(feature = "v2_74")]
1160 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
1161 #[doc(alias = "g_file_make_symbolic_link_async")]
1162 fn make_symbolic_link_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
1163 &self,
1164 symlink_value: impl AsRef<std::path::Path>,
1165 io_priority: glib::Priority,
1166 cancellable: Option<&impl IsA<Cancellable>>,
1167 callback: P,
1168 ) {
1169 let main_context = glib::MainContext::ref_thread_default();
1170 let is_main_context_owner = main_context.is_owner();
1171 let has_acquired_main_context = (!is_main_context_owner)
1172 .then(|| main_context.acquire().ok())
1173 .flatten();
1174 assert!(
1175 is_main_context_owner || has_acquired_main_context.is_some(),
1176 "Async operations only allowed if the thread is owning the MainContext"
1177 );
1178
1179 let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
1180 Box::new(glib::thread_guard::ThreadGuard::new(callback));
1181 unsafe extern "C" fn make_symbolic_link_async_trampoline<
1182 P: FnOnce(Result<(), glib::Error>) + 'static,
1183 >(
1184 _source_object: *mut glib::gobject_ffi::GObject,
1185 res: *mut crate::ffi::GAsyncResult,
1186 user_data: glib::ffi::gpointer,
1187 ) {
1188 unsafe {
1189 let mut error = ptr::null_mut();
1190 let _ = ffi::g_file_make_symbolic_link_finish(
1191 _source_object as *mut _,
1192 res,
1193 &mut error,
1194 );
1195 let result = if error.is_null() {
1196 Ok(())
1197 } else {
1198 Err(from_glib_full(error))
1199 };
1200 let callback: Box<glib::thread_guard::ThreadGuard<P>> =
1201 Box::from_raw(user_data as *mut _);
1202 let callback: P = callback.into_inner();
1203 callback(result);
1204 }
1205 }
1206 let callback = make_symbolic_link_async_trampoline::<P>;
1207 unsafe {
1208 ffi::g_file_make_symbolic_link_async(
1209 self.as_ref().to_glib_none().0,
1210 symlink_value.as_ref().to_glib_none().0,
1211 io_priority.into_glib(),
1212 cancellable.map(|p| p.as_ref()).to_glib_none().0,
1213 Some(callback),
1214 Box::into_raw(user_data) as *mut _,
1215 );
1216 }
1217 }
1218
1219 #[cfg(feature = "v2_74")]
1220 #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
1221 fn make_symbolic_link_future(
1222 &self,
1223 symlink_value: impl AsRef<std::path::Path>,
1224 io_priority: glib::Priority,
1225 ) -> Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
1226 let symlink_value = symlink_value.as_ref().to_owned();
1227 Box::pin(crate::GioFuture::new(
1228 self,
1229 move |obj, cancellable, send| {
1230 obj.make_symbolic_link_async(
1231 &symlink_value,
1232 io_priority,
1233 Some(cancellable),
1234 move |res| {
1235 send.resolve(res);
1236 },
1237 );
1238 },
1239 ))
1240 }
1241
1242 #[cfg(feature = "v2_72")]
1243 #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))]
1244 fn move_future(
1245 &self,
1246 destination: &(impl IsA<File> + Clone + 'static),
1247 flags: crate::FileCopyFlags,
1248 io_priority: glib::Priority,
1249 ) -> (
1250 Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>>,
1251 Pin<Box<dyn futures_core::stream::Stream<Item = (i64, i64)> + 'static>>,
1252 ) {
1253 let destination = destination.clone();
1254
1255 let (sender, receiver) = futures_channel::mpsc::unbounded();
1256
1257 let fut = Box::pin(crate::GioFuture::new(
1258 self,
1259 move |obj, cancellable, send| {
1260 obj.move_async(
1261 &destination,
1262 flags,
1263 io_priority,
1264 Some(cancellable),
1265 Some(Box::new(move |current_num_bytes, total_num_bytes| {
1266 let _ = sender.unbounded_send((current_num_bytes, total_num_bytes));
1267 })),
1268 move |res| {
1269 send.resolve(res);
1270 },
1271 );
1272 },
1273 ));
1274
1275 (fut, Box::pin(receiver))
1276 }
1277
1278 #[doc(alias = "g_file_set_attribute")]
1279 fn set_attribute<'a>(
1280 &self,
1281 attribute: &str,
1282 value: impl Into<FileAttributeValue<'a>>,
1283 flags: FileQueryInfoFlags,
1284 cancellable: Option<&impl IsA<Cancellable>>,
1285 ) -> Result<(), glib::Error> {
1286 unsafe {
1287 let mut error = std::ptr::null_mut();
1288 let value: FileAttributeValue<'a> = value.into();
1289 let is_ok = ffi::g_file_set_attribute(
1290 self.as_ref().to_glib_none().0,
1291 attribute.to_glib_none().0,
1292 value.type_().into_glib(),
1293 value.as_ptr(),
1294 flags.into_glib(),
1295 cancellable.map(|p| p.as_ref()).to_glib_none().0,
1296 &mut error,
1297 );
1298 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
1299 if error.is_null() {
1300 Ok(())
1301 } else {
1302 Err(from_glib_full(error))
1303 }
1304 }
1305 }
1306}
1307
1308impl<O: IsA<File>> FileExtManual for O {}