#![forbid(unsafe_code)]
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::{Arc, Mutex, OnceLock, RwLock};
pub use irox_time;
use irox_time::epoch::UnixTimestamp;
use irox_time::Duration;
use irox_tools::random::{Random, PRNG};
use irox_tools::sync::SynchronizedOptional;
use irox_tools::vec::RetainTake;
pub mod console;
#[cfg(feature = "egui")]
pub mod egui;
pub mod read;
pub mod write;
static RAND: OnceLock<Mutex<Random>> = OnceLock::new();
fn get_random_id() -> u64 {
if let Ok(mut rand) = RAND.get_or_init(|| Mutex::new(Random::default())).lock() {
return rand.next_u64();
};
Random::default().next_u64()
}
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: AtomicU64,
current_status: SynchronizedOptional<String>,
_element_units: TaskElementUnits,
created: UnixTimestamp,
started: OnceLock<UnixTimestamp>,
ended: OnceLock<UnixTimestamp>,
remaining: RwLock<Duration>,
children: RwLock<Vec<Task>>,
}
#[derive(Debug, Clone)]
pub struct Task {
inner: Arc<TaskInner>,
cancelled: Arc<AtomicBool>,
}
impl Task {
#[must_use]
pub fn new(id: u64, name: String, max_elements: u64) -> Task {
let inner = TaskInner {
id: AtomicU64::new(id),
name,
max_elements: AtomicU64::new(max_elements),
_element_units: TaskElementUnits::None,
counter: AtomicU64::new(0),
current_status: SynchronizedOptional::empty(),
children: RwLock::new(Vec::new()),
created: UnixTimestamp::now(),
started: OnceLock::new(),
ended: OnceLock::new(),
remaining: RwLock::new(Duration::default()),
};
Task {
inner: Arc::new(inner),
cancelled: Arc::new(AtomicBool::new(false)),
}
}
#[must_use]
pub fn new_infinite(id: u64, name: String) -> Task {
Self::new(id, name, u64::MAX)
}
#[must_use]
pub fn new_infinite_named(name: String) -> Task {
let id = get_random_id();
Task::new_infinite(id, name)
}
#[must_use]
pub fn new_named(name: String, max_elements: u64) -> Task {
let id = get_random_id();
Task::new(id, name, max_elements)
}
#[must_use]
pub fn current_progress_count(&self) -> u64 {
self.inner.counter.load(Ordering::SeqCst)
}
pub fn set_current_progress_count(&self, current_progress: u64) {
self.inner.counter.store(current_progress, Ordering::SeqCst);
}
#[must_use]
pub fn max_elements(&self) -> u64 {
self.inner.max_elements.load(Ordering::SeqCst)
}
pub fn set_max_elements(&self, max_elements: u64) {
self.inner
.max_elements
.store(max_elements, Ordering::SeqCst)
}
#[must_use]
pub fn current_progress_frac(&self) -> f64 {
let cur = self.current_progress_count() as f64;
let max = self.max_elements() as f64;
cur / max
}
#[must_use]
pub fn get_id(&self) -> u64 {
self.inner.id.load(Ordering::SeqCst)
}
#[must_use]
pub fn get_name(&self) -> &str {
self.inner.name.as_str()
}
#[must_use]
pub fn get_created(&self) -> UnixTimestamp {
self.inner.created
}
#[must_use]
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::SeqCst);
self.update_remaining();
if completed == self.max_elements() {
self.mark_ended();
}
}
fn update_remaining(&self) {
let completed = self.inner.counter.load(Ordering::SeqCst);
if completed > 0 {
if let Some(started) = self.get_started() {
let mult = 1. / self.current_progress_frac();
let elapsed = started.elapsed();
let est_end = elapsed * mult;
if let Ok(mut remaining) = self.inner.remaining.write() {
*remaining = est_end - elapsed;
}
}
}
}
pub fn mark_all_completed(&self) {
self.inner
.counter
.store(self.max_elements(), Ordering::SeqCst);
if let Ok(mut remaining) = self.inner.remaining.write() {
*remaining = Duration::default();
}
self.mark_ended();
}
pub fn mark_some_completed(&self, completed: u64) {
self.inner.counter.fetch_add(completed, Ordering::SeqCst);
self.update_remaining()
}
pub fn get_remaining_time(&self) -> Duration {
if let Ok(remaining) = self.inner.remaining.read() {
return *remaining;
}
Duration::default()
}
pub fn mark_started(&self) {
let _res = self.inner.started.set(UnixTimestamp::now());
}
#[must_use]
pub fn get_ended(&self) -> Option<&UnixTimestamp> {
self.inner.ended.get()
}
pub fn mark_ended(&self) {
let _res = self.inner.ended.set(UnixTimestamp::now());
}
#[must_use]
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)
}
pub fn clean_completed_children(&self) -> Vec<Task> {
if let Ok(mut write) = self.inner.children.write() {
return write.retain_take(Task::is_complete);
}
vec![]
}
#[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 push_new_child_task(&self, task: Task) {
let write = self.inner.children.write();
if let Ok(mut write) = write {
write.push(task)
}
}
#[must_use]
pub fn is_complete(&self) -> bool {
self.inner.ended.get().is_some() || self.current_progress_frac() >= 1.
}
pub fn cancel(&self) {
self.cancelled.store(true, Ordering::Relaxed);
self.each_child(|ch| {
ch.cancel();
})
}
#[must_use]
pub fn is_cancelled(&self) -> bool {
self.cancelled.load(Ordering::Relaxed)
}
#[must_use]
pub fn current_status(&self) -> Option<Arc<String>> {
self.inner.current_status.get()
}
pub fn set_current_status<T: AsRef<str>>(&self, status: Option<T>) {
let _res = self
.inner
.current_status
.set(status.map(|v| v.as_ref().to_string()));
}
}
#[macro_export]
macro_rules! get_human {
($inp:ident) => {{
let temp = ((1. + $inp).log10() / 3.) as u32;
let chr = match temp {
0 => "",
1 => "K",
2 => "M",
3 => "G",
4 => "T",
5 => "P",
6 => "E",
_ => "?",
};
let inp = $inp / 10f64.powf(3. * temp as f64);
(inp, chr)
}};
}