use std::io;
#[cfg(unix)]
mod unix;
#[cfg(unix)]
pub use unix::{UnixConsoleControl, UnixModes};
#[cfg(unix)]
pub type ActiveConsoleControl = UnixConsoleControl;
#[cfg(windows)]
mod windows;
#[cfg(windows)]
pub use windows::{WindowsConsoleControl, WindowsModes};
#[cfg(windows)]
pub type ActiveConsoleControl = WindowsConsoleControl;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HandlerContract {
AsyncSignalSafe,
SeparateThreadWithBudget { millis: u32 },
}
pub trait ConsoleControl: crate::sealed::Sealed {
type Saved: Send + Sync + Copy + 'static;
const HANDLER_CONTRACT: HandlerContract;
fn capture(&self) -> io::Result<Self::Saved>;
fn restore(&self, saved: &Self::Saved) -> io::Result<()>;
fn write_raw(&self, bytes: &[u8]);
fn trap(&self, on_interrupt: fn()) -> io::Result<()>;
fn interrupt_exit_code(&self) -> i32;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_console_that_cannot_be_captured_reports_the_os_error_rather_than_inventing_one() {
let ctl = crate::CONSOLE;
match ctl.capture() {
Ok(saved) => ctl.restore(&saved).expect("captured modes must restore"),
Err(e) => assert!(
e.raw_os_error().is_some(),
"the failure must carry a real errno, not a synthesized one: {e:?}"
),
}
}
#[test]
fn the_interrupt_exit_code_is_the_shell_convention() {
assert_eq!(crate::CONSOLE.interrupt_exit_code(), 130);
}
}