shell_rs/
sleep.rs

1// Copyright (c) 2021 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
2// Use of this source is governed by Apache-2.0 License that can be found
3// in the LICENSE file.
4
5use std::thread;
6use std::time::Duration;
7
8use super::error::{Error, ErrorKind};
9
10/// Pause for `number` seconds.
11///
12/// `number` may have suffix. Suffix may be 's' for seconds (the default), 'm' for minutes,
13/// 'h' for hours or 'd' for days.
14/// `number` need not be an integer.
15///
16/// Given two or more arguments, pause for the amount of time specified by the sum of their values.
17pub fn sleep(number: &str) -> Result<(), Error> {
18    let time = parse_time(number)?;
19    thread::sleep(time);
20    Ok(())
21}
22
23fn parse_time(time: &str) -> Result<Duration, Error> {
24    let mut duration = Duration::new(0, 0);
25    for part in time.split_ascii_whitespace() {
26        let (has_suffix, multiple) = match part.chars().last() {
27            Some('s') => (true, 1),
28            Some('m') => (true, 60),
29            Some('h') => (true, 60 * 60),
30            Some('d') => (true, 24 * 60 * 60),
31            _ => (false, 1),
32        };
33
34        let interval = if has_suffix {
35            part.split_at(part.len() - 1).0
36        } else {
37            part
38        };
39        if let Ok(secs) = str::parse::<u64>(interval) {
40            duration += Duration::from_secs(secs * multiple);
41        } else {
42            return Err(Error::from_string(
43                ErrorKind::ParameterError,
44                format!("Invalid time interval `{:?}`", part),
45            ));
46        }
47    }
48
49    Ok(duration)
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn test_parse_time() {
58        assert_eq!(parse_time(" 3 \n").unwrap(), Duration::from_secs(3));
59        assert_eq!(parse_time("3").unwrap(), Duration::from_secs(3));
60        assert_eq!(parse_time("3s").unwrap(), Duration::from_secs(3));
61        assert_eq!(parse_time("3s 4").unwrap(), Duration::from_secs(7));
62        assert_eq!(
63            parse_time("3s 4m").unwrap(),
64            Duration::from_secs(3 + 4 * 60)
65        );
66
67        assert!(parse_time("3s 4a").is_err());
68    }
69}