utils/sleep-inhibitor/src/lib.rs
113 lines
//! Cross-platform helper for preventing idle sleep while a turn is running.//!//! Platform-specific behavior://! - macOS: Uses native IOKit power assertions instead of spawning `caffeinate`.//! - Linux: Spawns `systemd-inhibit` or `gnome-session-inhibit` while active.//! - Windows: Uses `PowerCreateRequest` + `PowerSetRequest` with//! `PowerRequestSystemRequired`.//! - Other platforms: No-op backend.#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]mod dummy;#[cfg(target_os = "linux")]mod linux_inhibitor;#[cfg(target_os = "macos")]mod macos;#[cfg(target_os = "windows")]mod windows_inhibitor;#[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]use dummy as imp;#[cfg(target_os = "linux")]use linux_inhibitor as imp;#[cfg(target_os = "macos")]use macos as imp;#[cfg(target_os = "windows")]use windows_inhibitor as imp;/// Keeps the machine awake while a turn is in progress when enabled.#[derive(Debug)]pub struct SleepInhibitor { enabled: bool, turn_running: bool, platform: imp::SleepInhibitor,}impl SleepInhibitor { pub fn new(enabled: bool) -> Self { Self { enabled, turn_running: false, platform: imp::SleepInhibitor::new(), } } /// Update the active turn state; turns sleep prevention on/off as needed. pub fn set_turn_running(&mut self, turn_running: bool) { self.turn_running = turn_running; if !self.enabled { self.release(); return; } if turn_running { self.acquire(); } else { self.release(); } } fn acquire(&mut self) { self.platform.acquire(); } fn release(&mut self) { self.platform.release(); } /// Return the latest turn-running state requested by the caller. pub fn is_turn_running(&self) -> bool { self.turn_running }}#[cfg(test)]mod tests { use super::SleepInhibitor; #[test] fn sleep_inhibitor_toggles_without_panicking() { let mut inhibitor = SleepInhibitor::new(/*enabled*/ true); inhibitor.set_turn_running(/*turn_running*/ true); assert!(inhibitor.is_turn_running()); inhibitor.set_turn_running(/*turn_running*/ false); assert!(!inhibitor.is_turn_running()); } #[test] fn sleep_inhibitor_disabled_does_not_panic() { let mut inhibitor = SleepInhibitor::new(/*enabled*/ false); inhibitor.set_turn_running(/*turn_running*/ true); assert!(inhibitor.is_turn_running()); inhibitor.set_turn_running(/*turn_running*/ false); assert!(!inhibitor.is_turn_running()); } #[test] fn sleep_inhibitor_multiple_true_calls_are_idempotent() { let mut inhibitor = SleepInhibitor::new(/*enabled*/ true); inhibitor.set_turn_running(/*turn_running*/ true); inhibitor.set_turn_running(/*turn_running*/ true); inhibitor.set_turn_running(/*turn_running*/ true); inhibitor.set_turn_running(/*turn_running*/ false); } #[test] fn sleep_inhibitor_can_toggle_multiple_times() { let mut inhibitor = SleepInhibitor::new(/*enabled*/ true); inhibitor.set_turn_running(/*turn_running*/ true); inhibitor.set_turn_running(/*turn_running*/ false); inhibitor.set_turn_running(/*turn_running*/ true); inhibitor.set_turn_running(/*turn_running*/ false); }}