Struct fundu::DurationParser
source · pub struct DurationParser<'a> { /* private fields */ }
standard
only.Expand description
A parser with a customizable set of TimeUnit
s 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 fundu::{Duration, DurationParser};
let parser = DurationParser::new();
assert_eq!(parser.parse("42Ms").unwrap(), Duration::positive(0, 42_000));
The parser is reusable and the set of time units is fully customizable
use fundu::{Duration, DurationParser, TimeUnit::*};
let parser = DurationParser::with_time_units(&[NanoSecond, Minute, Hour]);
for (input, expected) in &[
("9e3ns", Duration::positive(0, 9000)),
("10m", Duration::positive(600, 0)),
("1.1h", Duration::positive(3960, 0)),
("7", Duration::positive(7, 0)),
] {
assert_eq!(parser.parse(input).unwrap(), *expected);
}
Implementations§
source§impl<'a> DurationParser<'a>
impl<'a> DurationParser<'a>
sourcepub const fn new() -> Self
pub const fn new() -> Self
Construct the parser with the default set of TimeUnit
s.
Examples
use fundu::TimeUnit::*;
use fundu::{Duration, DurationParser};
assert_eq!(
DurationParser::new().parse("1").unwrap(),
Duration::positive(1, 0)
);
assert_eq!(
DurationParser::new().parse("1s").unwrap(),
Duration::positive(1, 0)
);
assert_eq!(
DurationParser::new().parse("42.0e9ns").unwrap(),
Duration::positive(42, 0)
);
assert_eq!(
DurationParser::new().get_current_time_units(),
vec![
NanoSecond,
MicroSecond,
MilliSecond,
Second,
Minute,
Hour,
Day,
Week
]
);
sourcepub const fn with_time_units(time_units: &[TimeUnit]) -> Self
pub const fn with_time_units(time_units: &[TimeUnit]) -> Self
sourcepub const fn without_time_units() -> Self
pub const fn without_time_units() -> Self
sourcepub const fn with_all_time_units() -> Self
pub const fn with_all_time_units() -> Self
sourcepub const fn builder() -> DurationParserBuilder<'a>
pub const fn builder() -> 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 fundu::TimeUnit::*;
use fundu::{Duration, DurationParser};
let parser = DurationParser::builder()
.all_time_units()
.default_unit(MicroSecond)
.allow_time_unit_delimiter()
.build();
assert_eq!(parser.parse("1 \t\nns").unwrap(), Duration::positive(0, 1));
assert_eq!(parser.parse("1").unwrap(), Duration::positive(0, 1_000));
// instead of
let mut parser = DurationParser::with_all_time_units();
parser
.default_unit(MicroSecond)
.allow_time_unit_delimiter(true);
assert_eq!(parser.parse("1 ns").unwrap(), Duration::positive(0, 1));
assert_eq!(parser.parse("1").unwrap(), Duration::positive(0, 1_000));
sourcepub fn parse(&self, source: &str) -> Result<FunduDuration, ParseError>
pub fn parse(&self, source: &str) -> Result<FunduDuration, ParseError>
Parse the source
string into a crate::Duration
.
See the module-level documentation for more information on the format.
Errors
If parsing into a crate::Duration
fails returns a ParseError
Examples
use fundu::{Duration, DurationParser};
assert_eq!(
DurationParser::new().parse("1.2e-1s").unwrap(),
Duration::positive(0, 120_000_000),
);
sourcepub fn default_unit(&mut self, time_unit: TimeUnit) -> &mut Self
pub fn default_unit(&mut self, time_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 fundu::TimeUnit::*;
use fundu::{Duration, DurationParser};
assert_eq!(
DurationParser::with_all_time_units()
.default_unit(NanoSecond)
.parse("42")
.unwrap(),
Duration::positive(0, 42)
);
sourcepub fn allow_time_unit_delimiter(&mut self, value: bool) -> &mut Self
pub fn allow_time_unit_delimiter(&mut self, value: bool) -> &mut Self
If Some
, allow one or more inner Delimiter
between the number and the TimeUnit
.
Per default no delimiter is allowed between the number and the TimeUnit
. As
usual the default time unit is assumed if no time unit was present. The delimiter can be
changed with DurationParser::set_inner_delimiter
.
Examples
use fundu::{Duration, 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_time_unit_delimiter(true);
assert_eq!(parser.parse("123 ns"), Ok(Duration::positive(0, 123)));
assert_eq!(parser.parse("123 ns"), Ok(Duration::positive(0, 123)));
assert_eq!(parser.parse("123ns"), Ok(Duration::positive(0, 123)));
parser.allow_time_unit_delimiter(true);
assert_eq!(parser.parse("123\r\nns"), Ok(Duration::positive(0, 123)));
assert_eq!(parser.parse("123\t\n\r ns"), Ok(Duration::positive(0, 123)));
sourcepub fn allow_sign_delimiter(&mut self, value: bool) -> &mut Self
pub fn allow_sign_delimiter(&mut self, value: bool) -> &mut Self
Allow one or more delimiters between the leading sign and the number.
A Delimiter
is defined as closure taking a byte and returning true if the delimiter
matched. If set to None
(the default) no delimiter is allowed between the sign and the
number.
Examples
use fundu::{Duration, DurationParser};
let mut parser = DurationParser::new();
parser.allow_sign_delimiter(true);
assert_eq!(parser.parse("+123ns"), Ok(Duration::positive(0, 123)));
assert_eq!(parser.parse("+\t\n 123ns"), Ok(Duration::positive(0, 123)));
assert_eq!(parser.parse("+ 123ns"), Ok(Duration::positive(0, 123)));
assert_eq!(parser.parse("+ 123ns"), Ok(Duration::positive(0, 123)));
sourcepub fn allow_negative(&mut self, value: bool) -> &mut Self
pub fn allow_negative(&mut self, value: bool) -> &mut Self
If true, then parsing negative durations is possible
Without setting this option the parser returns ParseError::NegativeNumber
if it
encounters a negative number.
Examples
use fundu::{Duration, DurationParser};
let mut parser = DurationParser::new();
parser.allow_negative(true);
assert_eq!(parser.parse("-123"), Ok(Duration::negative(123, 0)));
assert_eq!(parser.parse("-1.23e-7"), Ok(Duration::negative(0, 123)));
sourcepub fn allow_ago(&mut self, value: bool) -> &mut Self
pub fn allow_ago(&mut self, value: bool) -> &mut Self
If true, the ago
keyword can follow a time unit and the inner_delimiter
to denote a
negative duration
The ago
keyword is allowed in the source string after a time unit and only if a time unit
was encountered. The time unit and ago
must be delimited by the inner_delimiter
. Note
that setting this option automatically sets DurationParser::allow_negative
to true.
Examples
use fundu::{Duration, DurationParser};
let mut parser = DurationParser::with_all_time_units();
parser.allow_ago(true);
assert_eq!(parser.parse("123ns ago"), Ok(Duration::negative(0, 123)));
assert_eq!(parser.parse("-123ns ago"), Ok(Duration::positive(0, 123)));
And some illegal usages of ago
use fundu::TimeUnit::*;
use fundu::{DurationParser, Multiplier, ParseError, TimeKeyword};
let mut parser = DurationParser::with_all_time_units();
parser.allow_ago(true);
// Error because no time unit was specified
assert_eq!(
parser.parse("123 ago"),
Err(ParseError::TimeUnit(
3,
"Invalid time unit: ' ago'".to_string()
))
);
// Error because ago was specified multiple times
assert_eq!(
parser.parse("123ns ago ago"),
Err(ParseError::Syntax(
9,
"Expected end of input but found: ' ago'".to_string()
))
);
sourcepub fn disable_exponent(&mut self, value: bool) -> &mut Self
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()))
);
sourcepub fn disable_fraction(&mut self, value: bool) -> &mut Self
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 crate::Duration
s from being smaller than
seconds.
Examples
use fundu::{Duration, 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::positive(1, 230_000_000))
);
assert_eq!(parser.parse("123ns"), Ok(Duration::positive(0, 123)));
sourcepub fn disable_infinity(&mut self, value: bool) -> &mut Self
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::InvalidInput("inf".to_owned()))
);
assert_eq!(
parser.parse("infinity"),
Err(ParseError::InvalidInput("infinity".to_owned()))
);
assert_eq!(
parser.parse("+inf"),
Err(ParseError::InvalidInput("inf".to_owned()))
);
sourcepub fn number_is_optional(&mut self, value: bool) -> &mut Self
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 and/or fraction part, if not disabled with
DurationParser::disable_fraction
. The exponent is also part of the number and needs a
mantissa.
Examples
use fundu::{Duration, DurationParser};
let mut parser = DurationParser::new();
parser.number_is_optional(true);
assert_eq!(parser.parse("ns"), Ok(Duration::positive(0, 1)));
assert_eq!(parser.parse("+ns"), Ok(Duration::positive(0, 1)));
sourcepub fn parse_multiple(
&mut self,
value: bool,
conjunctions: Option<&'a [&'a str]>
) -> &mut Self
pub fn parse_multiple( &mut self, value: bool, conjunctions: Option<&'a [&'a str]> ) -> &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. It’s also possible to use complete words, like and
as
conjunctions between durations. Note that the Delimiter
is still needed to be set if
conjunctions are used in order to separate the conjunctions from durations.
Like a single duration, the summed durations saturate at crate::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
crate::Duration::MAX
, so any ParseError
s 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 is a notable constellation which has an effect on how durations are parsed:
If DurationParser::allow_time_unit_delimiter
is set to some delimiter, the Delimiter
of this method and the Delimiter
of the allow_time_unit_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
crate::Duration
will differ:
use fundu::{Duration, DurationParser};
let mut parser = DurationParser::new();
parser.parse_multiple(true, None).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::positive(3, 1)));
// Here, the parser parses `1 s` and then `1 ns`.
parser.allow_time_unit_delimiter(true);
assert_eq!(parser.parse("1 s 1 ns"), Ok(Duration::positive(1, 1)));
Examples
use fundu::{Duration, DurationParser};
let mut parser = DurationParser::new();
parser.parse_multiple(true, Some(&["and"]));
assert_eq!(
parser.parse("1.5h 2e+2ns"),
Ok(Duration::positive(5400, 200))
);
assert_eq!(
parser.parse("55s500ms"),
Ok(Duration::positive(55, 500_000_000))
);
assert_eq!(parser.parse("1m and 1ns"), Ok(Duration::positive(60, 1)));
assert_eq!(
parser.parse("1. .1"),
Ok(Duration::positive(1, 100_000_000))
);
assert_eq!(parser.parse("2h"), Ok(Duration::positive(2 * 60 * 60, 0)));
assert_eq!(
parser.parse("300ms20s 5d"),
Ok(Duration::positive(5 * 60 * 60 * 24 + 20, 300_000_000))
);
sourcepub fn set_inner_delimiter(&mut self, delimiter: Delimiter) -> &mut Self
pub fn set_inner_delimiter(&mut self, delimiter: Delimiter) -> &mut Self
Set the inner Delimiter
to something different then the default
u8::is_ascii_whitespace
Where the inner delimiter occurs, depends on other options:
DurationParser::allow_sign_delimiter
: Between the sign and the numberDurationParser::allow_time_unit_delimiter
: Between the number and the time unitDurationParser::allow_ago
: Between the time unit and theago
keyword
Examples
use fundu::{Duration, DurationParser};
let mut parser = DurationParser::with_all_time_units();
parser
.allow_ago(true)
.set_inner_delimiter(|byte| byte == b'#');
assert_eq!(parser.parse("1.5h#ago"), Ok(Duration::negative(5400, 0)));
let mut parser = DurationParser::with_all_time_units();
parser
.allow_sign_delimiter(true)
.set_inner_delimiter(|byte| byte == b'#');
assert_eq!(parser.parse("+##1.5h"), Ok(Duration::positive(5400, 0)));
sourcepub fn set_outer_delimiter(&mut self, delimiter: Delimiter) -> &mut Self
pub fn set_outer_delimiter(&mut self, delimiter: Delimiter) -> &mut Self
Set the outer Delimiter
to something different then the default
u8::is_ascii_whitespace
The outer delimiter is used to separate multiple durations like in 1second 1minute
and is
therefore used only if DurationParser::parse_multiple
is set. If conjunctions
are set,
this delimiter also separates the conjunction from the durations (like in 1second and 1minute
)
Examples
use fundu::{Duration, DurationParser};
let mut parser = DurationParser::with_all_time_units();
parser
.parse_multiple(true, None)
.set_outer_delimiter(|byte| byte == b';');
assert_eq!(
parser.parse("1.5h;2e+2ns"),
Ok(Duration::positive(5400, 200))
);
let mut parser = DurationParser::with_all_time_units();
parser
.parse_multiple(true, Some(&["and"]))
.set_outer_delimiter(|byte| byte == b';');
assert_eq!(
parser.parse("1.5h;and;2e+2ns"),
Ok(Duration::positive(5400, 200))
);
sourcepub fn get_current_time_units(&self) -> Vec<TimeUnit>
pub fn get_current_time_units(&self) -> Vec<TimeUnit>
Return the currently defined set of TimeUnit
.
Examples
use fundu::DurationParser;
use fundu::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<'a> Debug for DurationParser<'a>
impl<'a> Debug for DurationParser<'a>
source§impl<'a> Default for DurationParser<'a>
impl<'a> Default for DurationParser<'a>
source§impl<'a> PartialEq<DurationParser<'a>> for DurationParser<'a>
impl<'a> PartialEq<DurationParser<'a>> for DurationParser<'a>
source§fn eq(&self, other: &DurationParser<'a>) -> bool
fn eq(&self, other: &DurationParser<'a>) -> bool
self
and other
values to be equal, and is used
by ==
.