Skip to content

Commit

Permalink
add time unit abbr parser combinator
Browse files Browse the repository at this point in the history
  • Loading branch information
baoyachi committed Jan 13, 2024
1 parent 3c8d5ee commit 82540f3
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ time = { version = "0.3.17", optional = true }

serde = { version = "1.0.147", features = ["derive"], optional = true }
rust_decimal = { version = "1.29.1", default-features = false }
winnow = {version = "*",features = ["debug"]}

[dev-dependencies]
serde_json = { version = "1.0.87" }
Expand Down
28 changes: 28 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@
//! }
//! ```
mod parser;

#[cfg(all(feature = "chrono", feature = "serde"))]
use chrono::Duration as CDuration;

Expand All @@ -174,6 +176,7 @@ use nom::sequence::tuple;
use rust_decimal::prelude::ToPrimitive;
use rust_decimal::Decimal;
use std::convert::TryFrom;
use std::str::FromStr;
use std::time::Duration;
use thiserror::Error;
#[cfg(all(feature = "time", feature = "serde"))]
Expand Down Expand Up @@ -212,6 +215,31 @@ enum TimeUnit {
NanoSecond,
}

impl FromStr for TimeUnit {
type Err = DError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match &*s.to_lowercase() {
"y" | "year" => Ok(TimeUnit::Year),
"mon" | "month" => Ok(TimeUnit::Month),
"w" | "week" => Ok(TimeUnit::Week),
"d" | "day" => Ok(TimeUnit::Day),
"h" | "hour" | "hr" => Ok(TimeUnit::Hour),
"m" | "min" | "minute" => Ok(TimeUnit::Minute),
"s" | "sec" | "second" => Ok(TimeUnit::Second),
"ms" | "msec" | "millisecond" => Ok(TimeUnit::MilliSecond),
"µs" | "µsec" | "µsecond" | "us" | "usec" | "usecond" | "microsecond" => {
Ok(TimeUnit::MicroSecond)
}
"ns" | "nsec" | "nanosecond" => Ok(TimeUnit::NanoSecond),
_ => Err(DError::ParseError(format!(
"expect one of [y,mon,w,d,h,m,s,ms,µs,us,ns] or their longer forms.but find:{}",
s,
))),
}
}
}

const ONE_MICROSECOND_NANOSECOND: u64 = 1000;
const ONE_MILLISECOND_NANOSECOND: u64 = 1000 * ONE_MICROSECOND_NANOSECOND;
const ONE_SECOND_NANOSECOND: u64 = 1000 * ONE_MILLISECOND_NANOSECOND;
Expand Down
61 changes: 61 additions & 0 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use crate::TimeUnit;
use winnow::stream::AsChar;
use winnow::token::take_while;
use winnow::PResult;
use winnow::Parser;

fn time_unit_abbr(input: &mut &str) -> PResult<TimeUnit> {
take_while(1.., |c: char| c.is_alpha() || c == 'µ')
.try_map(str::parse)
.parse_next(input)
}

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

#[test]
fn test_time_unit_abbr() {
assert_eq!(
time_unit_abbr.parse_peek(&Partial::new("y")),
Ok(("", TimeUnit::Year))
);
assert_eq!(
time_unit_abbr.parse_peek(&Partial::new("mon")),
Ok(("", TimeUnit::Month))
);
assert_eq!(
time_unit_abbr.parse_peek(&Partial::new("w")),
Ok(("", TimeUnit::Week))
);
assert_eq!(
time_unit_abbr.parse_peek(&Partial::new("d")),
Ok(("", TimeUnit::Day))
);
assert_eq!(
time_unit_abbr.parse_peek(&Partial::new("h")),
Ok(("", TimeUnit::Hour))
);
assert_eq!(
time_unit_abbr.parse_peek(&Partial::new("m")),
Ok(("", TimeUnit::Minute))
);
assert_eq!(
time_unit_abbr.parse_peek(&Partial::new("s")),
Ok(("", TimeUnit::Second))
);
assert_eq!(
time_unit_abbr.parse_peek(&Partial::new("ms")),
Ok(("", TimeUnit::MilliSecond))
);
assert_eq!(
time_unit_abbr.parse_peek(&Partial::new("µs")),
Ok(("", TimeUnit::MicroSecond))
);
assert_eq!(
time_unit_abbr.parse_peek(&Partial::new("ns")),
Ok(("", TimeUnit::NanoSecond))
);
}
}

0 comments on commit 82540f3

Please sign in to comment.