clock_timer/
lib.rs

1//! # Rust Time Utility Library
2//!
3//! This library provides two main utilities for time management:
4//! a `TimerStruct` for countdown timers and a `StopwatchStruct` for measuring elapsed time.
5
6
7/// Module for countdown timer functionalities.
8pub mod timer {
9    use std::{io::Write, thread, time::Duration};
10
11    /// Represents a countdown timer.
12    #[derive(Clone, Copy, Debug)]
13    pub struct TimerStruct {
14        /// The total duration of the timer in seconds.
15        pub duration: u32,
16        /// The initial hours component of the timer.
17        pub hours: u32,
18        /// The initial minutes component of the timer.
19        pub minutes: u32,
20        /// The initial seconds component of the timer.
21        pub seconds: u32,
22    }
23
24    impl TimerStruct {
25        /// Creates a new `TimerStruct` instance.
26        ///
27        /// # Arguments
28        ///
29        /// * `hours` - The hours component of the timer duration.
30        /// * `minutes` - The minutes component of the timer duration.
31        /// * `seconds` - The seconds component of the timer duration.
32        ///
33        /// # Returns
34        ///
35        /// * `Ok(TimerStruct)` if the total duration calculated from `hours`, `minutes`,
36        ///   and `seconds` is greater than 0.
37        /// * `Err("Duration need to be 1 or more seconds.")` if the total duration is 0.
38        ///
39        /// # Examples
40        ///
41        /// ```
42        /// use your_crate_name::TimerStruct; // Replace your_crate_name with your actual crate name
43        ///
44        /// let timer = TimerStruct::new(0, 1, 30).expect("Failed to create timer"); // 1 minute 30 seconds
45        /// let invalid_timer = TimerStruct::new(0, 0, 0); // This will return an Err
46        /// ```
47        pub fn new(hours: u32, minutes: u32, seconds: u32) -> Result<TimerStruct, &'static str> {
48            let duration = (hours * 3600) + (minutes * 60) + seconds;
49
50            if duration == 0 {
51                return Err("Duration need to be 1 or more seconds.");
52            }
53
54            Ok(TimerStruct {
55                duration,
56                hours,
57                minutes,
58                seconds,
59            })
60        }
61
62        /// Starts the countdown timer.
63        ///
64        /// The timer will print the remaining time to the provided writer every second,
65        /// overwriting the previous line. When the timer reaches 0, it prints the final
66        /// `0:0:0` with a newline and stops.
67        ///
68        /// # Arguments
69        ///
70        /// * `writer` - A mutable reference to any type that implements the `std::io::Write`
71        ///              trait (e.g., `&mut std::io::Stdout`).
72        ///
73        /// # Examples
74        ///
75        /// ```
76        /// use your_crate_name::TimerStruct; // Replace your_crate_name with your actual crate name
77        /// use std::io::{self, stdout};
78        ///
79        /// let timer = TimerStruct::new(0, 0, 5).unwrap(); // 5-second timer
80        /// let mut writer = stdout();
81        /// timer.start_timer(&mut writer);
82        /// println!("Timer finished!");
83        /// ```
84        pub fn start_timer<W: Write>(&self, writer: &mut W) {
85            let mut current_duration = self.duration;
86            let one_second = Duration::from_secs(1);
87
88            loop {
89                // Calculate display components from the current total duration
90                let display_hours = current_duration / 3600;
91                let remaining_seconds_after_hours = current_duration % 3600;
92                let display_minutes = remaining_seconds_after_hours / 60;
93                let display_seconds = remaining_seconds_after_hours % 60;
94
95                let time_display_string =
96                    format!("{}:{}:{}", display_hours, display_minutes, display_seconds);
97
98                if current_duration == 0 {
99                    // If duration is 0, this is the final display. Print with a newline and break.
100                    writeln!(writer, "{}", time_display_string).unwrap();
101                    break;
102                } else {
103                    // For all other durations, print with a carriage return to overwrite the line.
104                    write!(writer, "{}\r", time_display_string).unwrap();
105                    writer.flush().unwrap(); // Ensure the output is flushed immediately
106                }
107
108                thread::sleep(one_second);
109                current_duration -= 1;
110            }
111        }
112    }
113}
114
115/// Re-exports `TimerStruct` from the `timer` module for easier access.
116pub use timer::TimerStruct;
117
118/// Module for stopwatch functionalities.
119pub mod stopwatch {
120    use std::{io::Write,thread, time::Duration};
121
122    /// Represents the current status of the stopwatch.
123    #[derive(Clone, Debug)]
124    pub enum StopwatchStatus {
125        /// The stopwatch is currently stopped.
126        Stopped,
127        /// The stopwatch is currently running.
128        Running,
129    }
130
131    /// Represents a stopwatch that measures elapsed time.
132    ///
133    /// It takes a generic type `T` which must be a closure that accepts a `u32`
134    /// (the final `current_time` when the stopwatch stops).
135    #[derive(Debug, Clone)]
136    pub struct StopwatchStruct<T>
137    where T: Fn(u32),
138    {
139        /// The current elapsed time in seconds.
140        pub current_time: u32,
141        /// The current status of the stopwatch (Running or Stopped).
142        pub status: StopwatchStatus,
143        /// A closure that will be executed when the stopwatch is stopped.
144        /// It receives the final `current_time` as an argument.
145        pub operation_on_stop: T,
146    }
147
148    impl<T> StopwatchStruct<T>
149    where T: Fn(u32),
150    {
151        /// Creates a new `StopwatchStruct` instance.
152        ///
153        /// # Arguments
154        ///
155        /// * `operation_on_stop` - A closure that will be called when the stopwatch status
156        ///   is set to `Stopped`. It receives the total elapsed time in seconds as its argument.
157        ///
158        /// # Returns
159        ///
160        /// A new `StopwatchStruct` initialized with `current_time` at 0 and `status` as `Running`.
161        ///
162        /// # Examples
163        ///
164        /// ```
165        /// use your_crate_name::stopwatch::{StopwatchStruct, StopwatchStatus}; // Replace your_crate_name
166        ///
167        /// let mut stopwatch = StopwatchStruct::new(|time| {
168        ///     println!("Stopwatch stopped at {} seconds.", time);
169        /// });
170        /// ```
171        pub fn new(operation_on_stop: T) -> StopwatchStruct<T> {
172            StopwatchStruct {
173                current_time: 0,
174                status: StopwatchStatus::Running,
175                operation_on_stop,
176            }
177        }
178
179        /// Starts the stopwatch.
180        ///
181        /// The stopwatch will increment its `current_time` every second and print the elapsed time
182        /// to the provided writer, overwriting the previous line. The loop continues indefinitely
183        /// until the `status` field of the `StopwatchStruct` is manually set to `StopwatchStatus::Stopped`
184        /// from outside this function (e.g., from another thread or an external signal).
185        ///
186        /// # Arguments
187        ///
188        /// * `writer` - A mutable reference to any type that implements the `std::io::Write`
189        ///              trait (e.g., `&mut std::io::Stdout`).
190        ///
191        /// # Examples
192        ///
193        /// ```
194        /// use your_crate_name::stopwatch::{StopwatchStruct, StopwatchStatus}; // Replace your_crate_name
195        /// use std::{io::stdout, thread, time::Duration};
196        ///
197        /// let mut stopwatch = StopwatchStruct::new(|time| {
198        ///     println!("\nStopwatch finished at {} seconds!", time);
199        /// });
200        ///
201        /// let mut writer = stdout();
202        ///
203        /// // To stop the stopwatch, you would typically change its status from another thread
204        /// // or based on some external event. For demonstration, we'll do it after a delay.
205        /// let mut stopwatch_clone = stopwatch.clone(); // Clone to move into another thread
206        /// thread::spawn(move || {
207        ///     thread::sleep(Duration::from_secs(5));
208        ///     stopwatch_clone.status = StopwatchStatus::Stopped; // Stop after 5 seconds
209        /// });
210        ///
211        /// stopwatch.start_timer(&mut writer);
212        /// println!("Stopwatch loop ended.");
213        /// ```
214        pub fn start_timer<W: Write>(&mut self, writer: &mut W) {
215            loop {
216                match self.status {
217                    StopwatchStatus::Stopped => {
218                        (self.operation_on_stop)(self.current_time);
219                        break;
220                    },
221                    StopwatchStatus::Running => (),
222                }
223 
224                let hours = self.current_time / 3600;
225                let mut remaining = self.current_time % 3600;
226                let minutes = remaining / 60;
227                remaining %= 60;
228                
229                let output_format = format!("{}:{}:{}", hours, minutes, remaining);
230       
231                if self.current_time == 0 {
232                    write!(writer, "{}", output_format).unwrap();
233                }
234
235                thread::sleep(Duration::from_secs(1));
236
237                self.current_time += 1;
238
239                write!(writer, "{}\r", output_format).unwrap();
240
241                writer.flush().unwrap();
242            }    
243        }
244
245        pub fn stop_timer(seconds: u32, reference: &mut StopwatchStruct<T>)
246        where T: Fn(u32), 
247        {
248            let duration = Duration::from_secs(seconds.into());
249            thread::sleep(duration);
250            reference.status = StopwatchStatus::Stopped; 
251        }
252    }
253}