use std::sync::Arc;
use async_trait::async_trait;
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct ProgressUpdate {
pub token: String,
pub message: String,
pub percentage: Option<u32>,
pub done: bool,
}
impl ProgressUpdate {
#[must_use]
pub fn new(
token: impl Into<String>,
message: impl Into<String>,
percentage: Option<u32>,
) -> Self {
Self {
token: token.into(),
message: message.into(),
percentage,
done: false,
}
}
#[must_use]
pub fn final_update(token: impl Into<String>, message: impl Into<String>) -> Self {
Self {
token: token.into(),
message: message.into(),
percentage: Some(100),
done: true,
}
}
}
#[async_trait]
pub trait ProgressReporter: Send + Sync + 'static {
async fn report(&self, update: ProgressUpdate);
}
#[derive(Debug, Default, Clone, Copy)]
pub struct NoopReporter;
#[async_trait]
impl ProgressReporter for NoopReporter {
async fn report(&self, _update: ProgressUpdate) {}
}
#[derive(Clone)]
pub struct ProgressSink {
inner: Arc<dyn ProgressReporter>,
token: String,
}
impl ProgressSink {
pub fn new(inner: Arc<dyn ProgressReporter>, token: impl Into<String>) -> Self {
Self {
inner,
token: token.into(),
}
}
#[must_use]
pub fn noop() -> Self {
Self {
inner: Arc::new(NoopReporter),
token: String::new(),
}
}
pub async fn report(&self, message: impl Into<String>, percentage: Option<u32>) {
self.inner
.report(ProgressUpdate {
token: self.token.clone(),
message: message.into(),
percentage,
done: false,
})
.await;
}
pub async fn finish(&self, message: impl Into<String>) {
self.inner
.report(ProgressUpdate {
token: self.token.clone(),
message: message.into(),
percentage: Some(100),
done: true,
})
.await;
}
}
impl std::fmt::Debug for ProgressSink {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ProgressSink")
.field("token", &self.token)
.finish_non_exhaustive()
}
}