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