use std::sync::{
Arc,
atomic::{AtomicBool, AtomicU64},
};
use compact_str::CompactString;
use parking_lot::RwLock;
use web_time::Instant;
use crate::progress::{Cold, Progress, ProgressType};
#[derive(Default)]
pub struct ProgressBuilder {
kind: ProgressType,
name: CompactString,
start: Option<Instant>,
total: u64,
atomic_pos: Option<Arc<AtomicU64>>,
atomic_total: Option<Arc<AtomicU64>>,
atomic_finished: Option<Arc<AtomicBool>>,
}
impl ProgressBuilder {
#[must_use]
pub fn new_bar(name: impl Into<CompactString>, total: impl Into<u64>) -> Self {
Self {
kind: ProgressType::Bar,
name: name.into(),
total: total.into(),
..Default::default()
}
}
#[must_use]
pub fn new_spinner(name: impl Into<CompactString>) -> Self {
Self {
kind: ProgressType::Spinner,
name: name.into(),
..Default::default()
}
}
#[must_use]
pub fn with_atomic_pos(mut self, atomic_pos: Arc<AtomicU64>) -> Self {
self.atomic_pos = Some(atomic_pos);
self
}
#[must_use]
pub fn with_atomic_total(mut self, atomic_total: Arc<AtomicU64>) -> Self {
self.atomic_total = Some(atomic_total);
self
}
#[must_use]
pub fn with_atomic_finished(mut self, atomic_finished: Arc<AtomicBool>) -> Self {
self.atomic_finished = Some(atomic_finished);
self
}
#[must_use]
pub const fn with_start_time(mut self, start: Instant) -> Self {
self.start = Some(start);
self
}
#[must_use]
pub fn with_start_time_now(self) -> Self {
self.with_start_time(Instant::now())
}
#[must_use]
pub fn build(self) -> Progress {
Progress {
kind: self.kind,
start: self.start,
cold: Arc::new(RwLock::new(Cold {
name: self.name,
stopped: None,
error: None,
})),
item: Arc::new(RwLock::new(CompactString::default())),
position: self
.atomic_pos
.unwrap_or_else(|| Arc::new(AtomicU64::new(0))),
total: self
.atomic_total
.unwrap_or_else(|| Arc::new(AtomicU64::new(self.total))),
finished: self
.atomic_finished
.unwrap_or_else(|| Arc::new(AtomicBool::new(false))),
}
}
}
#[cfg(test)]
mod tests {
use std::sync::{Arc, atomic::AtomicU64};
use super::ProgressBuilder;
#[test]
fn test_shared_atomics() {
let shared_pos = Arc::new(AtomicU64::new(0));
let p1 = ProgressBuilder::new_bar("worker_1", 100u64)
.with_atomic_pos(shared_pos.clone())
.build();
let p2 = ProgressBuilder::new_bar("worker_2", 100u64)
.with_atomic_pos(shared_pos) .build();
p1.inc(10u64);
assert_eq!(
p2.get_pos(),
10,
"p2 should see p1's updates via shared atomic"
);
}
}