ctrlc_tiny/
lib.rs

1mod bindings;
2
3use std::{io, sync::Once};
4
5static INIT: Once = Once::new();
6
7/// Initializes the SIGINT (Ctrl-C) signal handler.
8///
9/// This function installs a minimal, signal-safe handler for `SIGINT`.
10/// Once installed, any incoming Ctrl-C will set an internal flag,
11/// which can later be queried via [`is_ctrlc_received()`].
12///
13/// This function may be called multiple times;
14/// the signal handler will only be installed once.
15/// Repeated calls are safe and have no additional effect.
16///
17/// # Errors
18///
19/// Returns an `Err` if the underlying system call (`sigaction`)
20/// fails during handler installation. This typically indicates a
21/// low-level OS error or permission issue.
22///
23/// # Examples
24///
25/// ```rust,no_run
26/// ctrlc_tiny::init_ctrlc()?;
27/// loop {
28///     if ctrlc_tiny::is_ctrlc_received() {
29///         println!("Ctrl-C detected!");
30///         break;
31///     }
32/// }
33/// # Ok::<_, std::io::Error>(())
34/// ```
35pub fn init_ctrlc() -> io::Result<()> {
36    let mut result = Ok(());
37    INIT.call_once(|| unsafe {
38        if bindings::init_sigint_handler() != 0 {
39            result = Err(io::Error::last_os_error());
40        }
41    });
42    result
43}
44
45/// Checks whether Ctrl-C (SIGINT) has been received.
46///
47/// Returns `true` if a `SIGINT` signal (typically from Ctrl-C)
48/// has been delivered since [`init_ctrlc()`] was called.
49///
50/// Once set, the flag remains `true` for the lifetime of the process.
51///
52/// This function is safe to call from any thread at any time
53/// after initialization.
54///
55/// # Examples
56///
57/// ```rust,no_run
58/// ctrlc_tiny::init_ctrlc()?;
59/// loop {
60///     if ctrlc_tiny::is_ctrlc_received() {
61///         println!("Received Ctrl-C");
62///         break;
63///     }
64/// }
65/// # Ok::<_, std::io::Error>(())
66/// ```
67pub fn is_ctrlc_received() -> bool {
68    unsafe { bindings::get_is_sigint_received() != 0 }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn init_ctrlc_should_succeed_and_be_idempotent() {
77        assert!(init_ctrlc().is_ok());
78        assert!(init_ctrlc().is_ok());
79    }
80
81    #[test]
82    fn is_ctrlc_received_initially_false() {
83        assert!(!is_ctrlc_received());
84    }
85}