sftool_lib/
progress.rs

1//! 进度条回调系统
2//!
3//! 这个模块定义了进度条的抽象接口,允许用户在不同环境(CLI、GUI等)中
4//! 自定义进度条的显示方式。
5
6use std::sync::Arc;
7
8/// 进度条类型
9#[derive(Debug, Clone)]
10pub enum ProgressType {
11    /// 旋转进度条,用于不确定时长的操作
12    Spinner,
13    /// 条形进度条,用于有明确进度的操作
14    Bar { total: u64 },
15}
16
17/// 进度条状态
18#[derive(Debug, Clone)]
19pub struct ProgressInfo {
20    /// 进度条类型
21    pub progress_type: ProgressType,
22    /// 步骤前缀(通常是十六进制步骤号)
23    pub prefix: String,
24    /// 当前消息
25    pub message: String,
26    /// 当前进度(仅对 Bar 类型有效)
27    pub current: Option<u64>,
28}
29
30/// 进度回调 trait
31///
32/// 实现此 trait 以自定义进度条的显示方式
33pub trait ProgressCallback: Send + Sync {
34    /// 开始一个新的进度条
35    ///
36    /// # 参数
37    /// - `info`: 进度条信息
38    ///
39    /// # 返回值
40    /// 返回一个进度条 ID,用于后续的更新和完成操作
41    fn start(&self, info: ProgressInfo) -> ProgressId;
42
43    /// 更新进度条的消息
44    ///
45    /// # 参数
46    /// - `id`: 进度条 ID
47    /// - `message`: 新的消息
48    fn update_message(&self, id: ProgressId, message: String);
49
50    /// 增加进度(仅对 Bar 类型有效)
51    ///
52    /// # 参数
53    /// - `id`: 进度条 ID
54    /// - `delta`: 增加的进度量
55    fn increment(&self, id: ProgressId, delta: u64);
56
57    /// 完成进度条
58    ///
59    /// # 参数
60    /// - `id`: 进度条 ID
61    /// - `final_message`: 最终消息
62    fn finish(&self, id: ProgressId, final_message: String);
63}
64
65/// 进度条 ID 类型
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
67pub struct ProgressId(pub u64);
68
69/// 默认的空进度回调实现
70///
71/// 这个实现不会产生任何输出,适用于不需要进度显示的场景
72#[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
87/// 进度回调的包装器,便于使用
88pub type ProgressCallbackArc = Arc<dyn ProgressCallback>;
89
90/// 创建默认的空进度回调
91pub fn no_op_progress_callback() -> ProgressCallbackArc {
92    Arc::new(NoOpProgressCallback)
93}
94
95/// 进度条助手结构体
96///
97/// 提供便捷的方法来创建和管理进度条
98pub struct ProgressHelper {
99    callback: ProgressCallbackArc,
100    step_counter: Arc<std::sync::atomic::AtomicI32>,
101}
102
103impl ProgressHelper {
104    /// 创建新的进度助手,从指定的初始步骤开始
105    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    /// 获取下一个步骤号并递增计数器
113    fn next_step(&self) -> i32 {
114        self.step_counter
115            .fetch_add(1, std::sync::atomic::Ordering::SeqCst)
116    }
117
118    /// 创建一个旋转进度条
119    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    /// 创建一个条形进度条
135    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    /// 获取当前步骤号(不递增)
151    pub fn current_step(&self) -> i32 {
152        self.step_counter.load(std::sync::atomic::Ordering::SeqCst)
153    }
154
155    /// 同步步骤计数器到外部计数器
156    /// 这个方法用于将内部计数器的值同步到工具的 step 字段
157    pub fn sync_step_to_external(&self, external_step: &mut i32) {
158        *external_step = self.current_step();
159    }
160}
161
162/// 进度条处理器
163///
164/// 用于操作单个进度条实例
165pub struct ProgressHandler {
166    callback: ProgressCallbackArc,
167    id: ProgressId,
168}
169
170impl ProgressHandler {
171    /// 更新消息
172    pub fn set_message(&self, message: impl Into<String>) {
173        self.callback.update_message(self.id, message.into());
174    }
175
176    /// 增加进度
177    pub fn inc(&self, delta: u64) {
178        self.callback.increment(self.id, delta);
179    }
180
181    /// 完成进度条
182    pub fn finish_with_message(self, message: impl Into<String>) {
183        self.callback.finish(self.id, message.into());
184    }
185}