Skip to content

Commit 6c5b85f

Browse files
committed
refactor(hm-common): generalize CompactDuration over Into<Duration>
Blanket-impl CompactDuration for any `T: Into<Duration>` instead of only `Duration`, so `DurationMs` (and any future duration newtype) gets `.compact()` for free — no dependency edge into hm-pipeline-ir, since the impl never names the concrete type. Render sites drop `Duration::from(*ms).compact()` back to `ms.compact()`.
1 parent c4726ee commit 6c5b85f

2 files changed

Lines changed: 14 additions & 12 deletions

File tree

‎crates/hm-common/src/format.rs‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ use core::time::Duration;
55

66
mod sealed {
77
pub trait Sealed {}
8-
impl Sealed for core::time::Duration {}
8+
impl<T: Into<core::time::Duration>> Sealed for T {}
99
}
1010

11-
/// Extension trait adding a compact, stopwatch-style [`Display`] rendering to
12-
/// [`std::time::Duration`].
11+
/// Adds a compact, stopwatch-style [`Display`] rendering to any duration.
12+
///
13+
/// Implemented for any type convertible into a [`std::time::Duration`] —
14+
/// including [`Duration`] itself and newtypes like `hm_pipeline_ir::DurationMs`.
1315
///
1416
/// ```
1517
/// # use hm_common::format::CompactDuration;
@@ -21,10 +23,11 @@ pub trait CompactDuration: sealed::Sealed {
2123
fn compact(self) -> StopwatchDurationDisplay;
2224
}
2325

24-
impl CompactDuration for Duration {
26+
impl<T: Into<Duration>> CompactDuration for T {
2527
fn compact(self) -> StopwatchDurationDisplay {
28+
let d: Duration = self.into();
2629
StopwatchDurationDisplay {
27-
total_ms: u64::try_from(self.as_millis()).unwrap_or(u64::MAX),
30+
total_ms: u64::try_from(d.as_millis()).unwrap_or(u64::MAX),
2831
}
2932
}
3033
}

‎crates/hm-render/src/progress.rs‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
use std::collections::HashMap;
1111
use std::fmt;
1212
use std::io::Write;
13-
use std::time::Duration;
1413

1514
use hm_plugin_protocol::ir::DurationMs;
1615

@@ -156,7 +155,7 @@ impl<W: Write> ProgressRenderer<W> {
156155
Some(StepOutcome::Succeeded { duration_ms }) => (
157156
styled("✓", Style::new().green(), self.color),
158157
styled(
159-
&Duration::from(*duration_ms).compact().to_string(),
158+
&duration_ms.compact().to_string(),
160159
Style::new().dimmed(),
161160
self.color,
162161
),
@@ -169,7 +168,7 @@ impl<W: Write> ProgressRenderer<W> {
169168
styled(
170169
&format!(
171170
"{} exit {exit_code}",
172-
Duration::from(*duration_ms).compact()
171+
duration_ms.compact()
173172
),
174173
Style::new().red(),
175174
self.color,
@@ -180,7 +179,7 @@ impl<W: Write> ProgressRenderer<W> {
180179
styled(
181180
&format!(
182181
"{} cancelled",
183-
Duration::from(*duration_ms).compact()
182+
duration_ms.compact()
184183
),
185184
Style::new().dimmed(),
186185
self.color,
@@ -306,7 +305,7 @@ where
306305
}
307306
} else if let Some(span) = self.step_spans.get(step_id) {
308307
let name = self.step_names.get(step_id).map_or("?", String::as_str);
309-
let dur = Duration::from(*duration_ms).compact();
308+
let dur = duration_ms.compact();
310309
span.pb_set_style(&completed_style(self.color));
311310
span.pb_set_message(&format!("{name} ({dur})"));
312311
}
@@ -351,15 +350,15 @@ where
351350

352351
if *exit_code != 0 {
353352
self.print_failure_report();
354-
let dur = Duration::from(*duration_ms).compact();
353+
let dur = duration_ms.compact();
355354
let msg = format!("✗ Build failed in {dur}");
356355
let _ = writeln!(
357356
self.out,
358357
"\n{}",
359358
styled(&msg, Style::new().red().bold(), self.color)
360359
);
361360
} else {
362-
let dur = Duration::from(*duration_ms).compact();
361+
let dur = duration_ms.compact();
363362
let msg = format!("✓ Build succeeded in {dur}");
364363
let _ = writeln!(
365364
self.out,

0 commit comments

Comments
 (0)