1use anyhow::{Context, Result};
7use std::process;
8use std::sync::atomic::{AtomicBool, Ordering};
9use thiserror::Error;
10
11static HANDLER_INSTALLED: AtomicBool = AtomicBool::new(false);
12static CANCELLED: AtomicBool = AtomicBool::new(false);
13
14#[derive(Debug, Error)]
16#[error("cancelled")]
17pub struct CancellationError;
18
19pub fn init_handler() -> Result<()> {
21 if HANDLER_INSTALLED
22 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
23 .is_err()
24 {
25 return Ok(());
26 }
27
28 if let Err(err) = ctrlc::set_handler(|| {
29 if CANCELLED.swap(true, Ordering::Relaxed) {
30 process::exit(130);
31 }
32 }) {
33 HANDLER_INSTALLED.store(false, Ordering::Relaxed);
34 return Err(err).context("failed to install Ctrl+C handler");
35 }
36
37 Ok(())
38}
39
40pub fn is_cancelled() -> bool {
42 CANCELLED.load(Ordering::Relaxed)
43}
44
45pub fn check() -> std::result::Result<(), CancellationError> {
47 if is_cancelled() {
48 Err(CancellationError)
49 } else {
50 Ok(())
51 }
52}