use crate::{ShellError, Span};
use nu_glob::Interruptible;
use serde::{Deserialize, Serialize};
use std::sync::{
Arc,
atomic::{AtomicBool, Ordering},
};
#[derive(Debug, Clone)]
pub struct Signals {
signals: Option<Arc<AtomicBool>>,
}
impl Signals {
pub const EMPTY: Self = Signals { signals: None };
pub fn new(ctrlc: Arc<AtomicBool>) -> Self {
Self {
signals: Some(ctrlc),
}
}
pub const fn empty() -> Self {
Self::EMPTY
}
#[inline]
pub fn check(&self, span: &Span) -> Result<(), ShellError> {
#[inline]
#[cold]
fn interrupt_error(span: &Span) -> Result<(), ShellError> {
Err(ShellError::Interrupted { span: *span })
}
if self.interrupted() {
interrupt_error(span)
} else {
Ok(())
}
}
pub fn trigger(&self) {
if let Some(signals) = &self.signals {
signals.store(true, Ordering::Relaxed);
}
}
#[inline]
pub fn interrupted(&self) -> bool {
self.signals
.as_deref()
.is_some_and(|b| b.load(Ordering::Relaxed))
}
pub(crate) fn is_empty(&self) -> bool {
self.signals.is_none()
}
pub fn reset(&self) {
if let Some(signals) = &self.signals {
signals.store(false, Ordering::Relaxed);
}
}
}
impl Interruptible for Signals {
#[inline]
fn interrupted(&self) -> bool {
self.interrupted()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SignalAction {
Interrupt,
Reset,
}