duration_parser/
parse.rs

1use regex::Regex;
2use error::Error;
3
4const SEC_IN_MIN : u64 = 60;
5const SEC_IN_HR : u64 = SEC_IN_MIN * 60;
6const SEC_IN_DAY : u64 = SEC_IN_HR * 24;
7const SEC_IN_WK : u64 = SEC_IN_DAY * 7;
8const SEC_IN_YR : u64 = SEC_IN_DAY * 365;
9
10fn multiplier_from_unit(units : &str) -> Result<u64, Error> {
11	return match units.as_ref() {
12		"s" => Ok(1),
13		"m" => Ok(SEC_IN_MIN),
14		"h" => Ok(SEC_IN_HR),
15		"d" => Ok(SEC_IN_DAY),
16		"w" => Ok(SEC_IN_WK),
17		"y" => Ok(SEC_IN_YR),
18		_ => Err(Error::UnknownSuffix)
19	}
20}
21
22pub fn parse_duration(string : &String) -> Result<u64, Error> {
23	lazy_static! {
24		static ref TIME_RE: Regex = Regex::new(r"(?P<value>\d+)(?P<units>[a-z])").unwrap();
25	}
26
27	let caps_iter = TIME_RE.captures_iter(string);
28
29	let mut expected_length = 0;
30	let mut total_duration_in_ms : u64 = 0;
31	for caps in caps_iter {
32		let value_str = &caps["value"];
33		let units = &caps["units"];
34
35		expected_length += value_str.len() + units.len();
36
37		let value : u64 = match value_str.parse() {
38			Ok(val) => val,
39			Err(_) => return Err(Error::UnparsableNumber)
40		};
41
42		let duration_in_ms = match value.checked_mul(multiplier_from_unit(units)?) {
43			Some(val) => val,
44			None => return Err(Error::Overflow)
45		};
46
47		total_duration_in_ms = match total_duration_in_ms.checked_add(duration_in_ms) {
48			Some(val) => val,
49			None => return Err(Error::Overflow)
50		};
51	}
52
53	if expected_length == 0 {
54		return Err(Error::NoData);
55	}
56
57	if expected_length != string.len() {
58		return Err(Error::UnparsableExtras);
59	}
60
61	return Ok(total_duration_in_ms);
62}