use fundu_core::config::{Config, Delimiter};
use fundu_core::parse::Parser;
use super::time_units::{CustomTimeUnits, TimeKeyword};
use super::{Numeral, Numerals};
use crate::{CustomDurationParser, CustomTimeUnit, TimeUnit};
#[derive(Debug, PartialEq, Eq)]
pub struct CustomDurationParserBuilder<'a> {
config: Config<'a>,
time_units: Vec<CustomTimeUnit<'a>>,
keywords: Vec<TimeKeyword<'a>>,
numerals: Vec<Numeral<'a>>,
}
impl<'a> Default for CustomDurationParserBuilder<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> CustomDurationParserBuilder<'a> {
#[cfg_attr(miri, doc = "```rust,ignore")]
#[cfg_attr(not(miri), doc = "```rust")]
pub const fn new() -> Self {
Self {
config: Config::new(),
time_units: vec![],
keywords: vec![],
numerals: vec![],
}
}
pub fn time_unit(mut self, time_unit: CustomTimeUnit<'a>) -> Self {
self.time_units.push(time_unit);
self
}
pub fn time_units(mut self, time_units: &[CustomTimeUnit<'a>]) -> Self {
self.time_units.reserve_exact(time_units.len());
for unit in time_units {
self.time_units.push(*unit);
}
self
}
pub fn keyword(mut self, keyword: TimeKeyword<'a>) -> Self {
self.keywords.push(keyword);
self
}
pub fn keywords(mut self, keywords: &[TimeKeyword<'a>]) -> Self {
self.keywords.reserve_exact(keywords.len());
for keyword in keywords {
self.keywords.push(*keyword);
}
self
}
pub fn numeral(mut self, numeral: Numeral<'a>) -> Self {
self.numerals.push(numeral);
self
}
pub fn numerals(mut self, numerals: &[Numeral<'a>]) -> Self {
for numeral in numerals {
self.numerals.push(*numeral);
}
self
}
pub const fn default_unit(mut self, time_unit: TimeUnit) -> Self {
self.config.default_unit = time_unit;
self
}
pub const fn allow_time_unit_delimiter(mut self) -> Self {
self.config.allow_time_unit_delimiter = true;
self
}
pub const fn allow_sign_delimiter(mut self) -> Self {
self.config.allow_sign_delimiter = true;
self
}
pub const fn allow_negative(mut self) -> Self {
self.config.allow_negative = true;
self
}
pub const fn allow_ago(mut self) -> Self {
self.config.allow_ago = true;
self.config.allow_negative = true;
self
}
pub const fn disable_exponent(mut self) -> Self {
self.config.disable_exponent = true;
self
}
pub const fn disable_fraction(mut self) -> Self {
self.config.disable_fraction = true;
self
}
pub const fn disable_infinity(mut self) -> Self {
self.config.disable_infinity = true;
self
}
pub const fn number_is_optional(mut self) -> Self {
self.config.number_is_optional = true;
self
}
pub const fn parse_multiple(mut self, conjunctions: Option<&'a [&'a str]>) -> Self {
self.config.allow_multiple = true;
self.config.conjunctions = conjunctions;
self
}
pub const fn outer_delimiter(mut self, delimiter: Delimiter) -> Self {
self.config.outer_delimiter = delimiter;
self
}
pub const fn inner_delimiter(mut self, delimiter: Delimiter) -> Self {
self.config.inner_delimiter = delimiter;
self
}
pub fn build(self) -> CustomDurationParser<'a> {
CustomDurationParser {
time_units: CustomTimeUnits::with_time_units(&self.time_units),
inner: Parser::with_config(self.config),
keywords: CustomTimeUnits::with_keywords(&self.keywords),
numerals: Numerals::with_numerals(self.numerals),
}
}
}
#[cfg(test)]
mod tests {
use fundu_core::config::Config;
use fundu_core::time::TimeUnit::*;
use fundu_core::time::TimeUnitsLike;
use super::*;
use crate::{CustomTimeUnit, Multiplier};
#[test]
#[cfg_attr(miri, ignore)]
fn test_custom_duration_parser_builder_when_default() {
assert_eq!(
CustomDurationParserBuilder::default(),
CustomDurationParserBuilder::new()
);
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_custom_duration_parser_builder_when_new() {
let builder = CustomDurationParserBuilder::new();
assert_eq!(builder.config, Config::new());
assert!(builder.time_units.is_empty());
assert!(builder.numerals.is_empty());
assert!(builder.keywords.is_empty());
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_custom_duration_parser_builder_when_default_unit() {
let mut expected = Config::new();
expected.default_unit = MicroSecond;
let builder = CustomDurationParserBuilder::new().default_unit(MicroSecond);
assert_eq!(builder.config, expected);
}
#[test]
fn test_custom_duration_parser_builder_when_allow_delimiter() {
let builder = CustomDurationParserBuilder::new().allow_time_unit_delimiter();
assert!(builder.config.allow_time_unit_delimiter);
}
#[test]
fn test_custom_duration_parser_builder_when_allow_sign_delimiter() {
let builder = CustomDurationParserBuilder::new().allow_sign_delimiter();
assert!(builder.config.allow_sign_delimiter);
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_custom_duration_parser_builder_when_disable_exponent() {
let mut expected = Config::new();
expected.disable_exponent = true;
let builder = CustomDurationParserBuilder::new().disable_exponent();
assert_eq!(builder.config, expected);
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_custom_duration_parser_builder_when_disable_fraction() {
let mut expected = Config::new();
expected.disable_fraction = true;
let builder = CustomDurationParserBuilder::new().disable_fraction();
assert_eq!(builder.config, expected);
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_custom_duration_parser_builder_when_disable_infinity() {
let mut expected = Config::new();
expected.disable_infinity = true;
let builder = CustomDurationParserBuilder::new().disable_infinity();
assert_eq!(builder.config, expected);
}
#[test]
#[cfg_attr(miri, ignore)]
fn test_custom_duration_parser_builder_when_number_is_optional() {
let mut expected = Config::new();
expected.number_is_optional = true;
let builder = CustomDurationParserBuilder::new().number_is_optional();
assert_eq!(builder.config, expected);
}
#[test]
fn test_custom_duration_parser_builder_when_parse_multiple() {
let builder = CustomDurationParserBuilder::new().parse_multiple(None);
assert!(builder.config.allow_multiple);
assert!(builder.config.conjunctions.is_none());
}
#[test]
fn test_custom_duration_parser_builder_when_build_with_regular_time_unit() {
let mut expected = Config::new();
expected.number_is_optional = true;
let parser = CustomDurationParserBuilder::new()
.time_unit(CustomTimeUnit::with_default(Second, &["s", "secs"]))
.time_unit(CustomTimeUnit::new(Hour, &["h"], Some(Multiplier(3, 0))))
.time_units(&[
CustomTimeUnit::new(Minute, &["m", "min"], Some(Multiplier(2, 0))),
CustomTimeUnit::new(Day, &["d"], Some(Multiplier(4, 0))),
])
.number_is_optional()
.build();
assert!(!parser.is_empty());
assert_eq!(
parser.get_time_unit_by_id("s"),
Some((Second, Multiplier(1, 0)))
);
assert_eq!(
parser.get_time_unit_by_id("secs"),
Some((Second, Multiplier(1, 0)))
);
assert_eq!(
parser.get_time_unit_by_id("h"),
Some((Hour, Multiplier(3, 0)))
);
assert_eq!(
parser.get_time_unit_by_id("m"),
Some((Minute, Multiplier(2, 0)))
);
assert_eq!(
parser.get_time_unit_by_id("min"),
Some((Minute, Multiplier(2, 0)))
);
assert_eq!(
parser.get_time_unit_by_id("d"),
Some((Day, Multiplier(4, 0)))
);
}
#[test]
fn test_custom_duration_parser_builder_when_build_without_regular_time_units() {
let mut expected = Config::new();
expected.number_is_optional = true;
let parser = CustomDurationParserBuilder::new()
.time_units(&[
CustomTimeUnit::new(Minute, &["m", "min"], Some(Multiplier(2, 0))),
CustomTimeUnit::new(Day, &["d"], Some(Multiplier(4, 0))),
])
.number_is_optional()
.build();
assert!(!parser.is_empty());
assert_eq!(
parser.get_time_unit_by_id("m"),
Some((Minute, Multiplier(2, 0)))
);
assert_eq!(
parser.get_time_unit_by_id("min"),
Some((Minute, Multiplier(2, 0)))
);
assert_eq!(
parser.get_time_unit_by_id("d"),
Some((Day, Multiplier(4, 0)))
);
}
#[test]
fn test_custom_duration_parser_builder_when_keywords() {
let parser = CustomDurationParserBuilder::new()
.keywords(&[
TimeKeyword::new(Second, &["sec"], None),
TimeKeyword::new(Second, &["secs"], Some(Multiplier(2, 0))),
])
.build();
assert_eq!(
parser.keywords.get("sec").unwrap(),
(Second, Multiplier(1, 0))
);
assert_eq!(
parser.keywords.get("secs").unwrap(),
(Second, Multiplier(2, 0))
);
}
#[test]
fn test_custom_duration_parser_builder_when_numeral() {
let parser = CustomDurationParserBuilder::new()
.numeral(Numeral::new(&["some"], Multiplier(1, 0)))
.build();
assert!(!parser.numerals.is_empty());
assert_eq!(
parser.numerals.data,
vec![Numeral::new(&["some"], Multiplier(1, 0))]
);
}
#[test]
fn test_custom_duration_parser_builder_when_numerals() {
let parser = CustomDurationParserBuilder::new()
.numerals(&[
Numeral::new(&["some"], Multiplier(1, 0)),
Numeral::new(&["other"], Multiplier(2, 0)),
])
.build();
assert!(!parser.numerals.is_empty());
assert_eq!(
parser.numerals.data,
vec![
Numeral::new(&["some"], Multiplier(1, 0)),
Numeral::new(&["other"], Multiplier(2, 0)),
]
);
}
}