use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use crate::error::{Autom8Error, Result};
#[derive(Clone)]
pub struct SignalHandler {
shutdown_flag: Arc<AtomicBool>,
}
impl SignalHandler {
pub fn new() -> Result<Self> {
let shutdown_flag = Arc::new(AtomicBool::new(false));
let flag_clone = Arc::clone(&shutdown_flag);
ctrlc::set_handler(move || {
flag_clone.store(true, Ordering::SeqCst);
})
.map_err(|e| Autom8Error::SignalHandler(e.to_string()))?;
Ok(Self { shutdown_flag })
}
pub fn is_shutdown_requested(&self) -> bool {
self.shutdown_flag.load(Ordering::SeqCst)
}
#[cfg(test)]
pub fn reset(&self) {
self.shutdown_flag.store(false, Ordering::SeqCst);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_handler_can_be_created() {
let shutdown_flag = Arc::new(AtomicBool::new(false));
let handler = SignalHandler {
shutdown_flag: shutdown_flag.clone(),
};
assert!(!handler.is_shutdown_requested());
}
#[test]
fn test_is_shutdown_requested_returns_false_initially() {
let shutdown_flag = Arc::new(AtomicBool::new(false));
let handler = SignalHandler { shutdown_flag };
assert!(!handler.is_shutdown_requested());
}
#[test]
fn test_is_shutdown_requested_returns_true_when_flag_set() {
let shutdown_flag = Arc::new(AtomicBool::new(false));
let handler = SignalHandler {
shutdown_flag: shutdown_flag.clone(),
};
shutdown_flag.store(true, Ordering::SeqCst);
assert!(handler.is_shutdown_requested());
}
#[test]
fn test_handler_is_thread_safe() {
let shutdown_flag = Arc::new(AtomicBool::new(false));
let handler = SignalHandler {
shutdown_flag: shutdown_flag.clone(),
};
let handler_clone = handler.clone();
shutdown_flag.store(true, Ordering::SeqCst);
assert!(handler_clone.is_shutdown_requested());
assert!(handler.is_shutdown_requested());
}
#[test]
fn test_handler_clone_shares_state() {
let shutdown_flag = Arc::new(AtomicBool::new(false));
let handler1 = SignalHandler {
shutdown_flag: shutdown_flag.clone(),
};
let handler2 = handler1.clone();
assert!(!handler1.is_shutdown_requested());
assert!(!handler2.is_shutdown_requested());
shutdown_flag.store(true, Ordering::SeqCst);
assert!(handler1.is_shutdown_requested());
assert!(handler2.is_shutdown_requested());
}
#[test]
fn test_reset_clears_shutdown_flag() {
let shutdown_flag = Arc::new(AtomicBool::new(true));
let handler = SignalHandler { shutdown_flag };
assert!(handler.is_shutdown_requested());
handler.reset();
assert!(!handler.is_shutdown_requested());
}
}