sftool_lib/
progress.rs

1//! 进度事件系统
2//!
3//! 这个模块定义了进度的结构化上下文与事件接口,便于在 CLI/GUI
4//! 等不同前端进行统一格式化与呈现。
5
6use std::sync::atomic::{AtomicI32, AtomicU64, Ordering};
7use std::sync::{Arc, Mutex};
8
9/// 进度条类型
10#[derive(Debug, Clone)]
11pub enum ProgressType {
12    /// 旋转进度条,用于不确定时长的操作
13    Spinner,
14    /// 条形进度条,用于有明确进度的操作
15    Bar { total: u64 },
16}
17
18/// Stub 下载阶段
19#[derive(Debug, Clone)]
20pub enum StubStage {
21    Start,
22    SignatureKey,
23    RamStub,
24}
25
26/// 整体擦除样式
27#[derive(Debug, Clone)]
28pub enum EraseFlashStyle {
29    Complete,
30    Addressed,
31}
32
33/// 区域擦除样式
34#[derive(Debug, Clone)]
35pub enum EraseRegionStyle {
36    LegacyFlashStartDecimalLength,
37    HexLength,
38    Range,
39}
40
41/// 进度操作类型
42#[derive(Debug, Clone)]
43pub enum ProgressOperation {
44    Connect,
45    DownloadStub {
46        stage: StubStage,
47    },
48    EraseFlash {
49        address: u32,
50        style: EraseFlashStyle,
51    },
52    EraseRegion {
53        address: u32,
54        len: u32,
55        style: EraseRegionStyle,
56    },
57    EraseAllRegions,
58    Verify {
59        address: u32,
60        len: u32,
61    },
62    CheckRedownload {
63        address: u32,
64        size: u64,
65    },
66    WriteFlash {
67        address: u32,
68        size: u64,
69    },
70    ReadFlash {
71        address: u32,
72        size: u32,
73    },
74}
75
76/// 进度上下文
77#[derive(Debug, Clone)]
78pub struct ProgressContext {
79    /// 步骤号
80    pub step: i32,
81    /// 进度条类型
82    pub progress_type: ProgressType,
83    /// 操作语义
84    pub operation: ProgressOperation,
85    /// 当前进度(仅对 Bar 类型有效)
86    pub current: Option<u64>,
87}
88
89/// 进度条 ID 类型
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
91pub struct ProgressId(pub u64);
92
93/// 进度完成状态
94#[derive(Debug, Clone)]
95pub enum ProgressStatus {
96    Success,
97    Retry,
98    Skipped,
99    Required,
100    NotFound,
101    Failed(String),
102    Aborted,
103}
104
105/// 进度事件
106#[derive(Debug, Clone)]
107pub enum ProgressEvent {
108    Start {
109        id: ProgressId,
110        ctx: ProgressContext,
111    },
112    Update {
113        id: ProgressId,
114        ctx: ProgressContext,
115    },
116    Advance {
117        id: ProgressId,
118        delta: u64,
119    },
120    Finish {
121        id: ProgressId,
122        status: ProgressStatus,
123    },
124}
125
126/// 进度事件接收器
127pub trait ProgressSink: Send + Sync {
128    fn on_event(&self, event: ProgressEvent);
129}
130
131/// 进度事件接收器的包装器
132pub type ProgressSinkArc = Arc<dyn ProgressSink>;
133
134/// 默认的空进度接收器实现
135#[derive(Debug, Default)]
136pub struct NoOpProgressSink;
137
138impl ProgressSink for NoOpProgressSink {
139    fn on_event(&self, _event: ProgressEvent) {}
140}
141
142/// 创建默认的空进度接收器
143pub fn no_op_progress_sink() -> ProgressSinkArc {
144    Arc::new(NoOpProgressSink)
145}
146
147/// 进度助手结构体
148pub struct ProgressHelper {
149    sink: ProgressSinkArc,
150    step_counter: Arc<AtomicI32>,
151    id_counter: Arc<AtomicU64>,
152}
153
154impl ProgressHelper {
155    /// 创建新的进度助手,从指定的初始步骤开始
156    pub fn new(sink: ProgressSinkArc, initial_step: i32) -> Self {
157        Self {
158            sink,
159            step_counter: Arc::new(AtomicI32::new(initial_step)),
160            id_counter: Arc::new(AtomicU64::new(1)),
161        }
162    }
163
164    /// 获取下一个步骤号并递增计数器
165    fn next_step(&self) -> i32 {
166        self.step_counter.fetch_add(1, Ordering::SeqCst)
167    }
168
169    /// 获取下一个进度条 ID
170    fn next_id(&self) -> ProgressId {
171        ProgressId(self.id_counter.fetch_add(1, Ordering::SeqCst))
172    }
173
174    /// 创建一个旋转进度条
175    pub fn create_spinner(&self, operation: ProgressOperation) -> ProgressHandle {
176        let step = self.next_step();
177        let id = self.next_id();
178        let ctx = ProgressContext {
179            step,
180            progress_type: ProgressType::Spinner,
181            operation,
182            current: None,
183        };
184        self.sink.on_event(ProgressEvent::Start {
185            id,
186            ctx: ctx.clone(),
187        });
188        ProgressHandle::new(Arc::clone(&self.sink), id, ctx)
189    }
190
191    /// 创建一个条形进度条
192    pub fn create_bar(&self, total: u64, operation: ProgressOperation) -> ProgressHandle {
193        let step = self.next_step();
194        let id = self.next_id();
195        let ctx = ProgressContext {
196            step,
197            progress_type: ProgressType::Bar { total },
198            operation,
199            current: Some(0),
200        };
201        self.sink.on_event(ProgressEvent::Start {
202            id,
203            ctx: ctx.clone(),
204        });
205        ProgressHandle::new(Arc::clone(&self.sink), id, ctx)
206    }
207
208    /// 获取当前步骤号(不递增)
209    pub fn current_step(&self) -> i32 {
210        self.step_counter.load(Ordering::SeqCst)
211    }
212
213    /// 同步步骤计数器到外部计数器
214    pub fn sync_step_to_external(&self, external_step: &mut i32) {
215        *external_step = self.current_step();
216    }
217}
218
219/// 进度条处理器
220pub struct ProgressHandle {
221    sink: ProgressSinkArc,
222    id: ProgressId,
223    context: Mutex<ProgressContext>,
224    finished: bool,
225}
226
227impl ProgressHandle {
228    fn new(sink: ProgressSinkArc, id: ProgressId, context: ProgressContext) -> Self {
229        Self {
230            sink,
231            id,
232            context: Mutex::new(context),
233            finished: false,
234        }
235    }
236
237    /// 更新操作语义
238    pub fn set_operation(&self, operation: ProgressOperation) {
239        let mut ctx = self.context.lock().unwrap();
240        ctx.operation = operation;
241        self.sink.on_event(ProgressEvent::Update {
242            id: self.id,
243            ctx: ctx.clone(),
244        });
245    }
246
247    /// 增加进度
248    pub fn inc(&self, delta: u64) {
249        self.sink
250            .on_event(ProgressEvent::Advance { id: self.id, delta });
251    }
252
253    /// 完成进度条
254    pub fn finish(mut self, status: ProgressStatus) {
255        self.finished = true;
256        self.sink.on_event(ProgressEvent::Finish {
257            id: self.id,
258            status,
259        });
260    }
261}
262
263impl Drop for ProgressHandle {
264    fn drop(&mut self) {
265        if !self.finished {
266            self.sink.on_event(ProgressEvent::Finish {
267                id: self.id,
268                status: ProgressStatus::Aborted,
269            });
270        }
271    }
272}