sleep_utils/smart_sleep.rs
1use crate::{parse_sleep_duration, Result};
2use std::time::Duration;
3
4/// Smart sleep function that supports multiple input formats.
5///
6/// This function accepts various input types and automatically converts them
7/// to appropriate sleep durations. Zero and negative values result in no sleep.
8///
9/// # Supported Formats
10///
11/// - **Numbers**: `100`, `500` (interpreted as milliseconds)
12/// - **Text with units**: `"100ms"`, `"2s"`, `"1.5s"`, `"2 minutes"`
13/// - **Plain text**: `"100"` (interpreted as milliseconds)
14/// - **Duration objects**: `Duration::from_millis(100)`
15/// - **Zero/negative**: `0`, `-100` (no sleep performed)
16///
17/// # Examples
18///
19/// ```
20/// use sleep_utils::smart_sleep;
21///
22/// // Sleep for 100 milliseconds using a number
23/// smart_sleep(100).unwrap();
24///
25/// // Sleep for 200 milliseconds using text with units
26/// smart_sleep("200ms").unwrap();
27///
28/// // Sleep for 1.5 seconds
29/// smart_sleep("1.5s").unwrap();
30///
31/// // Sleep for 2 seconds with full unit name
32/// smart_sleep("2 seconds").unwrap();
33///
34/// // No sleep for zero values
35/// smart_sleep(0).unwrap();
36///
37/// // No sleep for negative values
38/// smart_sleep(-100).unwrap();
39/// ```
40///
41/// # Errors
42///
43/// Returns [`SleepError::InvalidDuration`] if the input string cannot be parsed
44/// as a valid duration.
45///
46/// # Panics
47///
48/// This function does not panic. All errors are returned as [`Result`].
49pub fn smart_sleep<S>(input: S) -> Result<()>
50where
51 S: Into<SleepInput>,
52{
53 let sleep_input = input.into();
54
55 if sleep_input.should_sleep() {
56 let duration = sleep_input.to_duration()?;
57 std::thread::sleep(duration);
58 }
59
60 Ok(())
61}
62
63/// Represents different types of sleep inputs.
64///
65/// This enum allows the [`smart_sleep`] function to accept multiple input types
66/// through the [`Into<SleepInput>`] trait.
67///
68/// # Variants
69///
70/// - `Number(isize)`: Numeric input interpreted as milliseconds
71/// - `Text(String)`: String input that will be parsed for duration
72/// - `Duration(Duration)`: Standard duration object
73#[derive(Debug, Clone)]
74pub enum SleepInput {
75 /// Numeric input interpreted as milliseconds
76 Number(isize),
77 /// Text input that will be parsed for duration information
78 Text(String),
79 /// Standard duration object
80 Duration(Duration),
81}
82
83// Implement various From traits for seamless conversion
84impl From<i32> for SleepInput {
85 fn from(value: i32) -> Self {
86 SleepInput::Number(value as isize)
87 }
88}
89
90impl From<isize> for SleepInput {
91 fn from(value: isize) -> Self {
92 SleepInput::Number(value)
93 }
94}
95
96impl From<&str> for SleepInput {
97 fn from(value: &str) -> Self {
98 SleepInput::Text(value.to_string())
99 }
100}
101
102impl From<String> for SleepInput {
103 fn from(value: String) -> Self {
104 SleepInput::Text(value)
105 }
106}
107
108impl From<Duration> for SleepInput {
109 fn from(value: Duration) -> Self {
110 SleepInput::Duration(value)
111 }
112}
113
114impl SleepInput {
115 /// Determines whether sleep should be performed for this input.
116 ///
117 /// Returns `false` for zero or negative numeric values, allowing
118 /// the caller to skip sleep operations when appropriate.
119 ///
120 /// # Examples
121 ///
122 /// ```
123 /// use sleep_utils::SleepInput;
124 ///
125 /// let positive = SleepInput::from(100);
126 /// assert!(positive.should_sleep());
127 ///
128 /// let zero = SleepInput::from(0);
129 /// assert!(!zero.should_sleep());
130 ///
131 /// let negative = SleepInput::from(-50);
132 /// assert!(!negative.should_sleep());
133 /// ```
134 pub fn should_sleep(&self) -> bool {
135 match self {
136 SleepInput::Number(n) => *n > 0,
137 SleepInput::Text(text) => {
138 if let Ok(n) = text.parse::<isize>() {
139 n > 0
140 } else {
141 true
142 }
143 }
144 SleepInput::Duration(duration) => !duration.is_zero(),
145 }
146 }
147
148 /// Converts the input to a [`Duration`] object.
149 ///
150 /// For text inputs, this will parse the string using [`parse_sleep_duration`].
151 /// For numeric inputs, values are interpreted as milliseconds.
152 ///
153 /// # Errors
154 ///
155 /// Returns [`SleepError::InvalidDuration`] if text input cannot be parsed.
156 ///
157 /// # Examples
158 ///
159 /// ```
160 /// use sleep_utils::SleepInput;
161 /// use std::time::Duration;
162 ///
163 /// let input = SleepInput::from("100ms");
164 /// let duration = input.to_duration().unwrap();
165 /// assert_eq!(duration, Duration::from_millis(100));
166 /// ```
167 pub fn to_duration(&self) -> Result<Duration> {
168 match self {
169 SleepInput::Number(n) => {
170 if *n <= 0 {
171 Ok(Duration::ZERO)
172 } else {
173 Ok(Duration::from_millis(*n as u64))
174 }
175 }
176 SleepInput::Text(text) => parse_sleep_duration(text),
177 SleepInput::Duration(duration) => Ok(*duration),
178 }
179 }
180}