#[inline]
pub fn cancelled_error(reason: impl Into<String>) -> crate::error::AtomwriteError {
crate::error::AtomwriteError::Cancelled {
reason: reason.into(),
exit: current_exit_code(),
}
}
static GLOBAL_DEADLINE: OnceLock<std::time::Instant> = OnceLock::new();
fn record_global_deadline(secs: u64) {
if let Some(at) = std::time::Instant::now().checked_add(std::time::Duration::from_secs(secs)) {
GLOBAL_DEADLINE.set(at).ok();
}
}
#[must_use]
pub fn global_deadline_remaining() -> Option<std::time::Duration> {
GLOBAL_DEADLINE
.get()
.map(|at| at.saturating_duration_since(std::time::Instant::now()))
}
#[derive(Clone, Debug)]
pub struct CancelCheck {
flag: Arc<AtomicBool>,
block: u32,
budget: u32,
}
impl CancelCheck {
#[inline]
#[must_use]
pub fn new(flag: Arc<AtomicBool>, block: u32) -> Self {
let block = block.max(1);
Self {
flag,
block,
budget: block,
}
}
#[inline]
#[must_use]
pub fn for_bytes(flag: Arc<AtomicBool>) -> Self {
Self::new(flag, CANCEL_BLOCK_BYTES as u32)
}
#[inline]
#[must_use]
pub fn for_matches(flag: Arc<AtomicBool>) -> Self {
Self::new(flag, CANCEL_BLOCK_MATCHES as u32)
}
#[inline]
pub fn advance(&mut self, units: u64) -> std::result::Result<(), AtomwriteError> {
let units = u32::try_from(units).unwrap_or(u32::MAX);
self.budget = self.budget.saturating_sub(units);
if self.budget > 0 {
return Ok(());
}
self.budget = self.block;
self.check()
}
#[inline]
pub fn check(&self) -> std::result::Result<(), AtomwriteError> {
if self.flag.load(Ordering::Acquire) {
return Err(cancelled_error(CANCEL_REASON));
}
Ok(())
}
}