1use crate::{ffi, AsyncResult, Cancellable, Initable, InputStream, OutputStream, SubprocessFlags};
6use glib::{prelude::*, translate::*};
7use std::{boxed::Box as Box_, pin::Pin};
8
9glib::wrapper! {
10 #[doc(alias = "GSubprocess")]
11 pub struct Subprocess(Object<ffi::GSubprocess>) @implements Initable;
12
13 match fn {
14 type_ => || ffi::g_subprocess_get_type(),
15 }
16}
17
18impl Subprocess {
19 #[doc(alias = "g_subprocess_newv")]
25 pub fn newv(
26 argv: &[&std::ffi::OsStr],
27 flags: SubprocessFlags,
28 ) -> Result<Subprocess, glib::Error> {
29 unsafe {
30 let mut error = std::ptr::null_mut();
31 let ret = ffi::g_subprocess_newv(argv.to_glib_none().0, flags.into_glib(), &mut error);
32 if error.is_null() {
33 Ok(from_glib_full(ret))
34 } else {
35 Err(from_glib_full(error))
36 }
37 }
38 }
39
40 #[doc(alias = "g_subprocess_communicate")]
41 pub fn communicate(
42 &self,
43 stdin_buf: Option<&glib::Bytes>,
44 cancellable: Option<&impl IsA<Cancellable>>,
45 ) -> Result<(Option<glib::Bytes>, Option<glib::Bytes>), glib::Error> {
46 unsafe {
47 let mut stdout_buf = std::ptr::null_mut();
48 let mut stderr_buf = std::ptr::null_mut();
49 let mut error = std::ptr::null_mut();
50 let is_ok = ffi::g_subprocess_communicate(
51 self.to_glib_none().0,
52 stdin_buf.to_glib_none().0,
53 cancellable.map(|p| p.as_ref()).to_glib_none().0,
54 &mut stdout_buf,
55 &mut stderr_buf,
56 &mut error,
57 );
58 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
59 if error.is_null() {
60 Ok((from_glib_full(stdout_buf), from_glib_full(stderr_buf)))
61 } else {
62 Err(from_glib_full(error))
63 }
64 }
65 }
66
67 #[doc(alias = "g_subprocess_communicate_async")]
68 pub fn communicate_async<
69 P: FnOnce(Result<(Option<glib::Bytes>, Option<glib::Bytes>), glib::Error>) + 'static,
70 >(
71 &self,
72 stdin_buf: Option<&glib::Bytes>,
73 cancellable: Option<&impl IsA<Cancellable>>,
74 callback: P,
75 ) {
76 let main_context = glib::MainContext::ref_thread_default();
77 let is_main_context_owner = main_context.is_owner();
78 let has_acquired_main_context = (!is_main_context_owner)
79 .then(|| main_context.acquire().ok())
80 .flatten();
81 assert!(
82 is_main_context_owner || has_acquired_main_context.is_some(),
83 "Async operations only allowed if the thread is owning the MainContext"
84 );
85
86 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
87 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
88 unsafe extern "C" fn communicate_async_trampoline<
89 P: FnOnce(Result<(Option<glib::Bytes>, Option<glib::Bytes>), glib::Error>) + 'static,
90 >(
91 _source_object: *mut glib::gobject_ffi::GObject,
92 res: *mut crate::ffi::GAsyncResult,
93 user_data: glib::ffi::gpointer,
94 ) {
95 let mut error = std::ptr::null_mut();
96 let mut stdout_buf = std::ptr::null_mut();
97 let mut stderr_buf = std::ptr::null_mut();
98 ffi::g_subprocess_communicate_finish(
99 _source_object as *mut _,
100 res,
101 &mut stdout_buf,
102 &mut stderr_buf,
103 &mut error,
104 );
105 let result = if error.is_null() {
106 Ok((from_glib_full(stdout_buf), from_glib_full(stderr_buf)))
107 } else {
108 Err(from_glib_full(error))
109 };
110 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
111 Box_::from_raw(user_data as *mut _);
112 let callback: P = callback.into_inner();
113 callback(result);
114 }
115 let callback = communicate_async_trampoline::<P>;
116 unsafe {
117 ffi::g_subprocess_communicate_async(
118 self.to_glib_none().0,
119 stdin_buf.to_glib_none().0,
120 cancellable.map(|p| p.as_ref()).to_glib_none().0,
121 Some(callback),
122 Box_::into_raw(user_data) as *mut _,
123 );
124 }
125 }
126
127 pub fn communicate_future(
128 &self,
129 stdin_buf: Option<&glib::Bytes>,
130 ) -> Pin<
131 Box_<
132 dyn std::future::Future<
133 Output = Result<(Option<glib::Bytes>, Option<glib::Bytes>), glib::Error>,
134 > + 'static,
135 >,
136 > {
137 let stdin_buf = stdin_buf.map(ToOwned::to_owned);
138 Box_::pin(crate::GioFuture::new(
139 self,
140 move |obj, cancellable, send| {
141 obj.communicate_async(
142 stdin_buf.as_ref().map(::std::borrow::Borrow::borrow),
143 Some(cancellable),
144 move |res| {
145 send.resolve(res);
146 },
147 );
148 },
149 ))
150 }
151
152 #[doc(alias = "g_subprocess_communicate_utf8")]
153 pub fn communicate_utf8(
154 &self,
155 stdin_buf: Option<&str>,
156 cancellable: Option<&impl IsA<Cancellable>>,
157 ) -> Result<(Option<glib::GString>, Option<glib::GString>), glib::Error> {
158 unsafe {
159 let mut stdout_buf = std::ptr::null_mut();
160 let mut stderr_buf = std::ptr::null_mut();
161 let mut error = std::ptr::null_mut();
162 let is_ok = ffi::g_subprocess_communicate_utf8(
163 self.to_glib_none().0,
164 stdin_buf.to_glib_none().0,
165 cancellable.map(|p| p.as_ref()).to_glib_none().0,
166 &mut stdout_buf,
167 &mut stderr_buf,
168 &mut error,
169 );
170 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
171 if error.is_null() {
172 Ok((from_glib_full(stdout_buf), from_glib_full(stderr_buf)))
173 } else {
174 Err(from_glib_full(error))
175 }
176 }
177 }
178
179 #[doc(alias = "g_subprocess_force_exit")]
180 pub fn force_exit(&self) {
181 unsafe {
182 ffi::g_subprocess_force_exit(self.to_glib_none().0);
183 }
184 }
185
186 #[doc(alias = "g_subprocess_get_exit_status")]
187 #[doc(alias = "get_exit_status")]
188 pub fn exit_status(&self) -> i32 {
189 unsafe { ffi::g_subprocess_get_exit_status(self.to_glib_none().0) }
190 }
191
192 #[doc(alias = "g_subprocess_get_identifier")]
193 #[doc(alias = "get_identifier")]
194 pub fn identifier(&self) -> Option<glib::GString> {
195 unsafe { from_glib_none(ffi::g_subprocess_get_identifier(self.to_glib_none().0)) }
196 }
197
198 #[doc(alias = "g_subprocess_get_if_exited")]
199 #[doc(alias = "get_if_exited")]
200 pub fn has_exited(&self) -> bool {
201 unsafe { from_glib(ffi::g_subprocess_get_if_exited(self.to_glib_none().0)) }
202 }
203
204 #[doc(alias = "g_subprocess_get_if_signaled")]
205 #[doc(alias = "get_if_signaled")]
206 pub fn has_signaled(&self) -> bool {
207 unsafe { from_glib(ffi::g_subprocess_get_if_signaled(self.to_glib_none().0)) }
208 }
209
210 #[doc(alias = "g_subprocess_get_status")]
211 #[doc(alias = "get_status")]
212 pub fn status(&self) -> i32 {
213 unsafe { ffi::g_subprocess_get_status(self.to_glib_none().0) }
214 }
215
216 #[doc(alias = "g_subprocess_get_stderr_pipe")]
217 #[doc(alias = "get_stderr_pipe")]
218 pub fn stderr_pipe(&self) -> Option<InputStream> {
219 unsafe { from_glib_none(ffi::g_subprocess_get_stderr_pipe(self.to_glib_none().0)) }
220 }
221
222 #[doc(alias = "g_subprocess_get_stdin_pipe")]
223 #[doc(alias = "get_stdin_pipe")]
224 pub fn stdin_pipe(&self) -> Option<OutputStream> {
225 unsafe { from_glib_none(ffi::g_subprocess_get_stdin_pipe(self.to_glib_none().0)) }
226 }
227
228 #[doc(alias = "g_subprocess_get_stdout_pipe")]
229 #[doc(alias = "get_stdout_pipe")]
230 pub fn stdout_pipe(&self) -> Option<InputStream> {
231 unsafe { from_glib_none(ffi::g_subprocess_get_stdout_pipe(self.to_glib_none().0)) }
232 }
233
234 #[doc(alias = "g_subprocess_get_successful")]
235 #[doc(alias = "get_successful")]
236 pub fn is_successful(&self) -> bool {
237 unsafe { from_glib(ffi::g_subprocess_get_successful(self.to_glib_none().0)) }
238 }
239
240 #[doc(alias = "g_subprocess_get_term_sig")]
241 #[doc(alias = "get_term_sig")]
242 pub fn term_sig(&self) -> i32 {
243 unsafe { ffi::g_subprocess_get_term_sig(self.to_glib_none().0) }
244 }
245
246 #[cfg(not(windows))]
247 #[cfg_attr(docsrs, doc(cfg(not(windows))))]
248 #[doc(alias = "g_subprocess_send_signal")]
249 pub fn send_signal(&self, signal_num: i32) {
250 unsafe {
251 ffi::g_subprocess_send_signal(self.to_glib_none().0, signal_num);
252 }
253 }
254
255 #[doc(alias = "g_subprocess_wait")]
256 pub fn wait(&self, cancellable: Option<&impl IsA<Cancellable>>) -> Result<(), glib::Error> {
257 unsafe {
258 let mut error = std::ptr::null_mut();
259 let is_ok = ffi::g_subprocess_wait(
260 self.to_glib_none().0,
261 cancellable.map(|p| p.as_ref()).to_glib_none().0,
262 &mut error,
263 );
264 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
265 if error.is_null() {
266 Ok(())
267 } else {
268 Err(from_glib_full(error))
269 }
270 }
271 }
272
273 #[doc(alias = "g_subprocess_wait_async")]
274 pub fn wait_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
275 &self,
276 cancellable: Option<&impl IsA<Cancellable>>,
277 callback: P,
278 ) {
279 let main_context = glib::MainContext::ref_thread_default();
280 let is_main_context_owner = main_context.is_owner();
281 let has_acquired_main_context = (!is_main_context_owner)
282 .then(|| main_context.acquire().ok())
283 .flatten();
284 assert!(
285 is_main_context_owner || has_acquired_main_context.is_some(),
286 "Async operations only allowed if the thread is owning the MainContext"
287 );
288
289 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
290 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
291 unsafe extern "C" fn wait_async_trampoline<P: FnOnce(Result<(), glib::Error>) + 'static>(
292 _source_object: *mut glib::gobject_ffi::GObject,
293 res: *mut crate::ffi::GAsyncResult,
294 user_data: glib::ffi::gpointer,
295 ) {
296 let mut error = std::ptr::null_mut();
297 ffi::g_subprocess_wait_finish(_source_object as *mut _, res, &mut error);
298 let result = if error.is_null() {
299 Ok(())
300 } else {
301 Err(from_glib_full(error))
302 };
303 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
304 Box_::from_raw(user_data as *mut _);
305 let callback: P = callback.into_inner();
306 callback(result);
307 }
308 let callback = wait_async_trampoline::<P>;
309 unsafe {
310 ffi::g_subprocess_wait_async(
311 self.to_glib_none().0,
312 cancellable.map(|p| p.as_ref()).to_glib_none().0,
313 Some(callback),
314 Box_::into_raw(user_data) as *mut _,
315 );
316 }
317 }
318
319 pub fn wait_future(
320 &self,
321 ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
322 Box_::pin(crate::GioFuture::new(
323 self,
324 move |obj, cancellable, send| {
325 obj.wait_async(Some(cancellable), move |res| {
326 send.resolve(res);
327 });
328 },
329 ))
330 }
331
332 #[doc(alias = "g_subprocess_wait_check")]
333 pub fn wait_check(
334 &self,
335 cancellable: Option<&impl IsA<Cancellable>>,
336 ) -> Result<(), glib::Error> {
337 unsafe {
338 let mut error = std::ptr::null_mut();
339 let is_ok = ffi::g_subprocess_wait_check(
340 self.to_glib_none().0,
341 cancellable.map(|p| p.as_ref()).to_glib_none().0,
342 &mut error,
343 );
344 debug_assert_eq!(is_ok == glib::ffi::GFALSE, !error.is_null());
345 if error.is_null() {
346 Ok(())
347 } else {
348 Err(from_glib_full(error))
349 }
350 }
351 }
352
353 #[doc(alias = "g_subprocess_wait_check_async")]
354 pub fn wait_check_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
355 &self,
356 cancellable: Option<&impl IsA<Cancellable>>,
357 callback: P,
358 ) {
359 let main_context = glib::MainContext::ref_thread_default();
360 let is_main_context_owner = main_context.is_owner();
361 let has_acquired_main_context = (!is_main_context_owner)
362 .then(|| main_context.acquire().ok())
363 .flatten();
364 assert!(
365 is_main_context_owner || has_acquired_main_context.is_some(),
366 "Async operations only allowed if the thread is owning the MainContext"
367 );
368
369 let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
370 Box_::new(glib::thread_guard::ThreadGuard::new(callback));
371 unsafe extern "C" fn wait_check_async_trampoline<
372 P: FnOnce(Result<(), glib::Error>) + 'static,
373 >(
374 _source_object: *mut glib::gobject_ffi::GObject,
375 res: *mut crate::ffi::GAsyncResult,
376 user_data: glib::ffi::gpointer,
377 ) {
378 let mut error = std::ptr::null_mut();
379 ffi::g_subprocess_wait_check_finish(_source_object as *mut _, res, &mut error);
380 let result = if error.is_null() {
381 Ok(())
382 } else {
383 Err(from_glib_full(error))
384 };
385 let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
386 Box_::from_raw(user_data as *mut _);
387 let callback: P = callback.into_inner();
388 callback(result);
389 }
390 let callback = wait_check_async_trampoline::<P>;
391 unsafe {
392 ffi::g_subprocess_wait_check_async(
393 self.to_glib_none().0,
394 cancellable.map(|p| p.as_ref()).to_glib_none().0,
395 Some(callback),
396 Box_::into_raw(user_data) as *mut _,
397 );
398 }
399 }
400
401 pub fn wait_check_future(
402 &self,
403 ) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
404 Box_::pin(crate::GioFuture::new(
405 self,
406 move |obj, cancellable, send| {
407 obj.wait_check_async(Some(cancellable), move |res| {
408 send.resolve(res);
409 });
410 },
411 ))
412 }
413}