jiff::fmt::friendly::parser

Struct SpanParser

Source
pub struct SpanParser {
    _private: (),
}
Expand description

A parser for Jiff’s “friendly” duration format.

See the module documentation for more details on the precise format supported by this parser.

Unlike SpanPrinter, this parser doesn’t have any configuration knobs. While it may grow some in the future, the approach taken here is for the parser to support the entire grammar. That is, the parser can parse anything emitted by SpanPrinter. (And indeed, the parser can even handle things that the printer can’t emit due to lack of configurability. For example, 1hour1m is a valid friendly duration, but SpanPrinter cannot emit it due to a mixing of verbose and compact designator labels.)

§Advice

Since this parser has no configuration, there are generally only two reasons why you might want to use this type specifically:

  1. You need to parse from &[u8].
  2. You need to parse only the “friendly” format.

Otherwise, you can use the FromStr implementations on both Span and SignedDuration, which automatically support the friendly format in addition to the ISO 8601 format simultaneously:

use jiff::{SignedDuration, Span, ToSpan};

let span: Span = "5 years, 2 months".parse()?;
assert_eq!(span, 5.years().months(2).fieldwise());

let sdur: SignedDuration = "5 hours, 2 minutes".parse()?;
assert_eq!(sdur, SignedDuration::new(5 * 60 * 60 + 2 * 60, 0));

§Example

This example shows how to parse a Span directly from &str:

use jiff::{fmt::friendly::SpanParser, ToSpan};

static PARSER: SpanParser = SpanParser::new();

let string = "1 year, 3 months, 15:00:01.3";
let span = PARSER.parse_span(string)?;
assert_eq!(
    span,
    1.year().months(3).hours(15).seconds(1).milliseconds(300).fieldwise(),
);

// Negative durations are supported too!
let string = "1 year, 3 months, 15:00:01.3 ago";
let span = PARSER.parse_span(string)?;
assert_eq!(
    span,
    -1.year().months(3).hours(15).seconds(1).milliseconds(300).fieldwise(),
);

Fields§

§_private: ()

Implementations§

Source§

impl SpanParser

Source

pub const fn new() -> SpanParser

Creates a new parser for the “friendly” duration format.

The parser returned uses the default configuration. (Although, at time of writing, there are no available configuration options for this parser.) This is identical to SpanParser::default, but it can be used in a const context.

§Example

This example shows how to parse a Span directly from &[u8]:

use jiff::{fmt::friendly::SpanParser, ToSpan};

static PARSER: SpanParser = SpanParser::new();

let bytes = b"1 year 3 months 15 hours 1300ms";
let span = PARSER.parse_span(bytes)?;
assert_eq!(
    span,
    1.year().months(3).hours(15).milliseconds(1300).fieldwise(),
);
Source

pub fn parse_span<I: AsRef<[u8]>>(&self, input: I) -> Result<Span, Error>

Run the parser on the given string (which may be plain bytes) and, if successful, return the parsed Span.

See the module documentation for more details on the specific grammar supported by this parser.

§Example

This shows a number of different duration formats that can be parsed into a Span:

use jiff::{fmt::friendly::SpanParser, ToSpan};

let spans = [
    ("40d", 40.days()),
    ("40 days", 40.days()),
    ("1y1d", 1.year().days(1)),
    ("1yr 1d", 1.year().days(1)),
    ("3d4h59m", 3.days().hours(4).minutes(59)),
    ("3 days, 4 hours, 59 minutes", 3.days().hours(4).minutes(59)),
    ("3d 4h 59m", 3.days().hours(4).minutes(59)),
    ("2h30m", 2.hours().minutes(30)),
    ("2h 30m", 2.hours().minutes(30)),
    ("1mo", 1.month()),
    ("1w", 1.week()),
    ("1 week", 1.week()),
    ("1w4d", 1.week().days(4)),
    ("1 wk 4 days", 1.week().days(4)),
    ("1m", 1.minute()),
    ("0.0021s", 2.milliseconds().microseconds(100)),
    ("0s", 0.seconds()),
    ("0d", 0.seconds()),
    ("0 days", 0.seconds()),
    (
        "1y1mo1d1h1m1.1s",
        1.year().months(1).days(1).hours(1).minutes(1).seconds(1).milliseconds(100),
    ),
    (
        "1yr 1mo 1day 1hr 1min 1.1sec",
        1.year().months(1).days(1).hours(1).minutes(1).seconds(1).milliseconds(100),
    ),
    (
        "1 year, 1 month, 1 day, 1 hour, 1 minute 1.1 seconds",
        1.year().months(1).days(1).hours(1).minutes(1).seconds(1).milliseconds(100),
    ),
    (
        "1 year, 1 month, 1 day, 01:01:01.1",
        1.year().months(1).days(1).hours(1).minutes(1).seconds(1).milliseconds(100),
    ),
    (
        "1 yr, 1 month, 1 d, 1 h, 1 min 1.1 second",
        1.year().months(1).days(1).hours(1).minutes(1).seconds(1).milliseconds(100),
    ),
];

static PARSER: SpanParser = SpanParser::new();
for (string, span) in spans {
    let parsed = PARSER.parse_span(string)?;
    assert_eq!(
        span.fieldwise(),
        parsed.fieldwise(),
        "result of parsing {string:?}",
    );
}
Source

pub fn parse_duration<I: AsRef<[u8]>>( &self, input: I, ) -> Result<SignedDuration, Error>

Run the parser on the given string (which may be plain bytes) and, if successful, return the parsed SignedDuration.

See the module documentation for more details on the specific grammar supported by this parser.

§Example

This shows a number of different duration formats that can be parsed into a SignedDuration:

use jiff::{fmt::friendly::SpanParser, SignedDuration};

let durations = [
    ("2h30m", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
    ("2 hrs 30 mins", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
    ("2 hours 30 minutes", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
    ("2 hrs 30 minutes", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
    ("2.5h", SignedDuration::from_secs(2 * 60 * 60 + 30 * 60)),
    ("1m", SignedDuration::from_mins(1)),
    ("1.5m", SignedDuration::from_secs(90)),
    ("0.0021s", SignedDuration::new(0, 2_100_000)),
    ("0s", SignedDuration::ZERO),
    ("0.000000001s", SignedDuration::from_nanos(1)),
];

static PARSER: SpanParser = SpanParser::new();
for (string, duration) in durations {
    let parsed = PARSER.parse_duration(string)?;
    assert_eq!(duration, parsed, "result of parsing {string:?}");
}
Source

fn parse_to_span<'i>(&self, input: &'i [u8]) -> Result<Parsed<'i, Span>, Error>

Source

fn parse_to_duration<'i>( &self, input: &'i [u8], ) -> Result<Parsed<'i, SignedDuration>, Error>

Source

fn parse_units_to_span<'i>( &self, input: &'i [u8], first_unit_value: ri64<{ _ }, { _ }>, ) -> Result<Parsed<'i, Span>, Error>

Source

fn parse_units_to_duration<'i>( &self, input: &'i [u8], first_unit_value: ri64<{ _ }, { _ }>, ) -> Result<Parsed<'i, SignedDuration>, Error>

Source

fn parse_hms_maybe<'i>( &self, input: &'i [u8], hour: ri64<{ _ }, { _ }>, ) -> Result<Parsed<'i, Option<HMS>>, Error>

This possibly parses a HH:MM:SS[.fraction].

This expects that a unit value has been parsed and looks for a : at input[0]. If : is found, then this proceeds to parse HMS. Otherwise, a None value is returned.

Source

fn parse_hms<'i>( &self, input: &'i [u8], hour: ri64<{ _ }, { _ }>, ) -> Result<Parsed<'i, HMS>, Error>

This parses a HH:MM:SS[.fraction] when it is known/expected to be present.

This is also marked as non-inlined since we expect this to be a less common case. Where as parse_hms_maybe is called unconditionally to check to see if the HMS should be parsed.

This assumes that the beginning of input immediately follows the first : in HH:MM:SS[.fraction].

Source

fn parse_unit_value<'i>( &self, input: &'i [u8], ) -> Result<Parsed<'i, Option<ri64<{ _ }, { _ }>>>, Error>

Parsed a unit value, i.e., an integer.

If no digits ([0-9]) were found at the current position of the parser then None is returned. This means, for example, that parsing a duration should stop.

Note that this is safe to call on untrusted input. It will not attempt to consume more input than could possibly fit into a parsed integer.

Source

fn parse_unit_designator<'i>( &self, input: &'i [u8], ) -> Result<Parsed<'i, Unit>, Error>

Parse a unit designator, e.g., years or nano.

If no designator could be found, including if the given input is empty, then this return an error.

This does not attempt to handle leading or trailing whitespace.

Source

fn parse_prefix_sign<'i>( &self, input: &'i [u8], ) -> Parsed<'i, Option<ri8<-1, 1>>>

Parses an optional prefix sign from the given input.

A prefix sign is either a + or a -. If neither are found, then None is returned.

Source

fn parse_suffix_sign<'i>( &self, prefix_sign: Option<ri8<-1, 1>>, input: &'i [u8], ) -> Result<Parsed<'i, ri8<-1, 1>>, Error>

Parses an optional suffix sign from the given input.

This requires, as input, the result of parsing a prefix sign since this will return an error if both a prefix and a suffix sign were found.

A suffix sign is the string ago. Any other string means that there is no suffix sign. This will also look for mandatory whitespace and eat any additional optional whitespace. i.e., This should be called immediately after parsing the last unit designator/label.

Regardless of whether a prefix or suffix sign was found, a definitive sign is returned. (When there’s no prefix or suffix sign, then the sign returned is positive.)

Source

fn parse_optional_comma<'i>( &self, input: &'i [u8], ) -> Result<Parsed<'i, ()>, Error>

Parses an optional comma following a unit designator.

If a comma is seen, then it is mandatory that it be followed by whitespace.

This also takes care to provide a custom error message if the end of input is seen after a comma.

If input doesn’t start with a comma, then this is a no-op.

Source

fn parse_optional_whitespace<'i>(&self, input: &'i [u8]) -> Parsed<'i, ()>

Parses zero or more bytes of ASCII whitespace.

Trait Implementations§

Source§

impl Clone for SpanParser

Source§

fn clone(&self) -> SpanParser

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SpanParser

Source§

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

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

impl Default for SpanParser

Source§

fn default() -> SpanParser

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

Auto Trait Implementations§

Blanket Implementations§

Source§

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

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

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

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

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

Source§

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

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. 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 T
where 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

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 T
where U: TryFrom<T>,

Source§

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.