thedes_async_util/
progress.rs1use std::sync::{
2 Arc,
3 atomic::{AtomicUsize, Ordering::*},
4};
5
6pub fn open(goal: usize) -> (Logger, Monitor) {
7 let shared = Arc::new(Shared {
8 goal,
9 current: AtomicUsize::new(0),
10 status: std::sync::Mutex::new(Vec::new()),
11 });
12
13 let logger =
14 Logger { shared: shared.clone(), status_index: shared.enter() };
15 let monitor = Monitor { shared };
16
17 (logger, monitor)
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct Progress {
22 current: usize,
23 status: String,
24}
25
26impl Progress {
27 pub fn current(&self) -> usize {
28 self.current
29 }
30
31 pub fn status(&self) -> &str {
32 &self.status
33 }
34}
35
36#[derive(Debug)]
37struct Shared {
38 goal: usize,
39 current: AtomicUsize,
40 status: std::sync::Mutex<Vec<Option<Box<str>>>>,
41}
42
43impl Shared {
44 pub fn goal(&self) -> usize {
45 self.goal
46 }
47
48 pub fn read_status(&self) -> String {
49 let statuses = self.status.lock().expect("poisoned lock");
50 let mut status = String::new();
51
52 for maybe in &*statuses {
53 if let Some(item) = maybe {
54 if !status.is_empty() {
55 status += " > ";
56 }
57 status += item;
58 }
59 }
60
61 status
62 }
63
64 pub fn read_current(&self) -> usize {
65 self.current.load(Relaxed)
66 }
67
68 pub fn read(&self) -> Progress {
69 Progress { status: self.read_status(), current: self.read_current() }
70 }
71
72 pub fn increment(&self) {
73 self.current.fetch_add(1, Relaxed);
74 }
75
76 pub fn set_status(&self, index: usize, status: &str) {
77 self.status.lock().expect("poisoned lock")[index] = Some(status.into());
78 }
79
80 pub fn enter(&self) -> usize {
81 let mut statuses = self.status.lock().expect("poisoned lock");
82 let index = statuses.len();
83 statuses.push(Some(Box::default()));
84 index
85 }
86
87 pub fn leave(&self, index: usize) {
88 let mut statuses = self.status.lock().expect("poisoned lock");
89 statuses[index] = None;
90
91 while statuses.last().is_some_and(Option::is_none) {
92 statuses.pop();
93 }
94 }
95}
96
97#[derive(Debug, Clone)]
98pub struct Monitor {
99 shared: Arc<Shared>,
100}
101
102impl Monitor {
103 pub fn goal(&self) -> usize {
104 self.shared.goal()
105 }
106
107 pub fn read(&self) -> Progress {
108 self.shared.read()
109 }
110}
111
112#[derive(Debug)]
113pub struct Logger {
114 shared: Arc<Shared>,
115 status_index: usize,
116}
117
118impl Logger {
119 pub fn goal(&self) -> usize {
120 self.shared.goal()
121 }
122
123 pub fn read(&self) -> Progress {
124 self.shared.read()
125 }
126
127 pub fn increment(&self) {
128 self.shared.increment();
129 }
130
131 pub fn set_status(&self, status: &str) {
132 self.shared.set_status(self.status_index, status);
133 }
134
135 pub fn nest(&self) -> Logger {
136 Self { shared: self.shared.clone(), status_index: self.shared.enter() }
137 }
138}
139
140impl Drop for Logger {
141 fn drop(&mut self) {
142 self.shared.leave(self.status_index);
143 }
144}