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}