#![allow(clippy::upper_case_acronyms)]
use pest::Parser;
#[derive(Parser)]
#[grammar = "time.pest"] pub struct TimeParser;
use std::error::Error;
#[doc(hidden)]
const YEAR_MILLIS: u128 = 31556952000;
#[doc(hidden)]
const MONTH_MILLIS: u128 = 2592000000;
#[doc(hidden)]
const WEEK_MILLIS: u128 = 604800000;
#[doc(hidden)]
const DAY_MILLIS: u128 = 86400000;
#[doc(hidden)]
const HOUR_MILLIS: u128 = 3600000;
#[doc(hidden)]
const MINUTE_MILLIS: u128 = 60000;
#[doc(hidden)]
const SECOND_MILLIS: u128 = 1000;
pub fn parse_time(unparsed_input: &str) -> Result<u128, Box<dyn Error>> {
let mut parsed_file = TimeParser::parse(Rule::file, unparsed_input)?;
let mut total_millis: u128 = 0;
for line in parsed_file.next().unwrap().into_inner() {
match line.as_rule() {
Rule::durations => {
for durations_expr in line.into_inner() {
let mut durations_inner = durations_expr.into_inner();
let quantity: u128 = durations_inner
.next() .unwrap()
.as_str() .trim() .parse()
.expect("could not parse input into an integer");
let unit_str = durations_inner.next().unwrap();
let unit_millis: u128 =
match TimeParser::parse(Rule::singular, unit_str.as_str())
.ok() .unwrap()
.next() .unwrap()
.into_inner() .next() .unwrap()
.as_rule()
{
Rule::year => YEAR_MILLIS,
Rule::month => MONTH_MILLIS,
Rule::week => WEEK_MILLIS,
Rule::day => DAY_MILLIS,
Rule::hour => HOUR_MILLIS,
Rule::minute => MINUTE_MILLIS,
Rule::second => SECOND_MILLIS,
_ => unreachable!(),
};
total_millis += unit_millis * quantity;
}
}
Rule::EOI => (),
_ => unreachable!(),
};
}
Ok(total_millis)
}