use std::{
fmt::{Debug, Display},
time::Duration,
};
use crate::DriverError;
#[derive(Debug, Clone)]
pub(crate) enum Progress {
Failed(DriverError),
Converged,
InProgressPercentage(f64),
#[allow(clippy::enum_variant_names)]
InProgress,
NotStarted,
}
impl Default for Progress {
fn default() -> Self {
Self::NotStarted
}
}
#[derive(Debug, Default, Clone)]
pub struct Step {
pub(crate) iteration: usize,
pub(crate) elapsed: Duration,
pub(crate) elapsed_iter: Duration,
pub(crate) progress: Progress,
}
impl Display for Step {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "[{:>6}]", self.iteration())?;
write!(f, " [{}]", format_duration(self.elapsed()))?;
Ok(())
}
}
impl Step {
pub fn iteration(&self) -> usize {
self.iteration
}
pub fn elapsed(&self) -> Duration {
self.elapsed
}
pub fn elapsed_iter(&self) -> Duration {
self.elapsed_iter
}
pub fn progress_percentage(&self) -> Option<f64> {
match self.progress {
Progress::InProgressPercentage(p) => Some(p),
_ => None,
}
}
pub fn time_remaining(&self) -> Option<Duration> {
let progress = self.progress_percentage()?;
let secs = self.elapsed().as_secs_f64() * 100.0 / progress;
if secs.is_finite() {
Some(Duration::from_secs_f64(secs))
} else {
Some(Duration::ZERO)
}
}
}
pub fn format_duration(d: Duration) -> impl Display {
struct DurationDisplay(Duration);
impl Display for DurationDisplay {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let total_seconds = self.0.as_secs();
let millis = self.0.subsec_millis();
let hours = total_seconds / 3600;
let mins = (total_seconds % 3600) / 60;
let secs = total_seconds % 60;
write!(f, "{:02}:{:02}:{:02}.{:03}", hours, mins, secs, millis)
}
}
DurationDisplay(d)
}
#[cfg(test)]
mod tests {
use std::mem::size_of;
#[test]
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
fn step_sizes() {
assert_eq!(size_of::<Vec<f64>>(), 24);
}
}