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