use crate::deps::Duration;
#[derive(Debug, Clone)]
pub struct ProgressEvent {
pub current: u64,
pub total: u64,
pub message: String,
pub elapsed: Duration,
pub eta: Option<Duration>,
pub finished: bool,
}
impl ProgressEvent {
pub fn percentage(&self) -> f64 {
if self.total == 0 {
return 0.0;
}
(self.current as f64 / self.total as f64) * 100.0
}
pub fn ratio(&self) -> f64 {
if self.total == 0 {
return 0.0;
}
self.current as f64 / self.total as f64
}
pub fn message(&self) -> &str {
&self.message
}
pub fn is_finished(&self) -> bool {
self.finished
}
pub fn rate(&self) -> f64 {
let secs = self.elapsed.as_secs_f64();
if secs == 0.0 {
return 0.0;
}
self.current as f64 / secs
}
pub fn to_string_human(&self) -> String {
let pct = self.percentage();
let rate = self.rate();
let eta_str = match self.eta {
Some(eta) => format_duration(eta),
None => "计算中...".to_string(),
};
if self.finished {
format!(
"✓ 完成 {}/{} (用时: {})",
self.current,
self.total,
format_duration(self.elapsed)
)
} else {
format!(
"{:.1}% ({}/{}) - {:.1}/s - ETA: {} - {}",
pct, self.current, self.total, rate, eta_str, self.message
)
}
}
}
fn format_duration(d: Duration) -> String {
let secs = d.as_secs();
if secs < 60 {
format!("{}s", secs)
} else if secs < 3600 {
format!("{}m {}s", secs / 60, secs % 60)
} else {
format!("{}h {}m", secs / 3600, (secs % 3600) / 60)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_percentage() {
let event = ProgressEvent {
current: 50,
total: 100,
message: "test".to_string(),
elapsed: Duration::from_secs(10),
eta: Some(Duration::from_secs(10)),
finished: false,
};
assert!((event.percentage() - 50.0).abs() < 0.001);
}
#[test]
fn test_ratio() {
let event = ProgressEvent {
current: 25,
total: 100,
message: "test".to_string(),
elapsed: Duration::from_secs(5),
eta: None,
finished: false,
};
assert!((event.ratio() - 0.25).abs() < 0.001);
}
#[test]
fn test_rate() {
let event = ProgressEvent {
current: 100,
total: 200,
message: "test".to_string(),
elapsed: Duration::from_secs(10),
eta: None,
finished: false,
};
assert!((event.rate() - 10.0).abs() < 0.001);
}
}