1use std::sync::atomic::{AtomicBool, Ordering};
6use std::sync::Arc;
7
8use crate::cli::ThreadMode;
9use crate::error::{CliError, Result};
10
11pub const EXIT_CODE_INTERRUPTED: i32 = 130;
13
14static INTERRUPTED: AtomicBool = AtomicBool::new(false);
16
17pub fn is_interrupted() -> bool {
19 INTERRUPTED.load(Ordering::SeqCst)
20}
21
22pub fn setup_signal_handler() -> Result<Arc<AtomicBool>> {
32 let flag = Arc::new(AtomicBool::new(false));
34 let flag_clone = Arc::clone(&flag);
35
36 ctrlc::set_handler(move || {
37 INTERRUPTED.store(true, Ordering::SeqCst);
39 flag_clone.store(true, Ordering::SeqCst);
40
41 eprintln!("\nInterrupted. Cleaning up...");
43 })
44 .map_err(|e| CliError::Io(std::io::Error::other(e)))?;
45
46 Ok(flag)
47}
48
49pub fn validate_thread_mode(mode: ThreadMode, quiet: bool) -> ThreadMode {
63 match mode {
64 ThreadMode::Multi => ThreadMode::Multi,
65 ThreadMode::Single => {
66 if !quiet {
67 eprintln!(
68 "Warning: Single-threaded mode (--thread-mode single) is not supported in v0.3.2."
69 );
70 eprintln!(" Falling back to multi-threaded mode. (v0.4+ で有効化予定)");
71 }
72 ThreadMode::Multi
73 }
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn test_validate_thread_mode_multi() {
83 let result = validate_thread_mode(ThreadMode::Multi, false);
84 assert_eq!(result, ThreadMode::Multi);
85 }
86
87 #[test]
88 fn test_validate_thread_mode_single_quiet() {
89 let result = validate_thread_mode(ThreadMode::Single, true);
91 assert_eq!(result, ThreadMode::Multi);
92 }
93
94 #[test]
95 fn test_validate_thread_mode_single_verbose() {
96 let result = validate_thread_mode(ThreadMode::Single, false);
98 assert_eq!(result, ThreadMode::Multi);
99 }
100
101 #[test]
102 fn test_is_interrupted_default() {
103 assert!(!is_interrupted() || is_interrupted()); }
108
109 #[test]
110 fn test_exit_code_interrupted() {
111 assert_eq!(EXIT_CODE_INTERRUPTED, 130);
112 }
113}