[go: up one dir, main page]

gio/
file.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{cell::RefCell, mem, pin::Pin, ptr};
4
5use glib::{prelude::*, translate::*};
6
7#[cfg(feature = "v2_74")]
8use crate::FileIOStream;
9use crate::{ffi, Cancellable, File, FileCreateFlags, FileEnumerator, FileQueryInfoFlags};
10
11impl File {
12    #[cfg(feature = "v2_74")]
13    #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
14    #[doc(alias = "g_file_new_tmp_async")]
15    pub fn new_tmp_async<P: FnOnce(Result<(File, FileIOStream), glib::Error>) + 'static>(
16        tmpl: Option<impl AsRef<std::path::Path>>,
17        io_priority: glib::Priority,
18        cancellable: Option<&impl IsA<Cancellable>>,
19        callback: P,
20    ) {
21        let main_context = glib::MainContext::ref_thread_default();
22        let is_main_context_owner = main_context.is_owner();
23        let has_acquired_main_context = (!is_main_context_owner)
24            .then(|| main_context.acquire().ok())
25            .flatten();
26        assert!(
27            is_main_context_owner || has_acquired_main_context.is_some(),
28            "Async operations only allowed if the thread is owning the MainContext"
29        );
30
31        let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
32            Box::new(glib::thread_guard::ThreadGuard::new(callback));
33        unsafe extern "C" fn new_tmp_async_trampoline<
34            P: FnOnce(Result<(File, FileIOStream), glib::Error>) + 'static,
35        >(
36            _source_object: *mut glib::gobject_ffi::GObject,
37            res: *mut crate::ffi::GAsyncResult,
38            user_data: glib::ffi::gpointer,
39        ) {
40            let mut error = ptr::null_mut();
41            let mut iostream = ptr::null_mut();
42            let ret = ffi::g_file_new_tmp_finish(res, &mut iostream, &mut error);
43            let result = if error.is_null() {
44                Ok((from_glib_full(ret), from_glib_full(iostream)))
45            } else {
46                Err(from_glib_full(error))
47            };
48            let callback: Box<glib::thread_guard::ThreadGuard<P>> =
49                Box::from_raw(user_data as *mut _);
50            let callback: P = callback.into_inner();
51            callback(result);
52        }
53        let callback = new_tmp_async_trampoline::<P>;
54        unsafe {
55            ffi::g_file_new_tmp_async(
56                tmpl.as_ref().map(|p| p.as_ref()).to_glib_none().0,
57                io_priority.into_glib(),
58                cancellable.map(|p| p.as_ref()).to_glib_none().0,
59                Some(callback),
60                Box::into_raw(user_data) as *mut _,
61            );
62        }
63    }
64
65    #[cfg(feature = "v2_74")]
66    #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
67    pub fn new_tmp_future(
68        tmpl: Option<impl AsRef<std::path::Path>>,
69        io_priority: glib::Priority,
70    ) -> Pin<
71        Box<dyn std::future::Future<Output = Result<(File, FileIOStream), glib::Error>> + 'static>,
72    > {
73        let tmpl = tmpl.map(|tmpl| tmpl.as_ref().to_owned());
74        Box::pin(crate::GioFuture::new(
75            &(),
76            move |_obj, cancellable, send| {
77                Self::new_tmp_async(
78                    tmpl.as_ref()
79                        .map(<std::path::PathBuf as std::borrow::Borrow<std::path::Path>>::borrow),
80                    io_priority,
81                    Some(cancellable),
82                    move |res| {
83                        send.resolve(res);
84                    },
85                );
86            },
87        ))
88    }
89
90    #[cfg(feature = "v2_74")]
91    #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
92    #[doc(alias = "g_file_new_tmp_dir_async")]
93    pub fn new_tmp_dir_async<P: FnOnce(Result<File, glib::Error>) + 'static>(
94        tmpl: Option<impl AsRef<std::path::Path>>,
95        io_priority: glib::Priority,
96        cancellable: Option<&impl IsA<Cancellable>>,
97        callback: P,
98    ) {
99        let main_context = glib::MainContext::ref_thread_default();
100        let is_main_context_owner = main_context.is_owner();
101        let has_acquired_main_context = (!is_main_context_owner)
102            .then(|| main_context.acquire().ok())
103            .flatten();
104        assert!(
105            is_main_context_owner || has_acquired_main_context.is_some(),
106            "Async operations only allowed if the thread is owning the MainContext"
107        );
108
109        let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
110            Box::new(glib::thread_guard::ThreadGuard::new(callback));
111        unsafe extern "C" fn new_tmp_dir_async_trampoline<
112            P: FnOnce(Result<File, glib::Error>) + 'static,
113        >(
114            _source_object: *mut glib::gobject_ffi::GObject,
115            res: *mut crate::ffi::GAsyncResult,
116            user_data: glib::ffi::gpointer,
117        ) {
118            let mut error = ptr::null_mut();
119            let ret = ffi::g_file_new_tmp_dir_finish(res, &mut error);
120            let result = if error.is_null() {
121                Ok(from_glib_full(ret))
122            } else {
123                Err(from_glib_full(error))
124            };
125            let callback: Box<glib::thread_guard::ThreadGuard<P>> =
126                Box::from_raw(user_data as *mut _);
127            let callback: P = callback.into_inner();
128            callback(result);
129        }
130        let callback = new_tmp_dir_async_trampoline::<P>;
131        unsafe {
132            ffi::g_file_new_tmp_dir_async(
133                tmpl.as_ref().map(|p| p.as_ref()).to_glib_none().0,
134                io_priority.into_glib(),
135                cancellable.map(|p| p.as_ref()).to_glib_none().0,
136                Some(callback),
137                Box::into_raw(user_data) as *mut _,
138            );
139        }
140    }
141
142    #[cfg(feature = "v2_74")]
143    #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
144    pub fn new_tmp_dir_future(
145        tmpl: Option<impl AsRef<std::path::Path>>,
146        io_priority: glib::Priority,
147    ) -> Pin<Box<dyn std::future::Future<Output = Result<File, glib::Error>> + 'static>> {
148        let tmpl = tmpl.map(|tmpl| tmpl.as_ref().to_owned());
149        Box::pin(crate::GioFuture::new(
150            &(),
151            move |_obj, cancellable, send| {
152                Self::new_tmp_dir_async(
153                    tmpl.as_ref()
154                        .map(<std::path::PathBuf as std::borrow::Borrow<std::path::Path>>::borrow),
155                    io_priority,
156                    Some(cancellable),
157                    move |res| {
158                        send.resolve(res);
159                    },
160                );
161            },
162        ))
163    }
164}
165
166mod sealed {
167    pub trait Sealed {}
168    impl<T: super::IsA<super::File>> Sealed for T {}
169}
170
171pub trait FileExtManual: sealed::Sealed + IsA<File> + Sized {
172    #[doc(alias = "g_file_replace_contents_async")]
173    fn replace_contents_async<
174        B: AsRef<[u8]> + Send + 'static,
175        R: FnOnce(Result<(B, glib::GString), (B, glib::Error)>) + 'static,
176        C: IsA<Cancellable>,
177    >(
178        &self,
179        contents: B,
180        etag: Option<&str>,
181        make_backup: bool,
182        flags: FileCreateFlags,
183        cancellable: Option<&C>,
184        callback: R,
185    ) {
186        let main_context = glib::MainContext::ref_thread_default();
187        let is_main_context_owner = main_context.is_owner();
188        let has_acquired_main_context = (!is_main_context_owner)
189            .then(|| main_context.acquire().ok())
190            .flatten();
191        assert!(
192            is_main_context_owner || has_acquired_main_context.is_some(),
193            "Async operations only allowed if the thread is owning the MainContext"
194        );
195
196        let etag = etag.to_glib_none();
197        let cancellable = cancellable.map(|c| c.as_ref());
198        let gcancellable = cancellable.to_glib_none();
199        let user_data: Box<(glib::thread_guard::ThreadGuard<R>, B)> =
200            Box::new((glib::thread_guard::ThreadGuard::new(callback), contents));
201        // Need to do this after boxing as the contents pointer might change by moving into the box
202        let (count, contents_ptr) = {
203            let contents = &user_data.1;
204            let slice = contents.as_ref();
205            (slice.len(), slice.as_ptr())
206        };
207        unsafe extern "C" fn replace_contents_async_trampoline<
208            B: AsRef<[u8]> + Send + 'static,
209            R: FnOnce(Result<(B, glib::GString), (B, glib::Error)>) + 'static,
210        >(
211            _source_object: *mut glib::gobject_ffi::GObject,
212            res: *mut ffi::GAsyncResult,
213            user_data: glib::ffi::gpointer,
214        ) {
215            let user_data: Box<(glib::thread_guard::ThreadGuard<R>, B)> =
216                Box::from_raw(user_data as *mut _);
217            let (callback, contents) = *user_data;
218            let callback = callback.into_inner();
219
220            let mut error = ptr::null_mut();
221            let mut new_etag = ptr::null_mut();
222            let _ = ffi::g_file_replace_contents_finish(
223                _source_object as *mut _,
224                res,
225                &mut new_etag,
226                &mut error,
227            );
228            let result = if error.is_null() {
229                Ok((contents, from_glib_full(new_etag)))
230            } else {
231                Err((contents, from_glib_full(error)))
232            };
233            callback(result);
234        }
235        let callback = replace_contents_async_trampoline::<B, R>;
236        unsafe {
237            ffi::g_file_replace_contents_async(
238                self.as_ref().to_glib_none().0,
239                mut_override(contents_ptr),
240                count,
241                etag.0,
242                make_backup.into_glib(),
243                flags.into_glib(),
244                gcancellable.0,
245                Some(callback),
246                Box::into_raw(user_data) as *mut _,
247            );
248        }
249    }
250
251    fn replace_contents_future<B: AsRef<[u8]> + Send + 'static>(
252        &self,
253        contents: B,
254        etag: Option<&str>,
255        make_backup: bool,
256        flags: FileCreateFlags,
257    ) -> Pin<
258        Box<
259            dyn std::future::Future<Output = Result<(B, glib::GString), (B, glib::Error)>>
260                + 'static,
261        >,
262    > {
263        let etag = etag.map(glib::GString::from);
264        Box::pin(crate::GioFuture::new(
265            self,
266            move |obj, cancellable, send| {
267                obj.replace_contents_async(
268                    contents,
269                    etag.as_ref().map(|s| s.as_str()),
270                    make_backup,
271                    flags,
272                    Some(cancellable),
273                    move |res| {
274                        send.resolve(res);
275                    },
276                );
277            },
278        ))
279    }
280
281    #[doc(alias = "g_file_enumerate_children_async")]
282    fn enumerate_children_async<
283        P: IsA<Cancellable>,
284        Q: FnOnce(Result<FileEnumerator, glib::Error>) + 'static,
285    >(
286        &self,
287        attributes: &str,
288        flags: FileQueryInfoFlags,
289        io_priority: glib::Priority,
290        cancellable: Option<&P>,
291        callback: Q,
292    ) {
293        let main_context = glib::MainContext::ref_thread_default();
294        let is_main_context_owner = main_context.is_owner();
295        let has_acquired_main_context = (!is_main_context_owner)
296            .then(|| main_context.acquire().ok())
297            .flatten();
298        assert!(
299            is_main_context_owner || has_acquired_main_context.is_some(),
300            "Async operations only allowed if the thread is owning the MainContext"
301        );
302
303        let user_data: Box<glib::thread_guard::ThreadGuard<Q>> =
304            Box::new(glib::thread_guard::ThreadGuard::new(callback));
305        unsafe extern "C" fn create_async_trampoline<
306            Q: FnOnce(Result<FileEnumerator, glib::Error>) + 'static,
307        >(
308            _source_object: *mut glib::gobject_ffi::GObject,
309            res: *mut crate::ffi::GAsyncResult,
310            user_data: glib::ffi::gpointer,
311        ) {
312            let mut error = ptr::null_mut();
313            let ret =
314                ffi::g_file_enumerate_children_finish(_source_object as *mut _, res, &mut error);
315            let result = if error.is_null() {
316                Ok(from_glib_full(ret))
317            } else {
318                Err(from_glib_full(error))
319            };
320            let callback: Box<glib::thread_guard::ThreadGuard<Q>> =
321                Box::from_raw(user_data as *mut _);
322            let callback = callback.into_inner();
323            callback(result);
324        }
325        let callback = create_async_trampoline::<Q>;
326        unsafe {
327            ffi::g_file_enumerate_children_async(
328                self.as_ref().to_glib_none().0,
329                attributes.to_glib_none().0,
330                flags.into_glib(),
331                io_priority.into_glib(),
332                cancellable.map(|p| p.as_ref()).to_glib_none().0,
333                Some(callback),
334                Box::into_raw(user_data) as *mut _,
335            );
336        }
337    }
338
339    fn enumerate_children_future(
340        &self,
341        attributes: &str,
342        flags: FileQueryInfoFlags,
343        io_priority: glib::Priority,
344    ) -> Pin<Box<dyn std::future::Future<Output = Result<FileEnumerator, glib::Error>> + 'static>>
345    {
346        let attributes = attributes.to_owned();
347        Box::pin(crate::GioFuture::new(
348            self,
349            move |obj, cancellable, send| {
350                obj.enumerate_children_async(
351                    &attributes,
352                    flags,
353                    io_priority,
354                    Some(cancellable),
355                    move |res| {
356                        send.resolve(res);
357                    },
358                );
359            },
360        ))
361    }
362
363    #[doc(alias = "g_file_copy_async")]
364    fn copy_async<Q: FnOnce(Result<(), glib::Error>) + 'static>(
365        &self,
366        destination: &impl IsA<File>,
367        flags: crate::FileCopyFlags,
368        io_priority: glib::Priority,
369        cancellable: Option<&impl IsA<Cancellable>>,
370        progress_callback: Option<Box<dyn FnMut(i64, i64)>>,
371        callback: Q,
372    ) {
373        let main_context = glib::MainContext::ref_thread_default();
374        let is_main_context_owner = main_context.is_owner();
375        let has_acquired_main_context = (!is_main_context_owner)
376            .then(|| main_context.acquire().ok())
377            .flatten();
378        assert!(
379            is_main_context_owner || has_acquired_main_context.is_some(),
380            "Async operations only allowed if the thread is owning the MainContext"
381        );
382
383        let progress_trampoline = if progress_callback.is_some() {
384            Some(copy_async_progress_trampoline::<Q> as _)
385        } else {
386            None
387        };
388
389        let user_data: Box<(
390            glib::thread_guard::ThreadGuard<Q>,
391            RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
392        )> = Box::new((
393            glib::thread_guard::ThreadGuard::new(callback),
394            RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
395        ));
396        unsafe extern "C" fn copy_async_trampoline<Q: FnOnce(Result<(), glib::Error>) + 'static>(
397            _source_object: *mut glib::gobject_ffi::GObject,
398            res: *mut crate::ffi::GAsyncResult,
399            user_data: glib::ffi::gpointer,
400        ) {
401            let mut error = ptr::null_mut();
402            ffi::g_file_copy_finish(_source_object as *mut _, res, &mut error);
403            let result = if error.is_null() {
404                Ok(())
405            } else {
406                Err(from_glib_full(error))
407            };
408            let callback: Box<(
409                glib::thread_guard::ThreadGuard<Q>,
410                RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
411            )> = Box::from_raw(user_data as *mut _);
412            let callback = callback.0.into_inner();
413            callback(result);
414        }
415        unsafe extern "C" fn copy_async_progress_trampoline<
416            Q: FnOnce(Result<(), glib::Error>) + 'static,
417        >(
418            current_num_bytes: i64,
419            total_num_bytes: i64,
420            user_data: glib::ffi::gpointer,
421        ) {
422            let callback: &(
423                glib::thread_guard::ThreadGuard<Q>,
424                RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
425            ) = &*(user_data as *const _);
426            (callback
427                .1
428                .borrow_mut()
429                .as_mut()
430                .expect("no closure")
431                .get_mut())(current_num_bytes, total_num_bytes);
432        }
433
434        let user_data = Box::into_raw(user_data) as *mut _;
435
436        unsafe {
437            ffi::g_file_copy_async(
438                self.as_ref().to_glib_none().0,
439                destination.as_ref().to_glib_none().0,
440                flags.into_glib(),
441                io_priority.into_glib(),
442                cancellable.map(|p| p.as_ref()).to_glib_none().0,
443                progress_trampoline,
444                user_data,
445                Some(copy_async_trampoline::<Q>),
446                user_data,
447            );
448        }
449    }
450
451    fn copy_future(
452        &self,
453        destination: &(impl IsA<File> + Clone + 'static),
454        flags: crate::FileCopyFlags,
455        io_priority: glib::Priority,
456    ) -> (
457        Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>>,
458        Pin<Box<dyn futures_core::stream::Stream<Item = (i64, i64)> + 'static>>,
459    ) {
460        let destination = destination.clone();
461
462        let (sender, receiver) = futures_channel::mpsc::unbounded();
463
464        let fut = Box::pin(crate::GioFuture::new(
465            self,
466            move |obj, cancellable, send| {
467                obj.copy_async(
468                    &destination,
469                    flags,
470                    io_priority,
471                    Some(cancellable),
472                    Some(Box::new(move |current_num_bytes, total_num_bytes| {
473                        let _ = sender.unbounded_send((current_num_bytes, total_num_bytes));
474                    })),
475                    move |res| {
476                        send.resolve(res);
477                    },
478                );
479            },
480        ));
481
482        (fut, Box::pin(receiver))
483    }
484
485    #[doc(alias = "g_file_load_contents")]
486    fn load_contents(
487        &self,
488        cancellable: Option<&impl IsA<Cancellable>>,
489    ) -> Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error> {
490        unsafe {
491            let mut contents = std::ptr::null_mut();
492            let mut length = std::mem::MaybeUninit::uninit();
493            let mut etag_out = std::ptr::null_mut();
494            let mut error = std::ptr::null_mut();
495            let is_ok = ffi::g_file_load_contents(
496                self.as_ref().to_glib_none().0,
497                cancellable.map(|p| p.as_ref()).to_glib_none().0,
498                &mut contents,
499                length.as_mut_ptr(),
500                &mut etag_out,
501                &mut error,
502            );
503            debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
504            if error.is_null() {
505                Ok((
506                    FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
507                    from_glib_full(etag_out),
508                ))
509            } else {
510                Err(from_glib_full(error))
511            }
512        }
513    }
514
515    #[doc(alias = "g_file_load_contents_async")]
516    fn load_contents_async<
517        P: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
518            + 'static,
519    >(
520        &self,
521        cancellable: Option<&impl IsA<Cancellable>>,
522        callback: P,
523    ) {
524        let main_context = glib::MainContext::ref_thread_default();
525        let is_main_context_owner = main_context.is_owner();
526        let has_acquired_main_context = (!is_main_context_owner)
527            .then(|| main_context.acquire().ok())
528            .flatten();
529        assert!(
530            is_main_context_owner || has_acquired_main_context.is_some(),
531            "Async operations only allowed if the thread is owning the MainContext"
532        );
533
534        let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
535            Box::new(glib::thread_guard::ThreadGuard::new(callback));
536        unsafe extern "C" fn load_contents_async_trampoline<
537            P: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
538                + 'static,
539        >(
540            _source_object: *mut glib::gobject_ffi::GObject,
541            res: *mut crate::ffi::GAsyncResult,
542            user_data: glib::ffi::gpointer,
543        ) {
544            let mut error = std::ptr::null_mut();
545            let mut contents = std::ptr::null_mut();
546            let mut length = std::mem::MaybeUninit::uninit();
547            let mut etag_out = std::ptr::null_mut();
548            let _ = ffi::g_file_load_contents_finish(
549                _source_object as *mut _,
550                res,
551                &mut contents,
552                length.as_mut_ptr(),
553                &mut etag_out,
554                &mut error,
555            );
556            let result = if error.is_null() {
557                Ok((
558                    FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
559                    from_glib_full(etag_out),
560                ))
561            } else {
562                Err(from_glib_full(error))
563            };
564            let callback: Box<glib::thread_guard::ThreadGuard<P>> =
565                Box::from_raw(user_data as *mut _);
566            let callback: P = callback.into_inner();
567            callback(result);
568        }
569        let callback = load_contents_async_trampoline::<P>;
570        unsafe {
571            ffi::g_file_load_contents_async(
572                self.as_ref().to_glib_none().0,
573                cancellable.map(|p| p.as_ref()).to_glib_none().0,
574                Some(callback),
575                Box::into_raw(user_data) as *mut _,
576            );
577        }
578    }
579
580    fn load_contents_future(
581        &self,
582    ) -> Pin<
583        Box<
584            dyn std::future::Future<
585                    Output = Result<
586                        (glib::collections::Slice<u8>, Option<glib::GString>),
587                        glib::Error,
588                    >,
589                > + 'static,
590        >,
591    > {
592        Box::pin(crate::GioFuture::new(
593            self,
594            move |obj, cancellable, send| {
595                obj.load_contents_async(Some(cancellable), move |res| {
596                    send.resolve(res);
597                });
598            },
599        ))
600    }
601
602    #[doc(alias = "g_file_load_partial_contents_async")]
603    fn load_partial_contents_async<
604        P: FnMut(&[u8]) -> bool + 'static,
605        Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
606            + 'static,
607    >(
608        &self,
609        cancellable: Option<&impl IsA<Cancellable>>,
610        read_more_callback: P,
611        callback: Q,
612    ) {
613        let main_context = glib::MainContext::ref_thread_default();
614        let is_main_context_owner = main_context.is_owner();
615        let has_acquired_main_context = (!is_main_context_owner)
616            .then(|| main_context.acquire().ok())
617            .flatten();
618        assert!(
619            is_main_context_owner || has_acquired_main_context.is_some(),
620            "Async operations only allowed if the thread is owning the MainContext"
621        );
622
623        let user_data: Box<(
624            glib::thread_guard::ThreadGuard<Q>,
625            RefCell<glib::thread_guard::ThreadGuard<P>>,
626        )> = Box::new((
627            glib::thread_guard::ThreadGuard::new(callback),
628            RefCell::new(glib::thread_guard::ThreadGuard::new(read_more_callback)),
629        ));
630        unsafe extern "C" fn load_partial_contents_async_trampoline<
631            P: FnMut(&[u8]) -> bool + 'static,
632            Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
633                + 'static,
634        >(
635            _source_object: *mut glib::gobject_ffi::GObject,
636            res: *mut crate::ffi::GAsyncResult,
637            user_data: glib::ffi::gpointer,
638        ) {
639            let mut contents = ptr::null_mut();
640            let mut length = mem::MaybeUninit::uninit();
641            let mut etag_out = ptr::null_mut();
642            let mut error = ptr::null_mut();
643            ffi::g_file_load_partial_contents_finish(
644                _source_object as *mut _,
645                res,
646                &mut contents,
647                length.as_mut_ptr(),
648                &mut etag_out,
649                &mut error,
650            );
651            let result = if error.is_null() {
652                Ok((
653                    FromGlibContainer::from_glib_full_num(contents, length.assume_init() as _),
654                    from_glib_full(etag_out),
655                ))
656            } else {
657                Err(from_glib_full(error))
658            };
659            let callback: Box<(
660                glib::thread_guard::ThreadGuard<Q>,
661                RefCell<glib::thread_guard::ThreadGuard<P>>,
662            )> = Box::from_raw(user_data as *mut _);
663            let callback = callback.0.into_inner();
664            callback(result);
665        }
666        unsafe extern "C" fn load_partial_contents_async_read_more_trampoline<
667            P: FnMut(&[u8]) -> bool + 'static,
668            Q: FnOnce(Result<(glib::collections::Slice<u8>, Option<glib::GString>), glib::Error>)
669                + 'static,
670        >(
671            file_contents: *const libc::c_char,
672            file_size: i64,
673            user_data: glib::ffi::gpointer,
674        ) -> glib::ffi::gboolean {
675            use std::slice;
676
677            let callback: &(
678                glib::thread_guard::ThreadGuard<Q>,
679                RefCell<glib::thread_guard::ThreadGuard<P>>,
680            ) = &*(user_data as *const _);
681            let data = if file_size == 0 {
682                &[]
683            } else {
684                slice::from_raw_parts(file_contents as *const u8, file_size as usize)
685            };
686
687            (*callback.1.borrow_mut().get_mut())(data).into_glib()
688        }
689
690        let user_data = Box::into_raw(user_data) as *mut _;
691
692        unsafe {
693            ffi::g_file_load_partial_contents_async(
694                self.as_ref().to_glib_none().0,
695                cancellable.map(|p| p.as_ref()).to_glib_none().0,
696                Some(load_partial_contents_async_read_more_trampoline::<P, Q>),
697                Some(load_partial_contents_async_trampoline::<P, Q>),
698                user_data,
699            );
700        }
701    }
702
703    #[doc(alias = "g_file_measure_disk_usage")]
704    fn measure_disk_usage(
705        &self,
706        flags: crate::FileMeasureFlags,
707        cancellable: Option<&impl IsA<Cancellable>>,
708        progress_callback: Option<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
709    ) -> Result<(u64, u64, u64), glib::Error> {
710        let progress_callback_data: Box<
711            Option<RefCell<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>>,
712        > = Box::new(progress_callback.map(RefCell::new));
713        unsafe extern "C" fn progress_callback_func(
714            reporting: glib::ffi::gboolean,
715            current_size: u64,
716            num_dirs: u64,
717            num_files: u64,
718            user_data: glib::ffi::gpointer,
719        ) {
720            let reporting = from_glib(reporting);
721            let callback: &Option<RefCell<Box<dyn Fn(bool, u64, u64, u64) + 'static>>> =
722                &*(user_data as *mut _);
723            if let Some(ref callback) = *callback {
724                (*callback.borrow_mut())(reporting, current_size, num_dirs, num_files)
725            } else {
726                panic!("cannot get closure...")
727            };
728        }
729        let progress_callback = if progress_callback_data.is_some() {
730            Some(progress_callback_func as _)
731        } else {
732            None
733        };
734        let super_callback0: Box<Option<RefCell<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>>> =
735            progress_callback_data;
736        unsafe {
737            let mut disk_usage = mem::MaybeUninit::uninit();
738            let mut num_dirs = mem::MaybeUninit::uninit();
739            let mut num_files = mem::MaybeUninit::uninit();
740            let mut error = ptr::null_mut();
741            let _ = ffi::g_file_measure_disk_usage(
742                self.as_ref().to_glib_none().0,
743                flags.into_glib(),
744                cancellable.map(|p| p.as_ref()).to_glib_none().0,
745                progress_callback,
746                Box::into_raw(super_callback0) as *mut _,
747                disk_usage.as_mut_ptr(),
748                num_dirs.as_mut_ptr(),
749                num_files.as_mut_ptr(),
750                &mut error,
751            );
752            let disk_usage = disk_usage.assume_init();
753            let num_dirs = num_dirs.assume_init();
754            let num_files = num_files.assume_init();
755            if error.is_null() {
756                Ok((disk_usage, num_dirs, num_files))
757            } else {
758                Err(from_glib_full(error))
759            }
760        }
761    }
762
763    #[doc(alias = "g_file_measure_disk_usage_async")]
764    fn measure_disk_usage_async<P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static>(
765        &self,
766        flags: crate::FileMeasureFlags,
767        io_priority: glib::Priority,
768        cancellable: Option<&impl IsA<Cancellable>>,
769        progress_callback: Option<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
770        callback: P,
771    ) {
772        let main_context = glib::MainContext::ref_thread_default();
773        let is_main_context_owner = main_context.is_owner();
774        let has_acquired_main_context = (!is_main_context_owner)
775            .then(|| main_context.acquire().ok())
776            .flatten();
777        assert!(
778            is_main_context_owner || has_acquired_main_context.is_some(),
779            "Async operations only allowed if the thread is owning the MainContext"
780        );
781
782        let progress_callback_trampoline = if progress_callback.is_some() {
783            Some(measure_disk_usage_async_progress_trampoline::<P> as _)
784        } else {
785            None
786        };
787
788        let user_data: Box<(
789            glib::thread_guard::ThreadGuard<P>,
790            RefCell<
791                Option<
792                    glib::thread_guard::ThreadGuard<Box<dyn FnMut(bool, u64, u64, u64) + 'static>>,
793                >,
794            >,
795        )> = Box::new((
796            glib::thread_guard::ThreadGuard::new(callback),
797            RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
798        ));
799        unsafe extern "C" fn measure_disk_usage_async_trampoline<
800            P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static,
801        >(
802            _source_object: *mut glib::gobject_ffi::GObject,
803            res: *mut crate::ffi::GAsyncResult,
804            user_data: glib::ffi::gpointer,
805        ) {
806            let mut disk_usage = mem::MaybeUninit::uninit();
807            let mut num_dirs = mem::MaybeUninit::uninit();
808            let mut num_files = mem::MaybeUninit::uninit();
809            let mut error = ptr::null_mut();
810            ffi::g_file_measure_disk_usage_finish(
811                _source_object as *mut _,
812                res,
813                disk_usage.as_mut_ptr(),
814                num_dirs.as_mut_ptr(),
815                num_files.as_mut_ptr(),
816                &mut error,
817            );
818            let result = if error.is_null() {
819                Ok((
820                    disk_usage.assume_init(),
821                    num_dirs.assume_init(),
822                    num_files.assume_init(),
823                ))
824            } else {
825                Err(from_glib_full(error))
826            };
827            let callback: Box<(
828                glib::thread_guard::ThreadGuard<P>,
829                RefCell<
830                    Option<
831                        glib::thread_guard::ThreadGuard<
832                            Box<dyn FnMut(bool, u64, u64, u64) + 'static>,
833                        >,
834                    >,
835                >,
836            )> = Box::from_raw(user_data as *mut _);
837            let callback = callback.0.into_inner();
838            callback(result);
839        }
840        unsafe extern "C" fn measure_disk_usage_async_progress_trampoline<
841            P: FnOnce(Result<(u64, u64, u64), glib::Error>) + 'static,
842        >(
843            reporting: glib::ffi::gboolean,
844            disk_usage: u64,
845            num_dirs: u64,
846            num_files: u64,
847            user_data: glib::ffi::gpointer,
848        ) {
849            let callback: &(
850                glib::thread_guard::ThreadGuard<P>,
851                RefCell<
852                    Option<
853                        glib::thread_guard::ThreadGuard<
854                            Box<dyn FnMut(bool, u64, u64, u64) + 'static>,
855                        >,
856                    >,
857                >,
858            ) = &*(user_data as *const _);
859            (callback
860                .1
861                .borrow_mut()
862                .as_mut()
863                .expect("can't get callback")
864                .get_mut())(from_glib(reporting), disk_usage, num_dirs, num_files);
865        }
866
867        let user_data = Box::into_raw(user_data) as *mut _;
868
869        unsafe {
870            ffi::g_file_measure_disk_usage_async(
871                self.as_ref().to_glib_none().0,
872                flags.into_glib(),
873                io_priority.into_glib(),
874                cancellable.map(|p| p.as_ref()).to_glib_none().0,
875                progress_callback_trampoline,
876                user_data,
877                Some(measure_disk_usage_async_trampoline::<P>),
878                user_data,
879            );
880        }
881    }
882
883    fn measure_disk_usage_future(
884        &self,
885        flags: crate::FileMeasureFlags,
886        io_priority: glib::Priority,
887    ) -> (
888        Pin<Box<dyn std::future::Future<Output = Result<(u64, u64, u64), glib::Error>> + 'static>>,
889        Pin<Box<dyn futures_core::stream::Stream<Item = (bool, u64, u64, u64)> + 'static>>,
890    ) {
891        let (sender, receiver) = futures_channel::mpsc::unbounded();
892
893        let fut = Box::pin(crate::GioFuture::new(
894            self,
895            move |obj, cancellable, send| {
896                obj.measure_disk_usage_async(
897                    flags,
898                    io_priority,
899                    Some(cancellable),
900                    Some(Box::new(
901                        move |reporting, disk_usage, num_dirs, num_files| {
902                            let _ =
903                                sender.unbounded_send((reporting, disk_usage, num_dirs, num_files));
904                        },
905                    )),
906                    move |res| {
907                        send.resolve(res);
908                    },
909                );
910            },
911        ));
912
913        (fut, Box::pin(receiver))
914    }
915
916    #[cfg(feature = "v2_72")]
917    #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))]
918    #[doc(alias = "g_file_move_async")]
919    fn move_async<Q: FnOnce(Result<(), glib::Error>) + 'static>(
920        &self,
921        destination: &impl IsA<File>,
922        flags: crate::FileCopyFlags,
923        io_priority: glib::Priority,
924        cancellable: Option<&impl IsA<Cancellable>>,
925        progress_callback: Option<Box<dyn FnMut(i64, i64)>>,
926        callback: Q,
927    ) {
928        let main_context = glib::MainContext::ref_thread_default();
929        let is_main_context_owner = main_context.is_owner();
930        let has_acquired_main_context = (!is_main_context_owner)
931            .then(|| main_context.acquire().ok())
932            .flatten();
933        assert!(
934            is_main_context_owner || has_acquired_main_context.is_some(),
935            "Async operations only allowed if the thread is owning the MainContext"
936        );
937
938        let progress_trampoline = if progress_callback.is_some() {
939            Some(move_async_progress_trampoline::<Q> as _)
940        } else {
941            None
942        };
943
944        let user_data: Box<(
945            glib::thread_guard::ThreadGuard<Q>,
946            RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
947        )> = Box::new((
948            glib::thread_guard::ThreadGuard::new(callback),
949            RefCell::new(progress_callback.map(glib::thread_guard::ThreadGuard::new)),
950        ));
951        unsafe extern "C" fn move_async_trampoline<Q: FnOnce(Result<(), glib::Error>) + 'static>(
952            _source_object: *mut glib::gobject_ffi::GObject,
953            res: *mut crate::ffi::GAsyncResult,
954            user_data: glib::ffi::gpointer,
955        ) {
956            let mut error = ptr::null_mut();
957            ffi::g_file_move_finish(_source_object as *mut _, res, &mut error);
958            let result = if error.is_null() {
959                Ok(())
960            } else {
961                Err(from_glib_full(error))
962            };
963            let callback: Box<(
964                glib::thread_guard::ThreadGuard<Q>,
965                RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
966            )> = Box::from_raw(user_data as *mut _);
967            let callback = callback.0.into_inner();
968            callback(result);
969        }
970        unsafe extern "C" fn move_async_progress_trampoline<
971            Q: FnOnce(Result<(), glib::Error>) + 'static,
972        >(
973            current_num_bytes: i64,
974            total_num_bytes: i64,
975            user_data: glib::ffi::gpointer,
976        ) {
977            let callback: &(
978                glib::thread_guard::ThreadGuard<Q>,
979                RefCell<Option<glib::thread_guard::ThreadGuard<Box<dyn FnMut(i64, i64)>>>>,
980            ) = &*(user_data as *const _);
981            (callback
982                .1
983                .borrow_mut()
984                .as_mut()
985                .expect("no closure")
986                .get_mut())(current_num_bytes, total_num_bytes);
987        }
988
989        let user_data = Box::into_raw(user_data) as *mut _;
990
991        unsafe {
992            ffi::g_file_move_async(
993                self.as_ref().to_glib_none().0,
994                destination.as_ref().to_glib_none().0,
995                flags.into_glib(),
996                io_priority.into_glib(),
997                cancellable.map(|p| p.as_ref()).to_glib_none().0,
998                progress_trampoline,
999                user_data,
1000                Some(move_async_trampoline::<Q>),
1001                user_data,
1002            );
1003        }
1004    }
1005
1006    #[cfg(feature = "v2_74")]
1007    #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
1008    #[doc(alias = "g_file_make_symbolic_link_async")]
1009    fn make_symbolic_link_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
1010        &self,
1011        symlink_value: impl AsRef<std::path::Path>,
1012        io_priority: glib::Priority,
1013        cancellable: Option<&impl IsA<Cancellable>>,
1014        callback: P,
1015    ) {
1016        let main_context = glib::MainContext::ref_thread_default();
1017        let is_main_context_owner = main_context.is_owner();
1018        let has_acquired_main_context = (!is_main_context_owner)
1019            .then(|| main_context.acquire().ok())
1020            .flatten();
1021        assert!(
1022            is_main_context_owner || has_acquired_main_context.is_some(),
1023            "Async operations only allowed if the thread is owning the MainContext"
1024        );
1025
1026        let user_data: Box<glib::thread_guard::ThreadGuard<P>> =
1027            Box::new(glib::thread_guard::ThreadGuard::new(callback));
1028        unsafe extern "C" fn make_symbolic_link_async_trampoline<
1029            P: FnOnce(Result<(), glib::Error>) + 'static,
1030        >(
1031            _source_object: *mut glib::gobject_ffi::GObject,
1032            res: *mut crate::ffi::GAsyncResult,
1033            user_data: glib::ffi::gpointer,
1034        ) {
1035            let mut error = ptr::null_mut();
1036            let _ =
1037                ffi::g_file_make_symbolic_link_finish(_source_object as *mut _, res, &mut error);
1038            let result = if error.is_null() {
1039                Ok(())
1040            } else {
1041                Err(from_glib_full(error))
1042            };
1043            let callback: Box<glib::thread_guard::ThreadGuard<P>> =
1044                Box::from_raw(user_data as *mut _);
1045            let callback: P = callback.into_inner();
1046            callback(result);
1047        }
1048        let callback = make_symbolic_link_async_trampoline::<P>;
1049        unsafe {
1050            ffi::g_file_make_symbolic_link_async(
1051                self.as_ref().to_glib_none().0,
1052                symlink_value.as_ref().to_glib_none().0,
1053                io_priority.into_glib(),
1054                cancellable.map(|p| p.as_ref()).to_glib_none().0,
1055                Some(callback),
1056                Box::into_raw(user_data) as *mut _,
1057            );
1058        }
1059    }
1060
1061    #[cfg(feature = "v2_74")]
1062    #[cfg_attr(docsrs, doc(cfg(feature = "v2_74")))]
1063    fn make_symbolic_link_future(
1064        &self,
1065        symlink_value: impl AsRef<std::path::Path>,
1066        io_priority: glib::Priority,
1067    ) -> Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
1068        let symlink_value = symlink_value.as_ref().to_owned();
1069        Box::pin(crate::GioFuture::new(
1070            self,
1071            move |obj, cancellable, send| {
1072                obj.make_symbolic_link_async(
1073                    &symlink_value,
1074                    io_priority,
1075                    Some(cancellable),
1076                    move |res| {
1077                        send.resolve(res);
1078                    },
1079                );
1080            },
1081        ))
1082    }
1083
1084    #[cfg(feature = "v2_72")]
1085    #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))]
1086    fn move_future(
1087        &self,
1088        destination: &(impl IsA<File> + Clone + 'static),
1089        flags: crate::FileCopyFlags,
1090        io_priority: glib::Priority,
1091    ) -> (
1092        Pin<Box<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>>,
1093        Pin<Box<dyn futures_core::stream::Stream<Item = (i64, i64)> + 'static>>,
1094    ) {
1095        let destination = destination.clone();
1096
1097        let (sender, receiver) = futures_channel::mpsc::unbounded();
1098
1099        let fut = Box::pin(crate::GioFuture::new(
1100            self,
1101            move |obj, cancellable, send| {
1102                obj.move_async(
1103                    &destination,
1104                    flags,
1105                    io_priority,
1106                    Some(cancellable),
1107                    Some(Box::new(move |current_num_bytes, total_num_bytes| {
1108                        let _ = sender.unbounded_send((current_num_bytes, total_num_bytes));
1109                    })),
1110                    move |res| {
1111                        send.resolve(res);
1112                    },
1113                );
1114            },
1115        ));
1116
1117        (fut, Box::pin(receiver))
1118    }
1119}
1120
1121impl<O: IsA<File>> FileExtManual for O {}