use std::sync::{
mpsc::{Receiver, SendError, Sender},
Arc, OnceLock,
};
use crate::channel::Channel;
pub trait Progress: Send {
fn apply(&self, current: &mut u32);
}
pub struct TaskProgress {
current: u32,
total: Arc<OnceLock<u32>>,
channel: Channel<Box<dyn Progress>>,
}
impl Default for TaskProgress {
fn default() -> Self {
Self::new()
}
}
impl TaskProgress {
pub fn new() -> Self {
Self {
current: 0,
total: Arc::new(OnceLock::new()),
channel: Channel::new(),
}
}
#[cfg(feature = "egui")]
pub fn ui(&self, ui: &mut egui::Ui) {
debug_assert!(self.total.get().is_some());
if let Some(total) = self.total.get().copied() {
ui.add(
egui::ProgressBar::new(self.current as f32 / total as f32)
.text(format!("{}/{}", self.current, total)),
);
} else {
ui.spinner();
}
}
pub fn current_mut(&mut self) -> &mut u32 {
&mut self.current
}
pub fn set_total(&self, total: u32) -> Result<(), u32> {
self.total.set(total)
}
pub fn sender(&self) -> Sender<Box<dyn Progress>> {
self.channel.sender()
}
pub fn receiver(&self) -> &Receiver<Box<dyn Progress>> {
self.channel.receiver()
}
pub fn share(&self) -> TaskProgressShared {
TaskProgressShared {
total: self.total.clone(),
sender: self.sender(),
}
}
}
pub struct TaskProgressShared {
total: Arc<OnceLock<u32>>,
sender: Sender<Box<dyn Progress>>,
}
impl TaskProgressShared {
pub fn set_total(&self, total: u32) -> Result<(), u32> {
self.total.set(total)
}
pub fn update<P: Progress + 'static>(
&self,
progress: P,
) -> Result<(), SendError<Box<dyn Progress>>> {
self.sender.send(Box::new(progress))
}
}