use std::sync::atomic::{AtomicI32, AtomicU64, Ordering};
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone)]
pub enum ProgressType {
Spinner,
Bar { total: u64 },
}
#[derive(Debug, Clone)]
pub enum StubStage {
Start,
SignatureKey,
RamStub,
}
#[derive(Debug, Clone)]
pub enum EraseFlashStyle {
Complete,
Addressed,
}
#[derive(Debug, Clone)]
pub enum EraseRegionStyle {
LegacyFlashStartDecimalLength,
HexLength,
Range,
}
#[derive(Debug, Clone)]
pub enum ProgressOperation {
Connect,
DownloadStub {
stage: StubStage,
},
EraseFlash {
address: u32,
style: EraseFlashStyle,
},
EraseRegion {
address: u32,
len: u32,
style: EraseRegionStyle,
},
EraseAllRegions,
Verify {
address: u32,
len: u32,
},
CheckRedownload {
address: u32,
size: u64,
},
WriteFlash {
address: u32,
size: u64,
},
ReadFlash {
address: u32,
size: u32,
},
}
#[derive(Debug, Clone)]
pub struct ProgressContext {
pub step: i32,
pub progress_type: ProgressType,
pub operation: ProgressOperation,
pub current: Option<u64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ProgressId(pub u64);
#[derive(Debug, Clone)]
pub enum ProgressStatus {
Success,
Retry,
Skipped,
Required,
NotFound,
Failed(String),
Aborted,
}
#[derive(Debug, Clone)]
pub enum ProgressEvent {
Start {
id: ProgressId,
ctx: ProgressContext,
},
Update {
id: ProgressId,
ctx: ProgressContext,
},
Advance {
id: ProgressId,
delta: u64,
},
Finish {
id: ProgressId,
status: ProgressStatus,
},
}
pub trait ProgressSink: Send + Sync {
fn on_event(&self, event: ProgressEvent);
}
pub type ProgressSinkArc = Arc<dyn ProgressSink>;
#[derive(Debug, Default)]
pub struct NoOpProgressSink;
impl ProgressSink for NoOpProgressSink {
fn on_event(&self, _event: ProgressEvent) {}
}
pub fn no_op_progress_sink() -> ProgressSinkArc {
Arc::new(NoOpProgressSink)
}
pub struct ProgressHelper {
sink: ProgressSinkArc,
step_counter: Arc<AtomicI32>,
id_counter: Arc<AtomicU64>,
}
impl ProgressHelper {
pub fn new(sink: ProgressSinkArc, initial_step: i32) -> Self {
Self {
sink,
step_counter: Arc::new(AtomicI32::new(initial_step)),
id_counter: Arc::new(AtomicU64::new(1)),
}
}
fn next_step(&self) -> i32 {
self.step_counter.fetch_add(1, Ordering::SeqCst)
}
fn next_id(&self) -> ProgressId {
ProgressId(self.id_counter.fetch_add(1, Ordering::SeqCst))
}
pub fn create_spinner(&self, operation: ProgressOperation) -> ProgressHandle {
let step = self.next_step();
let id = self.next_id();
let ctx = ProgressContext {
step,
progress_type: ProgressType::Spinner,
operation,
current: None,
};
self.sink.on_event(ProgressEvent::Start {
id,
ctx: ctx.clone(),
});
ProgressHandle::new(Arc::clone(&self.sink), id, ctx)
}
pub fn create_bar(&self, total: u64, operation: ProgressOperation) -> ProgressHandle {
let step = self.next_step();
let id = self.next_id();
let ctx = ProgressContext {
step,
progress_type: ProgressType::Bar { total },
operation,
current: Some(0),
};
self.sink.on_event(ProgressEvent::Start {
id,
ctx: ctx.clone(),
});
ProgressHandle::new(Arc::clone(&self.sink), id, ctx)
}
pub fn current_step(&self) -> i32 {
self.step_counter.load(Ordering::SeqCst)
}
pub fn sync_step_to_external(&self, external_step: &mut i32) {
*external_step = self.current_step();
}
}
pub struct ProgressHandle {
sink: ProgressSinkArc,
id: ProgressId,
context: Mutex<ProgressContext>,
finished: bool,
}
impl ProgressHandle {
fn new(sink: ProgressSinkArc, id: ProgressId, context: ProgressContext) -> Self {
Self {
sink,
id,
context: Mutex::new(context),
finished: false,
}
}
pub fn set_operation(&self, operation: ProgressOperation) {
let mut ctx = self.context.lock().unwrap();
ctx.operation = operation;
self.sink.on_event(ProgressEvent::Update {
id: self.id,
ctx: ctx.clone(),
});
}
pub fn inc(&self, delta: u64) {
self.sink
.on_event(ProgressEvent::Advance { id: self.id, delta });
}
pub fn finish(mut self, status: ProgressStatus) {
self.finished = true;
self.sink.on_event(ProgressEvent::Finish {
id: self.id,
status,
});
}
}
impl Drop for ProgressHandle {
fn drop(&mut self) {
if !self.finished {
self.sink.on_event(ProgressEvent::Finish {
id: self.id,
status: ProgressStatus::Aborted,
});
}
}
}