pub(crate) struct DurationUnits {
values: [u64; 10],
fraction: Option<u32>,
sign: Sign,
min: Option<Unit>,
max: Option<Unit>,
any_non_zero_units: bool,
}Expand description
A container for holding a partially parsed duration.
This is used for parsing into Span, SignedDuration and (hopefully
soon) std::time::Duration. It’s also used for both the ISO 8601
duration and “friendly” format.
This replaced a significant chunk of code that was bespoke to each combination of duration type and format.
The idea behind it is that we parse each duration component as an unsigned
64-bit integer and keep track of the sign separately. This is a critical
aspect that was motivated by being able to roundtrip all legal values of
a 96-bit signed integer number of nanoseconds (i.e., SignedDuration).
In particular, if we used i64 to represent each component, then it
makes it much more difficult to parse, e.g., 9223372036854775808 seconds ago. Namely, 9223372036854775808 is not a valid i64 but
-9223372036854775808 is. Notably, the sign is indicated by a suffix,
so we don’t know it’s negative when parsing the integer itself. So we
represent all components as their unsigned absolute value and apply the
sign at the end.
This also centralizes a lot of thorny duration math and opens up the opportunity for tighter optimization.
Fields§
§values: [u64; 10]The parsed unit values in descending order. That is, nanoseconds are at index 0 while years are at index 9.
fraction: Option<u32>Any fractional component parsed. The fraction is necessarily a fraction of the minimum unit if present.
sign: SignThe sign of the duration. This may be set at any time.
Note that this defaults to zero! So callers will always want to set this.
min: Option<Unit>The smallest unit value that was explicitly set.
max: Option<Unit>The largest unit value that was explicitly set.
any_non_zero_units: boolWhether there are any non-zero units.
Implementations§
Source§impl DurationUnits
impl DurationUnits
Sourcepub(crate) fn set_unit_value(
&mut self,
unit: Unit,
value: u64,
) -> Result<(), Error>
pub(crate) fn set_unit_value( &mut self, unit: Unit, value: u64, ) -> Result<(), Error>
Set the duration component value for the given unit.
The value here is always unsigned. To deal with negative values, set the sign independently. It will be accounted for when using one of this type’s methods for converting to a concrete duration type.
§Panics
When this is called after set_fraction.
§Errors
Since this is meant to be used in service of duration parsing and all duration parsing proceeds from largest to smallest units, this will return an error if the given unit is bigger than or equal to any previously set unit. This also implies that this can only be called at most once for each unit value.
Sourcepub(crate) fn set_hms(
&mut self,
hours: u64,
minutes: u64,
seconds: u64,
fraction: Option<u32>,
) -> Result<(), Error>
pub(crate) fn set_hms( &mut self, hours: u64, minutes: u64, seconds: u64, fraction: Option<u32>, ) -> Result<(), Error>
A convenience routine for setting values parsed from an HH:MM:SS
format (including the fraction).
§Errors
This forwards errors from DurationUnits::set_unit_value. It will also
return an error is the minimum parsed unit (so far) is smaller than
days. (Since HH:MM:SS can only appear after units of years, months,
weeks or days.)
Sourcepub(crate) fn set_fraction(&mut self, fraction: u32) -> Result<(), Error>
pub(crate) fn set_fraction(&mut self, fraction: u32) -> Result<(), Error>
Set the fractional value.
This is always interpreted as a fraction of the minimal unit.
Callers must ensure this is called after the last call to
DurationUnits::set_unit_value.
§Panics
When fraction is not in the range 0..=999_999_999. Callers are
expected to uphold this invariant.
§Errors
This will return an error if the minimum unit is Unit::Nanosecond.
(Because fractional nanoseconds are not supported.) This will also
return an error if the minimum unit is bigger than Unit::Hour.
Sourcepub(crate) fn set_sign(&mut self, sign: Sign)
pub(crate) fn set_sign(&mut self, sign: Sign)
Set the sign associated with the components.
The sign applies to the entire duration. There is no support for having some components signed and some unsigned.
If no sign is set, then it is assumed to be zero. Note also that even if a sign is explicitly set and all unit values are zero, then the sign will be set to zero.
Sourcepub(crate) fn to_span(&self) -> Result<Span, Error>
pub(crate) fn to_span(&self) -> Result<Span, Error>
Convert these duration components to a Span.
§Errors
If any individual unit exceeds the limits of a Span, or if the units
combine to exceed what can be represented by a Span, then this
returns an error.
This also returns an error if no units were set.
Sourcefn to_span_general(&self) -> Result<Span, Error>
fn to_span_general(&self) -> Result<Span, Error>
The “general” implementation of DurationUnits::to_span.
This handles all possible cases, including fractional units, with good error handling. Basically, we take this path when we think an error could occur. But this function is more bloaty and does more work, so the more it can be avoided, the better.
Sourcepub(crate) fn to_signed_duration(&self) -> Result<SignedDuration, Error>
pub(crate) fn to_signed_duration(&self) -> Result<SignedDuration, Error>
Convert these duration components to a SignedDuration.
§Errors
If the total number of nanoseconds represented by all units combined exceeds what can bit in a 96-bit signed integer, then an error is returned.
An error is also returned if any calendar units (days or greater) were set or if no units were set.
Sourcefn to_signed_duration_general(&self) -> Result<SignedDuration, Error>
fn to_signed_duration_general(&self) -> Result<SignedDuration, Error>
The “general” implementation of DurationUnits::to_signed_duration.
This handles all possible cases, including fractional units, with good error handling. Basically, we take this path when we think an error could occur. But this function is more bloaty and does more work, so the more it can be avoided, the better.
Sourcepub(crate) fn to_unsigned_duration(&self) -> Result<Duration, Error>
pub(crate) fn to_unsigned_duration(&self) -> Result<Duration, Error>
Convert these duration components to a core::time::Duration.
§Errors
If the total number of nanoseconds represented by all units combined exceeds what can bit in a 96-bit signed integer, then an error is returned.
An error is also returned if any calendar units (days or greater) were set or if no units were set.
Sourcefn to_unsigned_duration_general(&self) -> Result<Duration, Error>
fn to_unsigned_duration_general(&self) -> Result<Duration, Error>
The “general” implementation of DurationUnits::to_unsigned_duration.
This handles all possible cases, including fractional units, with good error handling. Basically, we take this path when we think an error could occur. But this function is more bloaty and does more work, so the more it can be avoided, the better.
Sourcepub(crate) fn get_min(&self) -> Option<Unit>
pub(crate) fn get_min(&self) -> Option<Unit>
Returns the minimum unit set.
This only returns None when no units have been set.
Sourcefn get_min_max_units(&self) -> Result<(Unit, Unit), Error>
fn get_min_max_units(&self) -> Result<(Unit, Unit), Error>
Returns the minimum and maximum units set.
This returns an error if no units were set. (Since this means there were no parsed duration components.)
Sourcefn get_unit_value(&self, unit: Unit) -> Result<i64, Error>
fn get_unit_value(&self, unit: Unit) -> Result<i64, Error>
Returns the corresponding unit value using the set signed-ness.