use std::path::PathBuf;
use tokio::sync::mpsc;
use crate::profiler::Entry;
#[derive(Debug, Clone)]
pub enum Progress {
Started { bytes_total: Option<u64>, entries_total: usize },
EntryStarted { entry: Entry },
EntryCompleted { entry: Entry },
EntryFailed { entry: Entry },
DirectoriesStarted { total: usize },
DirectoryCompleted { path: PathBuf },
DirectoryFailed { path: PathBuf },
}
#[derive(Clone)]
pub(crate) struct ProgressReporter {
tx: mpsc::UnboundedSender<Progress>,
}
impl ProgressReporter {
pub(crate) fn new(tx: mpsc::UnboundedSender<Progress>) -> Self {
Self { tx }
}
#[cfg(test)]
pub(crate) fn noop() -> Self {
let (tx, _rx) = mpsc::unbounded_channel();
Self { tx }
}
pub(crate) fn send(&self, progress: Progress) {
let _ = self.tx.send(progress);
}
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use super::*;
fn entry(name: &str) -> Entry {
Entry {
path: PathBuf::from(name),
relative_path: PathBuf::from(name),
size: 1,
modified: None,
}
}
#[test]
fn send_after_receiver_dropped_does_not_panic() {
let (tx, rx) = mpsc::unbounded_channel();
let reporter = ProgressReporter::new(tx);
drop(rx);
reporter.send(Progress::EntryStarted { entry: entry("a") });
}
#[tokio::test]
async fn sends_are_received_in_order() {
let (tx, mut rx) = mpsc::unbounded_channel();
let reporter = ProgressReporter::new(tx);
reporter.send(Progress::Started { bytes_total: Some(10), entries_total: 2 });
reporter.send(Progress::EntryStarted { entry: entry("a") });
reporter.send(Progress::EntryCompleted { entry: entry("a") });
drop(reporter);
assert!(matches!(rx.recv().await, Some(Progress::Started { .. })));
assert!(matches!(rx.recv().await, Some(Progress::EntryStarted { .. })));
assert!(matches!(rx.recv().await, Some(Progress::EntryCompleted { .. })));
assert!(rx.recv().await.is_none());
}
}