soar_utils/
time.rs

1/// Parses a duration string into a number of milliseconds.
2///
3/// This function takes a string in the format `1d1h1m1s` and parses it into
4/// a number of milliseconds. The string can contain any number of digits,
5/// followed by any combination of the letters `s`, `m`, `h`, and `d` to
6/// represent seconds, minutes, hours, and days, respectively.
7///
8/// # Arguments
9/// * `input` - A string in the format `1d1h1m1s1`.
10///
11/// # Returns
12/// A number of milliseconds, or `None` if the input string is invalid.
13/// If the integer overflows, the function returns `None`.
14///
15/// # Examples
16///
17/// ```
18/// use soar_utils::time::parse_duration;
19///
20/// let duration = parse_duration("1d1h1m1s");
21/// println!("Duration: {}", duration.unwrap());
22/// ```
23pub fn parse_duration(input: &str) -> Option<u128> {
24    let mut total: u128 = 0;
25    let mut chars = input.chars().peekable();
26
27    while chars.peek().is_some() {
28        let mut number_str = String::new();
29        while let Some(c) = chars.peek() {
30            if c.is_ascii_digit() {
31                number_str.push(chars.next()?);
32            } else {
33                break;
34            }
35        }
36
37        if number_str.is_empty() {
38            return None;
39        }
40
41        let number: u128 = number_str.parse().ok()?;
42        let multiplier = match chars.next()? {
43            's' => 1000,
44            'm' => 60 * 1000,
45            'h' => 60 * 60 * 1000,
46            'd' => 24 * 60 * 60 * 1000,
47            _ => return None,
48        };
49
50        total += number * multiplier;
51    }
52
53    Some(total)
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn test_parse_duration() {
62        assert_eq!(parse_duration("1s"), Some(1000));
63        assert_eq!(parse_duration("1m"), Some(60 * 1000));
64        assert_eq!(parse_duration("1h"), Some(60 * 60 * 1000));
65        assert_eq!(parse_duration("1d"), Some(24 * 60 * 60 * 1000));
66        assert_eq!(
67            parse_duration("1d1h"),
68            Some(24 * 60 * 60 * 1000 + 60 * 60 * 1000)
69        );
70        assert_eq!(
71            parse_duration("1d1h1m"),
72            Some(24 * 60 * 60 * 1000 + 60 * 60 * 1000 + 60 * 1000)
73        );
74        assert_eq!(
75            parse_duration("1d1h1m1s"),
76            Some(24 * 60 * 60 * 1000 + 60 * 60 * 1000 + 60 * 1000 + 1000)
77        );
78        assert_eq!(parse_duration("1d1h1m1s1"), None);
79        assert_eq!(parse_duration("1d1h1m1s1a"), None);
80        assert_eq!(parse_duration("fail"), None);
81        assert_eq!(parse_duration(""), Some(0));
82    }
83
84    #[test]
85    fn test_integer_overflow() {
86        assert_eq!(
87            parse_duration("340282366920938463463374607431768211456"),
88            None
89        );
90    }
91}