1use std::{pin::Pin, ptr};
4
5use glib::{prelude::*, translate::*, GString};
6use libc::c_char;
7
8use crate::{ffi, Cancellable, Subprocess};
9
10impl Subprocess {
11 #[doc(alias = "g_subprocess_communicate_utf8_async")]
12 pub fn communicate_utf8_async<
13 R: FnOnce(Result<(Option<GString>, Option<GString>), glib::Error>) + 'static,
14 C: IsA<Cancellable>,
15 >(
16 &self,
17 stdin_buf: Option<String>,
18 cancellable: Option<&C>,
19 callback: R,
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 stdin_buf = stdin_buf.to_glib_full();
32 let cancellable = cancellable.map(|c| c.as_ref());
33 let gcancellable = cancellable.to_glib_none();
34 let user_data: Box<(glib::thread_guard::ThreadGuard<R>, *mut c_char)> =
35 Box::new((glib::thread_guard::ThreadGuard::new(callback), stdin_buf));
36 unsafe extern "C" fn communicate_utf8_async_trampoline<
37 R: FnOnce(Result<(Option<GString>, Option<GString>), glib::Error>) + 'static,
38 >(
39 _source_object: *mut glib::gobject_ffi::GObject,
40 res: *mut ffi::GAsyncResult,
41 user_data: glib::ffi::gpointer,
42 ) {
43 let mut error = ptr::null_mut();
44 let mut stdout_buf = ptr::null_mut();
45 let mut stderr_buf = ptr::null_mut();
46 let _ = ffi::g_subprocess_communicate_utf8_finish(
47 _source_object as *mut _,
48 res,
49 &mut stdout_buf,
50 &mut stderr_buf,
51 &mut error,
52 );
53 let result = if error.is_null() {
54 Ok((from_glib_full(stdout_buf), from_glib_full(stderr_buf)))
55 } else {
56 Err(from_glib_full(error))
57 };
58 let callback: Box<(glib::thread_guard::ThreadGuard<R>, *mut c_char)> =
59 Box::from_raw(user_data as *mut _);
60 glib::ffi::g_free(callback.1 as *mut _);
61 (callback.0.into_inner())(result);
62 }
63 unsafe {
64 ffi::g_subprocess_communicate_utf8_async(
65 self.to_glib_none().0,
66 stdin_buf,
67 gcancellable.0,
68 Some(communicate_utf8_async_trampoline::<R>),
69 Box::into_raw(user_data) as *mut _,
70 );
71 }
72 }
73
74 pub fn communicate_utf8_future(
75 &self,
76 stdin_buf: Option<String>,
77 ) -> Pin<
78 Box<
79 dyn std::future::Future<
80 Output = Result<(Option<GString>, Option<GString>), glib::Error>,
81 > + 'static,
82 >,
83 > {
84 Box::pin(crate::GioFuture::new(
85 self,
86 move |obj, cancellable, send| {
87 obj.communicate_utf8_async(stdin_buf, Some(cancellable), move |res| {
88 send.resolve(res);
89 });
90 },
91 ))
92 }
93}