//! A minimal progress hook so the engine can report work without depending on
//! any UI crate. The CLI implements this with `indicatif`; library callers pass
//! `None`.

/// Receives coarse progress events from the engine. Implementations must be
/// `Sync` because the engine calls `inc` from parallel workers.
pub trait Progress: Sync {
    /// Begin a named stage with a known total number of items.
    fn begin(&self, stage: &str, total: u64);
    /// Advance the current stage by `n` items.
    fn inc(&self, n: u64);
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::atomic::{AtomicU64, Ordering};

    #[derive(Default)]
    struct Counter {
        total: AtomicU64,
        done: AtomicU64,
    }
    impl Progress for Counter {
        fn begin(&self, _stage: &str, total: u64) {
            self.total.store(total, Ordering::SeqCst);
        }
        fn inc(&self, n: u64) {
            self.done.fetch_add(n, Ordering::SeqCst);
        }
    }

    #[test]
    fn counter_records_begin_and_inc() {
        let c = Counter::default();
        let p: &dyn Progress = &c;
        p.begin("work", 3);
        p.inc(1);
        p.inc(2);
        assert_eq!(c.total.load(Ordering::SeqCst), 3);
        assert_eq!(c.done.load(Ordering::SeqCst), 3);
    }
}
