Struct fundu::DurationParser

source ·
pub struct DurationParser { /* private fields */ }
Available on crate feature standard only.
Expand description

A parser with a customizable set of TimeUnits with default identifiers.

See also the module level documentation for more details and more information about the format.

Examples

A parser with the default set of time units

use std::time::Duration;

use fundu::DurationParser;

let parser = DurationParser::new();
assert_eq!(parser.parse("42Ms").unwrap(), Duration::new(0, 42_000));

The parser is reusable and the set of time units is fully customizable

use fundu::{DurationParser, TimeUnit::*};
use std::time::Duration;
let parser = DurationParser::with_time_units(&[NanoSecond, Minute, Hour]);
for (input, expected) in &[
    ("9e3ns", Duration::new(0, 9000)),
    ("10m", Duration::new(600, 0)),
    ("1.1h", Duration::new(3960, 0)),
    ("7", Duration::new(7, 0)),
] {
    assert_eq!(parser.parse(input).unwrap(), *expected);
}

Implementations§

source§

impl DurationParser

source

pub const fn new() -> Self

Construct the parser with the default set of TimeUnits.

Examples
use std::time::Duration;

use fundu::DurationParser;
use fundu::TimeUnit::*;

assert_eq!(
    DurationParser::new().parse("1").unwrap(),
    Duration::new(1, 0)
);
assert_eq!(
    DurationParser::new().parse("1s").unwrap(),
    Duration::new(1, 0)
);
assert_eq!(
    DurationParser::new().parse("42.0e9ns").unwrap(),
    Duration::new(42, 0)
);

assert_eq!(
    DurationParser::new().get_current_time_units(),
    vec![
        NanoSecond,
        MicroSecond,
        MilliSecond,
        Second,
        Minute,
        Hour,
        Day,
        Week
    ]
);
source

pub fn with_time_units(time_units: &[TimeUnit]) -> Self

Initialize the parser with a custom set of TimeUnits.

Examples
use std::time::Duration;

use fundu::DurationParser;
use fundu::TimeUnit::*;

assert_eq!(
    DurationParser::with_time_units(&[NanoSecond, Hour, Week])
        .parse("1.5w")
        .unwrap(),
    Duration::new(60 * 60 * 24 * 7 + 60 * 60 * 24 * 7 / 2, 0)
);
source

pub const fn without_time_units() -> Self

Return a parser without TimeUnits.

Examples
use std::time::Duration;

use fundu::DurationParser;

assert_eq!(
    DurationParser::without_time_units().parse("33.33").unwrap(),
    Duration::new(33, 330_000_000)
);

assert_eq!(
    DurationParser::without_time_units().get_current_time_units(),
    vec![]
);
source

pub const fn with_all_time_units() -> Self

Construct a parser with all available TimeUnits.

Examples
use fundu::DurationParser;
use fundu::TimeUnit::*;

assert_eq!(
    DurationParser::with_all_time_units().get_current_time_units(),
    vec![
        NanoSecond,
        MicroSecond,
        MilliSecond,
        Second,
        Minute,
        Hour,
        Day,
        Week,
        Month,
        Year
    ]
);
source

pub const fn builder<'a>() -> DurationParserBuilder<'a>

Use the DurationParserBuilder to construct a DurationParser.

The DurationParserBuilder is more ergonomic in some use cases than using DurationParser directly. Using this method is the same like invoking DurationParserBuilder::default.

See DurationParserBuilder for more details.

Examples
use std::time::Duration;

use fundu::DurationParser;
use fundu::TimeUnit::*;

let parser = DurationParser::builder()
    .all_time_units()
    .default_unit(MicroSecond)
    .allow_delimiter(|byte| byte.is_ascii_whitespace())
    .build();

assert_eq!(parser.parse("1 \t\nns").unwrap(), Duration::new(0, 1));
assert_eq!(parser.parse("1").unwrap(), Duration::new(0, 1_000));

// instead of

let mut parser = DurationParser::with_all_time_units();
parser
    .default_unit(MicroSecond)
    .allow_delimiter(Some(|byte| byte == b' '));

assert_eq!(parser.parse("1 ns").unwrap(), Duration::new(0, 1));
assert_eq!(parser.parse("1").unwrap(), Duration::new(0, 1_000));
source

pub fn parse(&self, source: &str) -> Result<Duration, ParseError>

Parse the source string into a std::time::Duration depending on the current set of configured TimeUnits.

See the module-level documentation for more information on the format.

Examples
use std::time::Duration;

use fundu::DurationParser;

assert_eq!(
    DurationParser::new().parse("1.2e-1s").unwrap(),
    Duration::new(0, 120_000_000),
);
source

pub fn parse_negative(&self, source: &str) -> Result<Duration, ParseError>

Available on crate feature negative only.

Parse a source string into a time::Duration which can be negative.

This method is only available when activating the negative feature and saturates at time::Duration::MIN for parsed negative durations and at time::Duration::MAX for positive durations.

Examples
use fundu::DurationParser;

assert_eq!(
    DurationParser::new().parse_negative("-10.2e-1s").unwrap(),
    time::Duration::new(-1, -20_000_000),
);
assert_eq!(
    DurationParser::new().parse_negative("1.2e-1s").unwrap(),
    time::Duration::new(0, 120_000_000),
);
source

pub fn default_unit(&mut self, unit: TimeUnit) -> &mut Self

Set the default TimeUnit to unit.

The default time unit is applied when no time unit was given in the input string. If the default time unit is not set with this method the parser defaults to TimeUnit::Second.

Examples
use std::time::Duration;

use fundu::DurationParser;
use fundu::TimeUnit::*;

assert_eq!(
    DurationParser::with_all_time_units()
        .default_unit(NanoSecond)
        .parse("42")
        .unwrap(),
    Duration::new(0, 42)
);
source

pub fn allow_delimiter(&mut self, delimiter: Option<Delimiter>) -> &mut Self

If Some, allow one or more Delimiter between the number and the TimeUnit.

A Delimiter is defined as closure taking a byte and returning true if the delimiter matched. Per default no delimiter is allowed between the number and the TimeUnit. Note this setting implicitly allows the delimiter at the end of the string, but only if no time unit was present. As usual the default time unit is assumed.

Examples
use std::time::Duration;

use fundu::{DurationParser, ParseError};

let mut parser = DurationParser::new();
assert_eq!(
    parser.parse("123 ns"),
    Err(ParseError::TimeUnit(
        3,
        "Invalid time unit: ' ns'".to_string()
    ))
);

parser.allow_delimiter(Some(|byte| byte == b' '));
assert_eq!(parser.parse("123 ns"), Ok(Duration::new(0, 123)));

parser.allow_delimiter(Some(|byte| matches!(byte, b'\t' | b'\n' | b'\r' | b' ')));
assert_eq!(parser.parse("123 ns"), Ok(Duration::new(0, 123)));
assert_eq!(parser.parse("123\t\n\r ns"), Ok(Duration::new(0, 123)));
source

pub fn disable_exponent(&mut self, value: bool) -> &mut Self

If true, disable parsing an exponent.

If an exponent is encountered in the input string and this setting is active this results in an ParseError::Syntax.

Examples
use fundu::{DurationParser, ParseError};

let mut parser = DurationParser::new();
parser.disable_exponent(true);
assert_eq!(
    parser.parse("123e+1"),
    Err(ParseError::Syntax(3, "No exponent allowed".to_string()))
);
source

pub fn disable_fraction(&mut self, value: bool) -> &mut Self

If true, disable parsing a fraction in the source string.

This setting will disable parsing a fraction and a point delimiter will cause an error ParseError::Syntax. It does not prevent Durations from being smaller than seconds.

Examples
use std::time::Duration;

use fundu::{DurationParser, ParseError};

let mut parser = DurationParser::new();
parser.disable_fraction(true);

assert_eq!(
    parser.parse("123.456"),
    Err(ParseError::Syntax(3, "No fraction allowed".to_string()))
);

assert_eq!(parser.parse("123e-2"), Ok(Duration::new(1, 230_000_000)));

assert_eq!(parser.parse("123ns"), Ok(Duration::new(0, 123)));
source

pub fn disable_infinity(&mut self, value: bool) -> &mut Self

If true, disable parsing infinity

This setting will disable parsing infinity values like (inf or infinity).

Examples
use fundu::{DurationParser, ParseError};

let mut parser = DurationParser::new();
parser.disable_infinity(true);

assert_eq!(
    parser.parse("inf"),
    Err(ParseError::Syntax(0, format!("Invalid input: 'inf'")))
);
assert_eq!(
    parser.parse("infinity"),
    Err(ParseError::Syntax(0, format!("Invalid input: 'infinity'")))
);
assert_eq!(
    parser.parse("+inf"),
    Err(ParseError::Syntax(1, format!("Invalid input: 'inf'")))
);
source

pub fn number_is_optional(&mut self, value: bool) -> &mut Self

If true, this setting makes a number in the source string optional.

If no number is present, then 1 is assumed. If a number is present then it must still consist of either a whole part or fraction part, if not disabled with DurationParser::disable_fraction.

Examples
use std::time::Duration;

use fundu::DurationParser;

let mut parser = DurationParser::new();
parser.number_is_optional(true);

for input in &["ns", "e-9", "e-3Ms"] {
    assert_eq!(parser.parse(input), Ok(Duration::new(0, 1)));
}
source

pub fn parse_multiple(&mut self, delimiter: Option<Delimiter>) -> &mut Self

If set to some Delimiter, parse possibly multiple durations and sum them up.

If Delimiter is set to None, this functionality is disabled. The Delimiter may or may not occur to separate the durations. If the delimiter does not occur the next duration is recognized by a leading digit.

Like a single duration, the summed up durations saturate at Duration::MAX. Parsing multiple durations is short-circuiting and parsing stops after the first ParseError was encountered. Note that parsing doesn’t stop when reaching Duration::MAX, so any ParseErrors later in the input string are still reported.

Usage together with number format customizations

The number format and other aspects can be customized as usual via the methods within this struct and have the known effect. However, there are some interesting constellations:

If DurationParser::allow_delimiter is set to some delimiter, the Delimiter of this method and the Delimiter of the allow_delimiter method can be equal either in parts or in a whole without having side-effects on each other. But, if simultaneously DurationParser::number_is_optional is set to true, then the resulting Duration will differ:

use std::time::Duration;

use fundu::DurationParser;

let delimiter = |byte| matches!(byte, b' ' | b'\t');
let mut parser = DurationParser::new();
parser
    .parse_multiple(Some(delimiter))
    .number_is_optional(true);

// Here, the parser parses `1`, `s`, `1` and then `ns` separately
assert_eq!(parser.parse("1 s 1 ns"), Ok(Duration::new(3, 1)));

// Here, the parser parses `1 s` and then `1 ns`.
parser.allow_delimiter(Some(delimiter));
assert_eq!(parser.parse("1 s 1 ns"), Ok(Duration::new(1, 1)));
Examples
use std::time::Duration;

use fundu::DurationParser;

let mut parser = DurationParser::new();
parser.parse_multiple(Some(|byte| matches!(byte, b' ' | b'\t')));

assert_eq!(parser.parse("1.5h 2e+2ns"), Ok(Duration::new(5400, 200)));
assert_eq!(parser.parse("55s500ms"), Ok(Duration::new(55, 500_000_000)));
assert_eq!(parser.parse("1\t1"), Ok(Duration::new(2, 0)));
assert_eq!(parser.parse("1.   .1"), Ok(Duration::new(1, 100_000_000)));
assert_eq!(parser.parse("2h"), Ok(Duration::new(2 * 60 * 60, 0)));
assert_eq!(
    parser.parse("300ms20s 5d"),
    Ok(Duration::new(5 * 60 * 60 * 24 + 20, 300_000_000))
);
source

pub fn get_current_time_units(&self) -> Vec<TimeUnit>

Return the currently defined set of TimeUnit.

Examples
use fundu::{DurationParser, TimeUnit::*};

let parser = DurationParser::without_time_units();
assert_eq!(
    parser.get_current_time_units(),
    vec![]
);

assert_eq!(
    DurationParser::with_time_units(&[NanoSecond]).get_current_time_units(),
    vec![NanoSecond]
);

Trait Implementations§

source§

impl Debug for DurationParser

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Default for DurationParser

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl PartialEq<DurationParser> for DurationParser

source§

fn eq(&self, other: &DurationParser) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl Eq for DurationParser

source§

impl StructuralEq for DurationParser

source§

impl StructuralPartialEq for DurationParser

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.