Skip to main content

ralph_workflow/pipeline/timer/
io.rs

1// pipeline/timer/io.rs — boundary module for timer utilities.
2// File stem is `io` — recognized as boundary module by forbid_io_effects lint.
3
4// Timer utilities in the runtime boundary.
5//
6// This module provides time tracking capabilities that domain code can use.
7// Clock reading is isolated here to comply with functional programming rules.
8
9use std::cell::Cell;
10use std::time::{Duration, Instant};
11
12/// Timer for tracking execution duration with phase support.
13/// This is a boundary module - clock access is allowed here.
14///
15/// `phase_start` uses `Cell<Instant>` so `start_phase` can take `&self`,
16/// allowing non-boundary callers to reset the phase timer without holding
17/// `&mut Timer`.
18#[derive(Clone)]
19pub struct Timer {
20    start_time: Instant,
21    phase_start: Cell<Instant>,
22}
23
24impl Timer {
25    #[must_use]
26    pub fn new() -> Self {
27        let now = Instant::now();
28        Self {
29            start_time: now,
30            phase_start: Cell::new(now),
31        }
32    }
33
34    #[must_use]
35    pub fn from_timestamps(start_time: Instant, phase_start: Instant) -> Self {
36        Self {
37            start_time,
38            phase_start: Cell::new(phase_start),
39        }
40    }
41
42    pub fn start_phase(&self) {
43        self.phase_start.set(Instant::now());
44    }
45
46    #[must_use]
47    pub fn elapsed(&self) -> Duration {
48        self.start_time.elapsed()
49    }
50
51    #[must_use]
52    pub fn phase_elapsed(&self) -> Duration {
53        self.phase_start.get().elapsed()
54    }
55
56    #[must_use]
57    pub fn format_duration(duration: Duration) -> String {
58        let total_secs = duration.as_secs();
59        let mins = total_secs / 60;
60        let secs = total_secs % 60;
61        format!("{mins}m {secs:02}s")
62    }
63
64    #[must_use]
65    pub fn elapsed_formatted(&self) -> String {
66        Self::format_duration(self.elapsed())
67    }
68
69    #[must_use]
70    pub fn phase_elapsed_formatted(&self) -> String {
71        Self::format_duration(self.phase_elapsed())
72    }
73}
74
75impl Default for Timer {
76    fn default() -> Self {
77        Self::new()
78    }
79}