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}