use crate::error::{Error, Result};
use std::time::Duration;
pub fn parse_duration(s: &str) -> Result<Duration> {
let s = s.trim();
if s.is_empty() {
return Err(Error::InvalidDuration(s.to_string()));
}
let (num_str, suffix) = if let Some(n) = s.strip_suffix("ms") {
(n, "ms")
} else if let Some(n) = s.strip_suffix('s') {
(n, "s")
} else if let Some(n) = s.strip_suffix('m') {
(n, "m")
} else if let Some(n) = s.strip_suffix('h') {
(n, "h")
} else {
return Err(Error::InvalidDuration(format!(
"{s}: missing time suffix (ms, s, m, h)"
)));
};
let num: u64 = num_str
.parse()
.map_err(|_| Error::InvalidDuration(format!("{s}: invalid number")))?;
let duration = match suffix {
"ms" => Duration::from_millis(num),
"s" => Duration::from_secs(num),
"m" => Duration::from_secs(num * 60),
"h" => Duration::from_secs(num * 3600),
_ => unreachable!(),
};
Ok(duration)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_milliseconds() {
assert_eq!(parse_duration("500ms").unwrap(), Duration::from_millis(500));
assert_eq!(parse_duration("0ms").unwrap(), Duration::from_millis(0));
}
#[test]
fn parse_seconds() {
assert_eq!(parse_duration("30s").unwrap(), Duration::from_secs(30));
assert_eq!(parse_duration("1s").unwrap(), Duration::from_secs(1));
}
#[test]
fn parse_minutes() {
assert_eq!(parse_duration("5m").unwrap(), Duration::from_secs(300));
}
#[test]
fn parse_hours() {
assert_eq!(parse_duration("1h").unwrap(), Duration::from_secs(3600));
assert_eq!(parse_duration("2h").unwrap(), Duration::from_secs(7200));
}
#[test]
fn parse_with_whitespace() {
assert_eq!(parse_duration(" 30s ").unwrap(), Duration::from_secs(30));
}
#[test]
fn parse_invalid() {
assert!(parse_duration("").is_err());
assert!(parse_duration("30").is_err());
assert!(parse_duration("abc").is_err());
assert!(parse_duration("30x").is_err());
assert!(parse_duration("-5s").is_err());
}
}