use std::time::Duration as StdDuration;
use fundu_core::config::Delimiter;
use fundu_core::parse::Parser;
use fundu_core::time::Duration as FunduDuration;
use super::time_units::TimeUnits;
use crate::{DurationParserBuilder, ParseError, TimeUnit};
#[derive(Debug, PartialEq, Eq)]
pub struct DurationParser<'a> {
pub(super) time_units: TimeUnits,
pub(super) inner: Parser<'a>,
}
impl<'a> DurationParser<'a> {
pub const fn new() -> Self {
Self {
time_units: TimeUnits::with_default_time_units(),
inner: Parser::new(),
}
}
pub const fn with_time_units(time_units: &[TimeUnit]) -> Self {
Self {
time_units: TimeUnits::with_time_units(time_units),
inner: Parser::new(),
}
}
pub const fn without_time_units() -> Self {
Self {
time_units: TimeUnits::new(),
inner: Parser::new(),
}
}
pub const fn with_all_time_units() -> Self {
Self {
time_units: TimeUnits::with_all_time_units(),
inner: Parser::new(),
}
}
pub const fn builder() -> DurationParserBuilder<'a> {
DurationParserBuilder::new()
}
#[inline]
pub fn parse(&self, source: &str) -> Result<FunduDuration, ParseError> {
self.inner.parse(source, &self.time_units, None, None)
}
pub fn default_unit(&mut self, time_unit: TimeUnit) -> &mut Self {
self.inner.config.default_unit = time_unit;
self
}
pub fn allow_time_unit_delimiter(&mut self, value: bool) -> &mut Self {
self.inner.config.allow_time_unit_delimiter = value;
self
}
pub fn allow_sign_delimiter(&mut self, value: bool) -> &mut Self {
self.inner.config.allow_sign_delimiter = value;
self
}
pub fn allow_negative(&mut self, value: bool) -> &mut Self {
self.inner.config.allow_negative = value;
self
}
pub fn allow_ago(&mut self, value: bool) -> &mut Self {
self.inner.config.allow_ago = value;
if value {
self.inner.config.allow_negative = true;
}
self
}
pub fn disable_exponent(&mut self, value: bool) -> &mut Self {
self.inner.config.disable_exponent = value;
self
}
pub fn disable_fraction(&mut self, value: bool) -> &mut Self {
self.inner.config.disable_fraction = value;
self
}
pub fn disable_infinity(&mut self, value: bool) -> &mut Self {
self.inner.config.disable_infinity = value;
self
}
pub fn number_is_optional(&mut self, value: bool) -> &mut Self {
self.inner.config.number_is_optional = value;
self
}
pub fn parse_multiple(
&mut self,
value: bool,
conjunctions: Option<&'a [&'a str]>,
) -> &mut Self {
self.inner.config.allow_multiple = value;
self.inner.config.conjunctions = conjunctions;
self
}
pub fn set_inner_delimiter(&mut self, delimiter: Delimiter) -> &mut Self {
self.inner.config.inner_delimiter = delimiter;
self
}
pub fn set_outer_delimiter(&mut self, delimiter: Delimiter) -> &mut Self {
self.inner.config.outer_delimiter = delimiter;
self
}
pub fn get_current_time_units(&self) -> Vec<TimeUnit> {
self.time_units.get_time_units()
}
}
impl<'a> Default for DurationParser<'a> {
fn default() -> Self {
Self::new()
}
}
#[allow(clippy::missing_panics_doc)]
pub fn parse_duration(string: &str) -> Result<StdDuration, ParseError> {
DurationParser::new()
.parse(string)
.map(|d| d.try_into().unwrap())
}
#[cfg(test)]
mod tests {
use fundu_core::config::Config;
use fundu_core::time::TimeUnit::*;
use super::*;
#[test]
#[cfg_attr(miri, ignore)]
fn test_duration_parser_init_when_default() {
let config = Config::new();
let parser = DurationParser::default();
assert_eq!(parser.inner.config, config);
assert_eq!(
parser.get_current_time_units(),
vec![
NanoSecond,
MicroSecond,
MilliSecond,
Second,
Minute,
Hour,
Day,
Week
]
);
}
#[test]
fn test_duration_parser_setting_allow_delimiter() {
let mut parser = DurationParser::new();
parser.allow_time_unit_delimiter(true);
assert!(parser.inner.config.allow_time_unit_delimiter);
}
#[test]
fn test_duration_parser_setting_allow_sign_delimiter() {
let mut parser = DurationParser::new();
parser.allow_sign_delimiter(true);
assert!(parser.inner.config.allow_sign_delimiter);
}
#[test]
fn test_duration_parser_setting_allow_ago() {
let mut parser = DurationParser::new();
parser.allow_ago(true);
assert!(parser.inner.config.allow_ago);
assert!(parser.inner.config.allow_negative);
}
#[test]
fn test_duration_parser_setting_allow_ago_when_false() {
let mut parser = DurationParser::new();
parser.allow_ago(false);
assert!(!parser.inner.config.allow_ago);
assert!(!parser.inner.config.allow_negative);
}
#[test]
fn test_duration_parser_setting_disable_infinity() {
let mut parser = DurationParser::new();
parser.disable_infinity(true);
assert!(parser.inner.config.disable_infinity);
}
#[test]
fn test_duration_parser_setting_parse_multiple() {
let mut parser = DurationParser::new();
parser.parse_multiple(true, None);
assert!(parser.inner.config.allow_multiple);
assert!(parser.inner.config.conjunctions.is_none());
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_duration_parser_when_builder() {
assert_eq!(DurationParser::builder(), DurationParserBuilder::new());
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_duration_parser_builder_when_default() {
assert_eq!(
DurationParserBuilder::default(),
DurationParserBuilder::new()
);
}
#[test]
fn test_duration_parser_set_inner_delimiter() {
let mut parser = DurationParser::new();
parser.set_inner_delimiter(|byte| byte == b'a');
assert!((parser.inner.config.inner_delimiter)(b'a'));
assert!(!(parser.inner.config.inner_delimiter)(b' '));
}
#[test]
fn test_duration_parser_set_outer_delimiter() {
let mut parser = DurationParser::new();
parser.set_outer_delimiter(|byte| byte == b'a');
assert!((parser.inner.config.outer_delimiter)(b'a'));
assert!(!(parser.inner.config.outer_delimiter)(b' '));
}
}