use crate::{
messages::{MessageLevel, MessageRingBuffer},
progress::{key, Key, State, Step, Task, Value},
unit::Unit,
};
use dashmap::DashMap;
use parking_lot::Mutex;
use std::{ops::Deref, sync::Arc, time::SystemTime};
#[derive(Debug)]
pub struct Item {
pub(crate) key: Key,
pub(crate) highest_child_id: key::Id,
pub(crate) tree: Arc<DashMap<Key, Task>>,
pub(crate) messages: Arc<Mutex<MessageRingBuffer>>,
}
impl Drop for Item {
fn drop(&mut self) {
self.tree.remove(&self.key);
}
}
impl Item {
pub fn init(&mut self, max: Option<Step>, unit: Option<Unit>) {
if let Some(mut r) = self.tree.get_mut(&self.key) {
r.value_mut().progress = Some(Value {
done_at: max,
unit,
..Default::default()
})
};
}
fn alter_progress(&mut self, f: impl FnMut(&mut Value)) {
if let Some(mut r) = self.tree.get_mut(&self.key) {
r.value_mut().progress.as_mut().map(f);
};
}
pub fn set_name(&mut self, name: impl Into<String>) {
if let Some(mut r) = self.tree.get_mut(&self.key) {
r.value_mut().name = name.into();
};
}
pub fn name(&self) -> Option<String> {
self.tree.get(&self.key).map(|r| r.value().name.to_owned())
}
pub fn step(&self) -> Option<Step> {
self.tree
.get(&self.key)
.and_then(|r| r.value().progress.as_ref().map(|p| p.step))
}
pub fn max(&self) -> Option<Step> {
self.tree
.get(&self.key)
.and_then(|r| r.value().progress.as_ref().and_then(|p| p.done_at))
}
pub fn unit(&self) -> Option<Unit> {
self.tree
.get(&self.key)
.and_then(|r| r.value().progress.as_ref().and_then(|p| p.unit.clone()))
}
pub fn set(&mut self, step: Step) {
self.alter_progress(|p| {
p.step = step;
p.state = State::Running;
});
}
pub fn inc_by(&mut self, step: Step) {
self.alter_progress(|p| {
p.step += step;
p.state = State::Running;
});
}
pub fn inc(&mut self) {
self.alter_progress(|p| {
p.step += 1;
p.state = State::Running;
});
}
pub fn blocked(&mut self, reason: &'static str, eta: Option<SystemTime>) {
self.alter_progress(|p| p.state = State::Blocked(reason, eta));
}
pub fn halted(&mut self, reason: &'static str, eta: Option<SystemTime>) {
self.alter_progress(|p| p.state = State::Halted(reason, eta));
}
pub fn add_child(&mut self, name: impl Into<String>) -> Item {
let child_key = self.key.add_child(self.highest_child_id);
self.tree.insert(
child_key,
Task {
name: name.into(),
progress: None,
},
);
self.highest_child_id = self.highest_child_id.wrapping_add(1);
Item {
highest_child_id: 0,
key: child_key,
tree: self.tree.clone(),
messages: self.messages.clone(),
}
}
pub fn message(&mut self, level: MessageLevel, message: impl Into<String>) {
let message: String = message.into();
self.messages.lock().push_overwrite(
level,
{
let name = self.tree.get(&self.key).map(|v| v.name.to_owned()).unwrap_or_default();
#[cfg(feature = "progress-tree-log")]
match level {
MessageLevel::Failure => crate::warn!("{} → {}", name, message),
MessageLevel::Info | MessageLevel::Success => crate::info!("{} → {}", name, message),
};
name
},
message,
)
}
pub fn done(&mut self, message: impl Into<String>) {
self.message(MessageLevel::Success, message)
}
pub fn fail(&mut self, message: impl Into<String>) {
self.message(MessageLevel::Failure, message)
}
pub fn info(&mut self, message: impl Into<String>) {
self.message(MessageLevel::Info, message)
}
pub(crate) fn deep_clone(&self) -> Item {
Item {
key: self.key,
highest_child_id: self.highest_child_id,
tree: Arc::new(self.tree.deref().clone()),
messages: Arc::new(Mutex::new(self.messages.lock().clone())),
}
}
}
impl crate::Progress for Item {
type SubProgress = Item;
fn add_child(&mut self, name: impl Into<String>) -> Self::SubProgress {
Item::add_child(self, name)
}
fn init(&mut self, max: Option<usize>, unit: Option<Unit>) {
Item::init(self, max, unit)
}
fn set(&mut self, step: usize) {
Item::set(self, step)
}
fn unit(&self) -> Option<Unit> {
Item::unit(self)
}
fn max(&self) -> Option<usize> {
Item::max(self)
}
fn step(&self) -> usize {
Item::step(self).unwrap_or(0)
}
fn inc_by(&mut self, step: usize) {
self.inc_by(step)
}
fn message(&mut self, level: MessageLevel, message: impl Into<String>) {
Item::message(self, level, message)
}
}