shell-rs 0.2.6

Rust reimplementation of common coreutils APIs
Documentation
// Copyright (c) 2021 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
// Use of this source is governed by Apache-2.0 License that can be found
// in the LICENSE file.

use std::thread;
use std::time::Duration;

use super::error::{Error, ErrorKind};

/// Pause for `number` seconds.
///
/// `number` may have suffix. Suffix may be 's' for seconds (the default), 'm' for minutes,
/// 'h' for hours or 'd' for days.
/// `number` need not be an integer.
///
/// Given two or more arguments, pause for the amount of time specified by the sum of their values.
pub fn sleep(number: &str) -> Result<(), Error> {
    let time = parse_time(number)?;
    thread::sleep(time);
    Ok(())
}

fn parse_time(time: &str) -> Result<Duration, Error> {
    let mut duration = Duration::new(0, 0);
    for part in time.split_ascii_whitespace() {
        let (has_suffix, multiple) = match part.chars().last() {
            Some('s') => (true, 1),
            Some('m') => (true, 60),
            Some('h') => (true, 60 * 60),
            Some('d') => (true, 24 * 60 * 60),
            _ => (false, 1),
        };

        let interval = if has_suffix {
            part.split_at(part.len() - 1).0
        } else {
            part
        };
        if let Ok(secs) = str::parse::<u64>(interval) {
            duration += Duration::from_secs(secs * multiple);
        } else {
            return Err(Error::from_string(
                ErrorKind::ParameterError,
                format!("Invalid time interval `{:?}`", part),
            ));
        }
    }

    Ok(duration)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_parse_time() {
        assert_eq!(parse_time(" 3 \n").unwrap(), Duration::from_secs(3));
        assert_eq!(parse_time("3").unwrap(), Duration::from_secs(3));
        assert_eq!(parse_time("3s").unwrap(), Duration::from_secs(3));
        assert_eq!(parse_time("3s 4").unwrap(), Duration::from_secs(7));
        assert_eq!(
            parse_time("3s 4m").unwrap(),
            Duration::from_secs(3 + 4 * 60)
        );

        assert!(parse_time("3s 4a").is_err());
    }
}