use crate::Error;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Stage {
Segmenting,
Parameterizing,
Packing,
Output,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct Progress {
pub stage: Stage,
pub done: usize,
pub total: Option<usize>,
}
pub(crate) static QUIET: Ctx<'static> = Ctx::new(None);
pub(crate) struct Ctx<'a> {
callback: Option<&'a (dyn Fn(Progress) -> bool + Sync)>,
count: Mutex<(Stage, usize)>,
cancelled: AtomicBool,
}
impl<'a> Ctx<'a> {
pub const fn new(callback: Option<&'a (dyn Fn(Progress) -> bool + Sync)>) -> Self {
Ctx {
callback,
count: Mutex::new((Stage::Segmenting, 0)),
cancelled: AtomicBool::new(false),
}
}
pub fn advance(&self, stage: Stage, by: usize, total: Option<usize>) -> Result<(), Error> {
let Some(callback) = self.callback else {
return Ok(());
};
let mut count = self.count.lock().unwrap_or_else(|e| e.into_inner());
if self.is_cancelled() {
return Err(Error::Cancelled);
}
if count.0 != stage {
*count = (stage, 0);
}
count.1 += by;
if callback(Progress {
stage,
done: count.1,
total,
}) {
Ok(())
} else {
self.cancelled.store(true, Ordering::Relaxed);
Err(Error::Cancelled)
}
}
pub fn is_cancelled(&self) -> bool {
self.cancelled.load(Ordering::Relaxed)
}
}