ralph_workflow/pipeline/
mod.rs1#![deny(unsafe_code)]
25
26mod clipboard;
27pub mod idle_timeout;
28pub mod logfile;
29mod prompt;
30mod types;
31
32pub use prompt::{run_with_prompt, PipelineRuntime, PromptCommand};
33pub use types::AgentPhaseGuard;
34
35use std::time::{Duration, Instant};
38
39#[derive(Clone)]
41pub struct Timer {
42 start_time: Instant,
43 phase_start: Instant,
44}
45
46impl Timer {
47 pub fn new() -> Self {
49 let now = Instant::now();
50 Self {
51 start_time: now,
52 phase_start: now,
53 }
54 }
55
56 pub fn start_phase(&mut self) {
58 self.phase_start = Instant::now();
59 }
60
61 pub fn elapsed(&self) -> Duration {
63 self.start_time.elapsed()
64 }
65
66 pub fn phase_elapsed(&self) -> Duration {
68 self.phase_start.elapsed()
69 }
70
71 pub fn format_duration(duration: Duration) -> String {
73 let total_secs = duration.as_secs();
74 let mins = total_secs / 60;
75 let secs = total_secs % 60;
76 format!("{mins}m {secs:02}s")
77 }
78
79 pub fn elapsed_formatted(&self) -> String {
81 Self::format_duration(self.elapsed())
82 }
83
84 pub fn phase_elapsed_formatted(&self) -> String {
86 Self::format_duration(self.phase_elapsed())
87 }
88}
89
90impl Default for Timer {
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96#[cfg(test)]
97mod timer_tests {
98 use super::*;
99 use std::thread;
100
101 #[test]
102 fn test_format_duration_zero() {
103 let d = Duration::from_secs(0);
104 assert_eq!(Timer::format_duration(d), "0m 00s");
105 }
106
107 #[test]
108 fn test_format_duration_seconds() {
109 let d = Duration::from_secs(30);
110 assert_eq!(Timer::format_duration(d), "0m 30s");
111 }
112
113 #[test]
114 fn test_format_duration_minutes() {
115 let d = Duration::from_secs(65);
116 assert_eq!(Timer::format_duration(d), "1m 05s");
117 }
118
119 #[test]
120 fn test_format_duration_large() {
121 let d = Duration::from_secs(3661);
122 assert_eq!(Timer::format_duration(d), "61m 01s");
123 }
124
125 #[test]
126 fn test_timer_elapsed() {
127 let timer = Timer::new();
128 thread::sleep(Duration::from_millis(10));
129 assert!(timer.elapsed() >= Duration::from_millis(10));
130 }
131
132 #[test]
133 fn test_timer_phase() {
134 let mut timer = Timer::new();
135 thread::sleep(Duration::from_millis(10));
136 timer.start_phase();
137 thread::sleep(Duration::from_millis(10));
138 assert!(timer.phase_elapsed() < timer.elapsed());
140 }
141}