#![forbid(unsafe_code)]
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, OnceLock, RwLock};
use irox_time::epoch::UnixTimestamp;
pub mod console;
#[cfg(feature = "egui")]
pub mod egui;
pub trait ProgressPrinter {
fn track_task_progress(&self, task: &Task);
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TaskElementUnits {
None,
Bytes,
Bits,
}
#[derive(Debug)]
struct TaskInner {
id: AtomicU64,
name: String,
counter: AtomicU64,
max_elements: u64,
_element_units: TaskElementUnits,
created: UnixTimestamp,
started: OnceLock<UnixTimestamp>,
ended: OnceLock<UnixTimestamp>,
children: RwLock<Vec<Task>>,
}
#[derive(Debug, Clone)]
pub struct Task {
inner: Arc<TaskInner>,
}
impl Task {
pub fn new(id: u64, name: String, max_elements: u64) -> Task {
let inner = TaskInner {
id: AtomicU64::new(id),
name,
max_elements,
_element_units: TaskElementUnits::None,
counter: AtomicU64::new(0),
children: RwLock::new(Vec::new()),
created: UnixTimestamp::now(),
started: OnceLock::new(),
ended: OnceLock::new(),
};
Task {
inner: Arc::new(inner),
}
}
pub fn current_progress_count(&self) -> u64 {
self.inner.counter.load(Ordering::Relaxed)
}
pub fn max_elements(&self) -> u64 {
self.inner.max_elements
}
pub fn current_progress_frac(&self) -> f64 {
let cur = self.current_progress_count() as f64;
let max = self.max_elements() as f64;
cur / max
}
pub fn get_id(&self) -> u64 {
self.inner.id.load(Ordering::Relaxed)
}
pub fn get_name(&self) -> &str {
self.inner.name.as_str()
}
pub fn get_created(&self) -> UnixTimestamp {
self.inner.created
}
pub fn get_started(&self) -> Option<&UnixTimestamp> {
self.inner.started.get()
}
pub fn mark_one_completed(&self) {
let completed = self.inner.counter.fetch_add(1, Ordering::Relaxed);
if completed == self.inner.max_elements {
self.mark_ended();
}
}
pub fn mark_all_completed(&self) {
self.inner
.counter
.store(self.inner.max_elements, Ordering::Relaxed);
self.mark_ended();
}
pub fn mark_started(&self) {
let _res = self.inner.started.set(UnixTimestamp::now());
}
pub fn get_ended(&self) -> Option<&UnixTimestamp> {
self.inner.ended.get()
}
pub fn mark_ended(&self) {
let _res = self.inner.ended.set(UnixTimestamp::now());
}
pub fn num_children(&self) -> usize {
let read = self.inner.children.read();
let Ok(read) = read else {
return 0;
};
read.len()
}
pub fn each_child<F: FnMut(&Task)>(&self, func: F) {
let read = self.inner.children.read();
let Ok(read) = read else {
return;
};
read.iter().for_each(func)
}
#[must_use]
pub fn new_child_task(&self, id: u64, name: String, max_elements: u64) -> Task {
loop {
let write = self.inner.children.write();
if let Ok(mut write) = write {
let task = Task::new(id, name, max_elements);
let t2 = task.clone();
write.push(task);
return t2;
};
}
}
pub fn is_complete(&self) -> bool {
self.inner.ended.get().is_some() || self.current_progress_frac() >= 1.
}
}