sleep_utils/
duration_parser.rs1use crate::{Result, SleepError};
2use std::time::Duration;
3
4pub fn parse_sleep_duration(input: &str) -> Result<Duration> {
6 let input = input.trim().to_lowercase();
7
8 if input.is_empty() {
9 return Ok(Duration::ZERO);
10 }
11
12 if let Ok(millis) = input.parse::<isize>() {
14 if millis <= 0 {
15 return Ok(Duration::ZERO);
16 }
17 return Ok(Duration::from_millis(millis as u64));
18 }
19
20 if let Some(duration) = parse_duration_with_unit(&input)? {
22 Ok(duration)
23 } else {
24 Err(SleepError::InvalidDuration(format!(
25 "Invalid sleep duration format: '{}'",
26 input
27 )))
28 }
29}
30
31fn parse_duration_with_unit(input: &str) -> Result<Option<Duration>> {
33 use lazy_static::lazy_static;
34 use regex::Regex;
35
36 lazy_static! {
37 static ref PATTERNS: Vec<(&'static str, f64)> = vec![
38 (r"^(\d+)\s*(ms|millis?|milliseconds?)$", 1.0),
40 (r"^(\d+)\s*(s|sec|seconds?)$", 1000.0),
42 (r"^(\d+)\s*(m|min|minutes?)$", 60_000.0),
44 (r"^(\d+)(ms)$", 1.0),
46 (r"^(\d+)(s)$", 1000.0),
47 (r"^(\d+)(m)$", 60_000.0),
48 ];
49
50 static ref FLOAT_PATTERNS: Vec<(&'static str, f64)> = vec![
51 (r"^(\d*\.?\d+)\s*(s|sec|seconds?)$", 1000.0),
52 (r"^(\d*\.?\d+)\s*(m|min|minutes?)$", 60_000.0),
53 (r"^(\d*\.?\d+)(s)$", 1000.0),
54 (r"^(\d*\.?\d+)(m)$", 60_000.0),
55 ];
56 }
57
58 for (pattern, multiplier) in PATTERNS.iter() {
59 let re = Regex::new(pattern).unwrap();
60 if let Some(caps) = re.captures(input) {
61 if let Ok(value) = caps[1].parse::<isize>() {
62 if value <= 0 {
63 return Ok(Some(Duration::ZERO));
64 }
65 let millis = (value as f64 * multiplier) as u64;
66 return Ok(Some(Duration::from_millis(millis)));
67 }
68 }
69 }
70
71 for (pattern, multiplier) in FLOAT_PATTERNS.iter() {
72 let re = Regex::new(pattern).unwrap();
73 if let Some(caps) = re.captures(input) {
74 if let Ok(value) = caps[1].parse::<f64>() {
75 if value <= 0.0 {
76 return Ok(Some(Duration::ZERO));
77 }
78 let millis = (value * multiplier) as u64;
79 return Ok(Some(Duration::from_millis(millis)));
80 }
81 }
82 }
83
84 Ok(None)
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_parse_sleep_duration() -> Result<()> {
93 assert_eq!(parse_sleep_duration("100")?, Duration::from_millis(100));
94 assert_eq!(parse_sleep_duration("100ms")?, Duration::from_millis(100));
95 assert_eq!(parse_sleep_duration("1s")?, Duration::from_secs(1));
96 assert_eq!(parse_sleep_duration("1.5s")?, Duration::from_millis(1500));
97 assert_eq!(parse_sleep_duration("0")?, Duration::ZERO);
98 Ok(())
99 }
100}