use std::sync::Arc;
#[derive(Debug, Clone)]
pub enum ProgressType {
Spinner,
Bar { total: u64 },
}
#[derive(Debug, Clone)]
pub struct ProgressInfo {
pub progress_type: ProgressType,
pub prefix: String,
pub message: String,
pub current: Option<u64>,
}
pub trait ProgressCallback: Send + Sync {
fn start(&self, info: ProgressInfo) -> ProgressId;
fn update_message(&self, id: ProgressId, message: String);
fn increment(&self, id: ProgressId, delta: u64);
fn finish(&self, id: ProgressId, final_message: String);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ProgressId(pub u64);
#[derive(Debug, Default)]
pub struct NoOpProgressCallback;
impl ProgressCallback for NoOpProgressCallback {
fn start(&self, _info: ProgressInfo) -> ProgressId {
ProgressId(0)
}
fn update_message(&self, _id: ProgressId, _message: String) {}
fn increment(&self, _id: ProgressId, _delta: u64) {}
fn finish(&self, _id: ProgressId, _final_message: String) {}
}
pub type ProgressCallbackArc = Arc<dyn ProgressCallback>;
pub fn no_op_progress_callback() -> ProgressCallbackArc {
Arc::new(NoOpProgressCallback)
}
pub struct ProgressHelper {
callback: ProgressCallbackArc,
step_counter: Arc<std::sync::atomic::AtomicI32>,
}
impl ProgressHelper {
pub fn new(callback: ProgressCallbackArc, initial_step: i32) -> Self {
Self {
callback,
step_counter: Arc::new(std::sync::atomic::AtomicI32::new(initial_step)),
}
}
fn next_step(&self) -> i32 {
self.step_counter
.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
}
pub fn create_spinner(&self, message: impl Into<String>) -> ProgressHandler {
let step = self.next_step();
let info = ProgressInfo {
progress_type: ProgressType::Spinner,
prefix: format!("0x{:02X}", step),
message: message.into(),
current: None,
};
let id = self.callback.start(info);
ProgressHandler {
callback: Arc::clone(&self.callback),
id,
}
}
pub fn create_bar(&self, total: u64, message: impl Into<String>) -> ProgressHandler {
let step = self.next_step();
let info = ProgressInfo {
progress_type: ProgressType::Bar { total },
prefix: format!("0x{:02X}", step),
message: message.into(),
current: Some(0),
};
let id = self.callback.start(info);
ProgressHandler {
callback: Arc::clone(&self.callback),
id,
}
}
pub fn current_step(&self) -> i32 {
self.step_counter.load(std::sync::atomic::Ordering::SeqCst)
}
pub fn sync_step_to_external(&self, external_step: &mut i32) {
*external_step = self.current_step();
}
}
pub struct ProgressHandler {
callback: ProgressCallbackArc,
id: ProgressId,
}
impl ProgressHandler {
pub fn set_message(&self, message: impl Into<String>) {
self.callback.update_message(self.id, message.into());
}
pub fn inc(&self, delta: u64) {
self.callback.increment(self.id, delta);
}
pub fn finish_with_message(self, message: impl Into<String>) {
self.callback.finish(self.id, message.into());
}
}