use std::time::Duration;
use std::time::SystemTime;
use anyhow::Result;
use anyhow::anyhow;
use clap::Args as Arguments;
use clap::Parser;
use clap::Subcommand;
fn parse_duration(s: &str) -> Result<Duration> {
let durations = [("s", 1), ("m", 60), ("h", 3600)];
for (suffix, multiplier) in &durations {
if let Some(base) = s.strip_suffix(suffix)
&& let Ok(count) = base.parse::<u64>()
{
return Ok(Duration::from_secs(count * multiplier))
}
}
Err(anyhow!("invalid duration provided: {s}"))
}
#[derive(Debug, Parser)]
#[clap(version = env!("VERSION"))]
pub struct Args {
#[command(subcommand)]
pub command: Command,
pub message: String,
#[clap(short = 'f', long = "foreground", global = true)]
pub foreground: bool,
}
#[derive(Debug, Subcommand)]
pub(crate) enum Command {
In(RemindIn),
}
#[derive(Debug, Arguments)]
pub(crate) struct RemindIn {
#[clap(value_parser = parse_duration)]
duration: Duration,
}
impl RemindIn {
pub fn target_time(&self) -> SystemTime {
SystemTime::now() + self.duration
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn duration_parsing() {
assert_eq!(parse_duration("1s").unwrap(), Duration::from_secs(1));
assert_eq!(parse_duration("35s").unwrap(), Duration::from_secs(35));
assert_eq!(parse_duration("2m").unwrap(), Duration::from_secs(120));
assert_eq!(
parse_duration("5h").unwrap(),
Duration::from_secs(5 * 60 * 60)
);
assert!(
parse_duration("xxx")
.unwrap_err()
.to_string()
.contains("invalid duration provided")
);
}
}