use std::io::Write;
#[derive(Debug, Clone)]
pub struct ProgressEvent {
pub phase: &'static str,
pub message: String,
}
pub trait ProgressSink {
fn emit(&mut self, event: ProgressEvent);
}
pub struct ProgressReporter<'a> {
sink: Option<&'a mut dyn ProgressSink>,
}
impl<'a> ProgressReporter<'a> {
pub fn silent() -> Self {
Self { sink: None }
}
pub fn new(sink: &'a mut dyn ProgressSink) -> Self {
Self { sink: Some(sink) }
}
pub fn emit(&mut self, phase: &'static str, message: impl Into<String>) {
if let Some(sink) = self.sink.as_deref_mut() {
sink.emit(ProgressEvent {
phase,
message: message.into(),
});
}
}
}
pub struct WriterProgress<'a> {
writer: &'a mut dyn Write,
}
impl<'a> WriterProgress<'a> {
pub fn new(writer: &'a mut dyn Write) -> Self {
Self { writer }
}
}
impl ProgressSink for WriterProgress<'_> {
fn emit(&mut self, event: ProgressEvent) {
let tag = color_phase(event.phase);
let _ = writeln!(self.writer, "{} {}", tag, event.message);
let _ = self.writer.flush();
}
}
fn color_phase(phase: &str) -> String {
let (color, label) = match phase {
"push" => ("1;34", "PUSH"),
"pull" => ("1;36", "PULL"),
"pack" => ("1;33", "PACK"),
"unpack" => ("1;32", "UNPACK"),
_ => ("1;37", phase),
};
format!("\x1b[{}m[{}]\x1b[0m", color, label)
}