glib/
functions.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3pub use crate::auto::functions::*;
4#[cfg(not(windows))]
5use std::boxed::Box as Box_;
6#[cfg(not(windows))]
7use std::mem;
8#[cfg(not(windows))]
9#[cfg(feature = "v2_58")]
10use std::os::unix::io::AsRawFd;
11#[cfg(not(windows))]
12use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
13use std::ptr;
14
15// #[cfg(windows)]
16// #[cfg(feature = "v2_58")]
17// use std::os::windows::io::AsRawHandle;
18use crate::{ffi, translate::*, ChecksumType, GStr};
19#[cfg(not(windows))]
20use crate::{Error, Pid, SpawnFlags};
21
22#[cfg(feature = "v2_58")]
23#[cfg(not(windows))]
24#[cfg_attr(docsrs, doc(cfg(all(feature = "v2_58", not(windows)))))]
25#[allow(clippy::too_many_arguments)]
26#[doc(alias = "g_spawn_async_with_fds")]
27pub fn spawn_async_with_fds<P: AsRef<std::path::Path>, T: AsRawFd, U: AsRawFd, V: AsRawFd>(
28    working_directory: P,
29    argv: &[&str],
30    envp: &[&str],
31    flags: SpawnFlags,
32    child_setup: Option<Box_<dyn FnOnce() + 'static>>,
33    stdin_fd: T,
34    stdout_fd: U,
35    stderr_fd: V,
36) -> Result<Pid, Error> {
37    let child_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(child_setup);
38    unsafe extern "C" fn child_setup_func(user_data: ffi::gpointer) {
39        let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
40            Box_::from_raw(user_data as *mut _);
41        let callback = (*callback).expect("cannot get closure...");
42        callback()
43    }
44    let child_setup = if child_setup_data.is_some() {
45        Some(child_setup_func as _)
46    } else {
47        None
48    };
49    let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
50    unsafe {
51        let mut child_pid = mem::MaybeUninit::uninit();
52        let mut error = ptr::null_mut();
53        let _ = ffi::g_spawn_async_with_fds(
54            working_directory.as_ref().to_glib_none().0,
55            argv.to_glib_none().0,
56            envp.to_glib_none().0,
57            flags.into_glib(),
58            child_setup,
59            Box_::into_raw(super_callback0) as *mut _,
60            child_pid.as_mut_ptr(),
61            stdin_fd.as_raw_fd(),
62            stdout_fd.as_raw_fd(),
63            stderr_fd.as_raw_fd(),
64            &mut error,
65        );
66        let child_pid = from_glib(child_pid.assume_init());
67        if error.is_null() {
68            Ok(child_pid)
69        } else {
70            Err(from_glib_full(error))
71        }
72    }
73}
74
75// #[cfg(feature = "v2_58")]
76// #[cfg(windows)]
77// pub fn spawn_async_with_fds<
78//     P: AsRef<std::path::Path>,
79//     T: AsRawHandle,
80//     U: AsRawHandle,
81//     V: AsRawHandle,
82// >(
83//     working_directory: P,
84//     argv: &[&str],
85//     envp: &[&str],
86//     flags: SpawnFlags,
87//     child_setup: Option<Box_<dyn FnOnce() + 'static>>,
88//     stdin_fd: T,
89//     stdout_fd: U,
90//     stderr_fd: V,
91// ) -> Result<Pid, Error> {
92//     let child_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(child_setup);
93//     unsafe extern "C" fn child_setup_func<P: AsRef<std::path::Path>>(
94//         user_data: ffi::gpointer,
95//     ) {
96//         let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
97//             Box_::from_raw(user_data as *mut _);
98//         let callback = (*callback).expect("cannot get closure...");
99//         callback()
100//     }
101//     let child_setup = if child_setup_data.is_some() {
102//         Some(child_setup_func::<P> as _)
103//     } else {
104//         None
105//     };
106//     let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
107//     unsafe {
108//         let mut child_pid = mem::MaybeUninit::uninit();
109//         let mut error = ptr::null_mut();
110//         let _ = ffi::g_spawn_async_with_fds(
111//             working_directory.as_ref().to_glib_none().0,
112//             argv.to_glib_none().0,
113//             envp.to_glib_none().0,
114//             flags.into_glib(),
115//             child_setup,
116//             Box_::into_raw(super_callback0) as *mut _,
117//             child_pid.as_mut_ptr(),
118//             stdin_fd.as_raw_handle() as usize as _,
119//             stdout_fd.as_raw_handle() as usize as _,
120//             stderr_fd.as_raw_handle() as usize as _,
121//             &mut error,
122//         );
123//         let child_pid = from_glib(child_pid.assume_init());
124//         if error.is_null() {
125//             Ok(child_pid)
126//         } else {
127//             Err(from_glib_full(error))
128//         }
129//     }
130// }
131
132#[cfg(not(windows))]
133#[cfg_attr(docsrs, doc(cfg(not(windows))))]
134#[doc(alias = "g_spawn_async_with_pipes")]
135pub fn spawn_async_with_pipes<
136    P: AsRef<std::path::Path>,
137    T: FromRawFd,
138    U: FromRawFd,
139    V: FromRawFd,
140>(
141    working_directory: P,
142    argv: &[&std::path::Path],
143    envp: &[&std::path::Path],
144    flags: SpawnFlags,
145    child_setup: Option<Box_<dyn FnOnce() + 'static>>,
146) -> Result<(Pid, T, U, V), Error> {
147    let child_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(child_setup);
148    unsafe extern "C" fn child_setup_func(user_data: ffi::gpointer) {
149        let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
150            Box_::from_raw(user_data as *mut _);
151        let callback = (*callback).expect("cannot get closure...");
152        callback()
153    }
154    let child_setup = if child_setup_data.is_some() {
155        Some(child_setup_func as _)
156    } else {
157        None
158    };
159    let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = child_setup_data;
160    unsafe {
161        let mut child_pid = mem::MaybeUninit::uninit();
162        let mut standard_input = mem::MaybeUninit::uninit();
163        let mut standard_output = mem::MaybeUninit::uninit();
164        let mut standard_error = mem::MaybeUninit::uninit();
165        let mut error = ptr::null_mut();
166        let _ = ffi::g_spawn_async_with_pipes(
167            working_directory.as_ref().to_glib_none().0,
168            argv.to_glib_none().0,
169            envp.to_glib_none().0,
170            flags.into_glib(),
171            child_setup,
172            Box_::into_raw(super_callback0) as *mut _,
173            child_pid.as_mut_ptr(),
174            standard_input.as_mut_ptr(),
175            standard_output.as_mut_ptr(),
176            standard_error.as_mut_ptr(),
177            &mut error,
178        );
179        let child_pid = from_glib(child_pid.assume_init());
180        let standard_input = standard_input.assume_init();
181        let standard_output = standard_output.assume_init();
182        let standard_error = standard_error.assume_init();
183        if error.is_null() {
184            #[cfg(not(windows))]
185            {
186                Ok((
187                    child_pid,
188                    FromRawFd::from_raw_fd(standard_input),
189                    FromRawFd::from_raw_fd(standard_output),
190                    FromRawFd::from_raw_fd(standard_error),
191                ))
192            }
193        // #[cfg(windows)]
194        // {
195        //     use std::os::windows::io::{FromRawHandle, RawHandle};
196        //     Ok((
197        //         child_pid,
198        //         File::from_raw_handle(standard_input as usize as RawHandle),
199        //         File::from_raw_handle(standard_output as usize as RawHandle),
200        //         File::from_raw_handle(standard_error as usize as RawHandle),
201        //     ))
202        // }
203        } else {
204            Err(from_glib_full(error))
205        }
206    }
207}
208
209// rustdoc-stripper-ignore-next
210/// Obtain the character set for the current locale.
211///
212/// This returns whether the locale's encoding is UTF-8, and the current
213/// charset if available.
214#[doc(alias = "g_get_charset")]
215#[doc(alias = "get_charset")]
216pub fn charset() -> (bool, Option<&'static GStr>) {
217    unsafe {
218        let mut out_charset = ptr::null();
219        let is_utf8 = from_glib(ffi::g_get_charset(&mut out_charset));
220        let charset = from_glib_none(out_charset);
221        (is_utf8, charset)
222    }
223}
224
225#[doc(alias = "g_compute_checksum_for_string")]
226pub fn compute_checksum_for_string(
227    checksum_type: ChecksumType,
228    str: impl IntoGStr,
229) -> Option<crate::GString> {
230    str.run_with_gstr(|str| unsafe {
231        from_glib_full(ffi::g_compute_checksum_for_string(
232            checksum_type.into_glib(),
233            str.as_ptr(),
234            str.len() as _,
235        ))
236    })
237}
238
239/// Similar to the UNIX pipe() call, but on modern systems like Linux
240/// uses the pipe2() system call, which atomically creates a pipe with
241/// the configured flags.
242///
243/// As of GLib 2.78, the supported flags are `O_CLOEXEC`/`FD_CLOEXEC` (see below)
244/// and `O_NONBLOCK`. Prior to GLib 2.78, only `FD_CLOEXEC` was supported — if
245/// you wanted to configure `O_NONBLOCK` then that had to be done separately with
246/// `fcntl()`.
247///
248/// Since GLib 2.80, the constants `G_UNIX_PIPE_END_READ` and
249/// `G_UNIX_PIPE_END_WRITE` can be used as mnemonic indexes in @fds.
250///
251/// It is a programmer error to call this function with unsupported flags, and a
252/// critical warning will be raised.
253///
254/// As of GLib 2.78, it is preferred to pass `O_CLOEXEC` in, rather than
255/// `FD_CLOEXEC`, as that matches the underlying `pipe()` API more closely. Prior
256/// to 2.78, only `FD_CLOEXEC` was supported. Support for `FD_CLOEXEC` may be
257/// deprecated and removed in future.
258/// ## `fds`
259/// Array of two integers
260/// ## `flags`
261/// Bitfield of file descriptor flags, as for fcntl()
262///
263/// # Returns
264///
265/// [`true`] on success, [`false`] if not (and errno will be set).
266// rustdoc-stripper-ignore-next-stop
267/// Similar to the UNIX pipe() call, but on modern systems like Linux
268/// uses the pipe2() system call, which atomically creates a pipe with
269/// the configured flags.
270///
271/// As of GLib 2.78, the supported flags are `O_CLOEXEC`/`FD_CLOEXEC` (see below)
272/// and `O_NONBLOCK`. Prior to GLib 2.78, only `FD_CLOEXEC` was supported — if
273/// you wanted to configure `O_NONBLOCK` then that had to be done separately with
274/// `fcntl()`.
275///
276/// Since GLib 2.80, the constants `G_UNIX_PIPE_END_READ` and
277/// `G_UNIX_PIPE_END_WRITE` can be used as mnemonic indexes in @fds.
278///
279/// It is a programmer error to call this function with unsupported flags, and a
280/// critical warning will be raised.
281///
282/// As of GLib 2.78, it is preferred to pass `O_CLOEXEC` in, rather than
283/// `FD_CLOEXEC`, as that matches the underlying `pipe()` API more closely. Prior
284/// to 2.78, only `FD_CLOEXEC` was supported. Support for `FD_CLOEXEC` may be
285/// deprecated and removed in future.
286/// ## `fds`
287/// Array of two integers
288/// ## `flags`
289/// Bitfield of file descriptor flags, as for fcntl()
290///
291/// # Returns
292///
293/// [`true`] on success, [`false`] if not (and errno will be set).
294#[cfg(unix)]
295#[doc(alias = "g_unix_open_pipe")]
296pub fn unix_open_pipe(flags: i32) -> Result<(RawFd, RawFd), Error> {
297    unsafe {
298        let mut fds = [0, 2];
299        let mut error = ptr::null_mut();
300        let _ = ffi::g_unix_open_pipe(&mut fds, flags, &mut error);
301        if error.is_null() {
302            Ok((
303                FromRawFd::from_raw_fd(fds[0]),
304                FromRawFd::from_raw_fd(fds[1]),
305            ))
306        } else {
307            Err(from_glib_full(error))
308        }
309    }
310}
311
312#[cfg(unix)]
313#[doc(alias = "g_file_open_tmp")]
314pub fn file_open_tmp(
315    tmpl: Option<impl AsRef<std::path::Path>>,
316) -> Result<(RawFd, std::path::PathBuf), crate::Error> {
317    unsafe {
318        let mut name_used = ptr::null_mut();
319        let mut error = ptr::null_mut();
320        let ret = ffi::g_file_open_tmp(
321            tmpl.as_ref().map(|p| p.as_ref()).to_glib_none().0,
322            &mut name_used,
323            &mut error,
324        );
325        if error.is_null() {
326            Ok((ret.into_raw_fd(), from_glib_full(name_used)))
327        } else {
328            Err(from_glib_full(error))
329        }
330    }
331}
332
333// rustdoc-stripper-ignore-next
334/// Spawn a new infallible `Future` on the thread-default main context.
335///
336/// This can be called from any thread and will execute the future from the thread
337/// where main context is running, e.g. via a `MainLoop`.
338pub fn spawn_future<R: Send + 'static, F: std::future::Future<Output = R> + Send + 'static>(
339    f: F,
340) -> crate::JoinHandle<R> {
341    let ctx = crate::MainContext::ref_thread_default();
342    ctx.spawn(f)
343}
344
345// rustdoc-stripper-ignore-next
346/// Spawn a new infallible `Future` on the thread-default main context.
347///
348/// The given `Future` does not have to be `Send`.
349///
350/// This can be called only from the thread where the main context is running, e.g.
351/// from any other `Future` that is executed on this main context, or after calling
352/// `with_thread_default` or `acquire` on the main context.
353pub fn spawn_future_local<R: 'static, F: std::future::Future<Output = R> + 'static>(
354    f: F,
355) -> crate::JoinHandle<R> {
356    let ctx = crate::MainContext::ref_thread_default();
357    ctx.spawn_local(f)
358}