1use std::sync::Arc;
7
8#[derive(Debug, Clone)]
10pub enum ProgressType {
11 Spinner,
13 Bar { total: u64 },
15}
16
17#[derive(Debug, Clone)]
19pub struct ProgressInfo {
20 pub progress_type: ProgressType,
22 pub prefix: String,
24 pub message: String,
26 pub current: Option<u64>,
28}
29
30pub trait ProgressCallback: Send + Sync {
34 fn start(&self, info: ProgressInfo) -> ProgressId;
42
43 fn update_message(&self, id: ProgressId, message: String);
49
50 fn increment(&self, id: ProgressId, delta: u64);
56
57 fn finish(&self, id: ProgressId, final_message: String);
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub struct ProgressId(pub u64);
68
69#[derive(Debug, Default)]
73pub struct NoOpProgressCallback;
74
75impl ProgressCallback for NoOpProgressCallback {
76 fn start(&self, _info: ProgressInfo) -> ProgressId {
77 ProgressId(0)
78 }
79
80 fn update_message(&self, _id: ProgressId, _message: String) {}
81
82 fn increment(&self, _id: ProgressId, _delta: u64) {}
83
84 fn finish(&self, _id: ProgressId, _final_message: String) {}
85}
86
87pub type ProgressCallbackArc = Arc<dyn ProgressCallback>;
89
90pub fn no_op_progress_callback() -> ProgressCallbackArc {
92 Arc::new(NoOpProgressCallback)
93}
94
95pub struct ProgressHelper {
99 callback: ProgressCallbackArc,
100 step_counter: Arc<std::sync::atomic::AtomicI32>,
101}
102
103impl ProgressHelper {
104 pub fn new(callback: ProgressCallbackArc, initial_step: i32) -> Self {
106 Self {
107 callback,
108 step_counter: Arc::new(std::sync::atomic::AtomicI32::new(initial_step)),
109 }
110 }
111
112 fn next_step(&self) -> i32 {
114 self.step_counter
115 .fetch_add(1, std::sync::atomic::Ordering::SeqCst)
116 }
117
118 pub fn create_spinner(&self, message: impl Into<String>) -> ProgressHandler {
120 let step = self.next_step();
121 let info = ProgressInfo {
122 progress_type: ProgressType::Spinner,
123 prefix: format!("0x{:02X}", step),
124 message: message.into(),
125 current: None,
126 };
127 let id = self.callback.start(info);
128 ProgressHandler {
129 callback: Arc::clone(&self.callback),
130 id,
131 }
132 }
133
134 pub fn create_bar(&self, total: u64, message: impl Into<String>) -> ProgressHandler {
136 let step = self.next_step();
137 let info = ProgressInfo {
138 progress_type: ProgressType::Bar { total },
139 prefix: format!("0x{:02X}", step),
140 message: message.into(),
141 current: Some(0),
142 };
143 let id = self.callback.start(info);
144 ProgressHandler {
145 callback: Arc::clone(&self.callback),
146 id,
147 }
148 }
149
150 pub fn current_step(&self) -> i32 {
152 self.step_counter.load(std::sync::atomic::Ordering::SeqCst)
153 }
154
155 pub fn sync_step_to_external(&self, external_step: &mut i32) {
158 *external_step = self.current_step();
159 }
160}
161
162pub struct ProgressHandler {
166 callback: ProgressCallbackArc,
167 id: ProgressId,
168}
169
170impl ProgressHandler {
171 pub fn set_message(&self, message: impl Into<String>) {
173 self.callback.update_message(self.id, message.into());
174 }
175
176 pub fn inc(&self, delta: u64) {
178 self.callback.increment(self.id, delta);
179 }
180
181 pub fn finish_with_message(self, message: impl Into<String>) {
183 self.callback.finish(self.id, message.into());
184 }
185}