1pub 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}