jiff/fmt/
util.rs

1use crate::{
2    error::{err, ErrorContext},
3    fmt::Parsed,
4    util::{c::Sign, escape, parse, t},
5    Error, SignedDuration, Span, Unit,
6};
7
8/// A simple formatter for converting `i64` values to ASCII byte strings.
9///
10/// This avoids going through the formatting machinery which seems to
11/// substantially slow things down.
12///
13/// The `itoa` crate does the same thing as this formatter, but is a bit
14/// faster. We roll our own which is a bit slower, but gets us enough of a win
15/// to be satisfied with and with (almost) pure safe code.
16///
17/// By default, this only includes the sign if it's negative. To always include
18/// the sign, set `force_sign` to `true`.
19#[derive(Clone, Copy, Debug)]
20pub(crate) struct DecimalFormatter {
21    force_sign: Option<bool>,
22    minimum_digits: u8,
23    padding_byte: u8,
24}
25
26impl DecimalFormatter {
27    /// Creates a new decimal formatter using the default configuration.
28    pub(crate) const fn new() -> DecimalFormatter {
29        DecimalFormatter {
30            force_sign: None,
31            minimum_digits: 0,
32            padding_byte: b'0',
33        }
34    }
35
36    /// Format the given value using this configuration as a signed decimal
37    /// ASCII number.
38    #[cfg_attr(feature = "perf-inline", inline(always))]
39    pub(crate) const fn format_signed(&self, value: i64) -> Decimal {
40        Decimal::signed(self, value)
41    }
42
43    /// Format the given value using this configuration as an unsigned decimal
44    /// ASCII number.
45    #[cfg_attr(feature = "perf-inline", inline(always))]
46    pub(crate) const fn format_unsigned(&self, value: u64) -> Decimal {
47        Decimal::unsigned(self, value)
48    }
49
50    /// Forces the sign to be rendered, even if it's positive.
51    ///
52    /// When `zero_is_positive` is true, then a zero value is formatted with a
53    /// positive sign. Otherwise, it is formatted with a negative sign.
54    ///
55    /// Regardless of this setting, a sign is never emitted when formatting an
56    /// unsigned integer.
57    #[cfg(test)]
58    pub(crate) const fn force_sign(
59        self,
60        zero_is_positive: bool,
61    ) -> DecimalFormatter {
62        DecimalFormatter { force_sign: Some(zero_is_positive), ..self }
63    }
64
65    /// The minimum number of digits/padding that this number should be
66    /// formatted with. If the number would have fewer digits than this, then
67    /// it is padded out with the padding byte (which is zero by default) until
68    /// the minimum is reached.
69    ///
70    /// The minimum number of digits is capped at the maximum number of digits
71    /// for an i64 value (19) or a u64 value (20).
72    pub(crate) const fn padding(self, mut digits: u8) -> DecimalFormatter {
73        if digits > Decimal::MAX_I64_DIGITS {
74            digits = Decimal::MAX_I64_DIGITS;
75        }
76        DecimalFormatter { minimum_digits: digits, ..self }
77    }
78
79    /// The padding byte to use when `padding` is set.
80    ///
81    /// The default is `0`.
82    pub(crate) const fn padding_byte(self, byte: u8) -> DecimalFormatter {
83        DecimalFormatter { padding_byte: byte, ..self }
84    }
85
86    /// Returns the minimum number of digits for a signed value.
87    const fn get_signed_minimum_digits(&self) -> u8 {
88        if self.minimum_digits <= Decimal::MAX_I64_DIGITS {
89            self.minimum_digits
90        } else {
91            Decimal::MAX_I64_DIGITS
92        }
93    }
94
95    /// Returns the minimum number of digits for an unsigned value.
96    const fn get_unsigned_minimum_digits(&self) -> u8 {
97        if self.minimum_digits <= Decimal::MAX_U64_DIGITS {
98            self.minimum_digits
99        } else {
100            Decimal::MAX_U64_DIGITS
101        }
102    }
103}
104
105impl Default for DecimalFormatter {
106    fn default() -> DecimalFormatter {
107        DecimalFormatter::new()
108    }
109}
110
111/// A formatted decimal number that can be converted to a sequence of bytes.
112#[derive(Debug)]
113pub(crate) struct Decimal {
114    buf: [u8; Self::MAX_LEN as usize],
115    start: u8,
116    end: u8,
117}
118
119impl Decimal {
120    /// Discovered via
121    /// `i64::MIN.to_string().len().max(u64::MAX.to_string().len())`.
122    const MAX_LEN: u8 = 20;
123    /// Discovered via `i64::MAX.to_string().len()`.
124    const MAX_I64_DIGITS: u8 = 19;
125    /// Discovered via `u64::MAX.to_string().len()`.
126    const MAX_U64_DIGITS: u8 = 20;
127
128    /// Using the given formatter, turn the value given into an unsigned
129    /// decimal representation using ASCII bytes.
130    #[cfg_attr(feature = "perf-inline", inline(always))]
131    const fn unsigned(
132        formatter: &DecimalFormatter,
133        mut value: u64,
134    ) -> Decimal {
135        let mut decimal = Decimal {
136            buf: [0; Self::MAX_LEN as usize],
137            start: Self::MAX_LEN,
138            end: Self::MAX_LEN,
139        };
140        loop {
141            decimal.start -= 1;
142
143            let digit = (value % 10) as u8;
144            value /= 10;
145            decimal.buf[decimal.start as usize] = b'0' + digit;
146            if value == 0 {
147                break;
148            }
149        }
150
151        while decimal.len() < formatter.get_unsigned_minimum_digits() {
152            decimal.start -= 1;
153            decimal.buf[decimal.start as usize] = formatter.padding_byte;
154        }
155        decimal
156    }
157
158    /// Using the given formatter, turn the value given into a signed decimal
159    /// representation using ASCII bytes.
160    #[cfg_attr(feature = "perf-inline", inline(always))]
161    const fn signed(formatter: &DecimalFormatter, mut value: i64) -> Decimal {
162        // Specialize the common case to generate tighter codegen.
163        if value >= 0 && formatter.force_sign.is_none() {
164            let mut decimal = Decimal {
165                buf: [0; Self::MAX_LEN as usize],
166                start: Self::MAX_LEN,
167                end: Self::MAX_LEN,
168            };
169            loop {
170                decimal.start -= 1;
171
172                let digit = (value % 10) as u8;
173                value /= 10;
174                decimal.buf[decimal.start as usize] = b'0' + digit;
175                if value == 0 {
176                    break;
177                }
178            }
179
180            while decimal.len() < formatter.get_signed_minimum_digits() {
181                decimal.start -= 1;
182                decimal.buf[decimal.start as usize] = formatter.padding_byte;
183            }
184            return decimal;
185        }
186        Decimal::signed_cold(formatter, value)
187    }
188
189    #[cold]
190    #[inline(never)]
191    const fn signed_cold(formatter: &DecimalFormatter, value: i64) -> Decimal {
192        let sign = value.signum();
193        let Some(mut value) = value.checked_abs() else {
194            let buf = [
195                b'-', b'9', b'2', b'2', b'3', b'3', b'7', b'2', b'0', b'3',
196                b'6', b'8', b'5', b'4', b'7', b'7', b'5', b'8', b'0', b'8',
197            ];
198            return Decimal { buf, start: 0, end: Self::MAX_LEN };
199        };
200        let mut decimal = Decimal {
201            buf: [0; Self::MAX_LEN as usize],
202            start: Self::MAX_LEN,
203            end: Self::MAX_LEN,
204        };
205        loop {
206            decimal.start -= 1;
207
208            let digit = (value % 10) as u8;
209            value /= 10;
210            decimal.buf[decimal.start as usize] = b'0' + digit;
211            if value == 0 {
212                break;
213            }
214        }
215        while decimal.len() < formatter.get_signed_minimum_digits() {
216            decimal.start -= 1;
217            decimal.buf[decimal.start as usize] = formatter.padding_byte;
218        }
219        if sign < 0 {
220            decimal.start -= 1;
221            decimal.buf[decimal.start as usize] = b'-';
222        } else if let Some(zero_is_positive) = formatter.force_sign {
223            let ascii_sign =
224                if sign > 0 || zero_is_positive { b'+' } else { b'-' };
225            decimal.start -= 1;
226            decimal.buf[decimal.start as usize] = ascii_sign;
227        }
228        decimal
229    }
230
231    /// Returns the total number of ASCII bytes (including the sign) that are
232    /// used to represent this decimal number.
233    #[inline]
234    const fn len(&self) -> u8 {
235        self.end - self.start
236    }
237
238    /// Returns the ASCII representation of this decimal as a byte slice.
239    ///
240    /// The slice returned is guaranteed to be valid ASCII.
241    #[inline]
242    fn as_bytes(&self) -> &[u8] {
243        &self.buf[usize::from(self.start)..usize::from(self.end)]
244    }
245
246    /// Returns the ASCII representation of this decimal as a string slice.
247    #[inline]
248    pub(crate) fn as_str(&self) -> &str {
249        // SAFETY: This is safe because all bytes written to `self.buf` are
250        // guaranteed to be ASCII (including in its initial state), and thus,
251        // any subsequence is guaranteed to be valid UTF-8.
252        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
253    }
254}
255
256/// A simple formatter for converting fractional components to ASCII byte
257/// strings.
258///
259/// We only support precision to 9 decimal places, which corresponds to
260/// nanosecond precision as a fractional second component.
261#[derive(Clone, Copy, Debug)]
262pub(crate) struct FractionalFormatter {
263    precision: Option<u8>,
264}
265
266impl FractionalFormatter {
267    /// Creates a new fractional formatter using the given precision settings.
268    pub(crate) const fn new() -> FractionalFormatter {
269        FractionalFormatter { precision: None }
270    }
271
272    /// Format the given value using this configuration as a decimal ASCII
273    /// fractional number.
274    pub(crate) const fn format(&self, value: u32) -> Fractional {
275        Fractional::new(self, value)
276    }
277
278    /// Set the precision.
279    ///
280    /// If the `precision` is greater than `9`, then it is clamped to `9`.
281    ///
282    /// When the precision is not set, then it is automatically determined
283    /// based on the value.
284    pub(crate) const fn precision(
285        self,
286        precision: Option<u8>,
287    ) -> FractionalFormatter {
288        let precision = match precision {
289            None => None,
290            Some(p) if p > 9 => Some(9),
291            Some(p) => Some(p),
292        };
293        FractionalFormatter { precision, ..self }
294    }
295
296    /// Returns true if and only if at least one digit will be written for the
297    /// given value.
298    ///
299    /// This is useful for callers that need to know whether to write
300    /// a decimal separator, e.g., `.`, before the digits.
301    pub(crate) fn will_write_digits(self, value: u32) -> bool {
302        self.precision.map_or_else(|| value != 0, |p| p > 0)
303    }
304
305    /// Returns true if and only if this formatter has an explicit non-zero
306    /// precision setting.
307    ///
308    /// This is useful for determining whether something like `0.000` needs to
309    /// be written in the case of a `precision=Some(3)` setting and a zero
310    /// value.
311    pub(crate) fn has_non_zero_fixed_precision(self) -> bool {
312        self.precision.map_or(false, |p| p > 0)
313    }
314
315    /// Returns true if and only if this formatter has fixed zero precision.
316    /// That is, no matter what is given as input, a fraction is never written.
317    pub(crate) fn has_zero_fixed_precision(self) -> bool {
318        self.precision.map_or(false, |p| p == 0)
319    }
320}
321
322/// A formatted fractional number that can be converted to a sequence of bytes.
323#[derive(Debug)]
324pub(crate) struct Fractional {
325    buf: [u8; Self::MAX_LEN as usize],
326    end: u8,
327}
328
329impl Fractional {
330    /// Since we don't support precision bigger than this.
331    const MAX_LEN: u8 = 9;
332
333    /// Using the given formatter, turn the value given into a fractional
334    /// decimal representation using ASCII bytes.
335    ///
336    /// Note that the fractional number returned *may* expand to an empty
337    /// slice of bytes. This occurs whenever the precision is set to `0`, or
338    /// when the precision is not set and the value is `0`. Any non-zero
339    /// explicitly set precision guarantees that the slice returned is not
340    /// empty.
341    ///
342    /// This panics if the value given isn't in the range `0..=999_999_999`.
343    pub(crate) const fn new(
344        formatter: &FractionalFormatter,
345        mut value: u32,
346    ) -> Fractional {
347        assert!(value <= 999_999_999);
348        let mut fractional = Fractional {
349            buf: [b'0'; Self::MAX_LEN as usize],
350            end: Self::MAX_LEN,
351        };
352        let mut i = 9;
353        loop {
354            i -= 1;
355
356            let digit = (value % 10) as u8;
357            value /= 10;
358            fractional.buf[i] += digit;
359            if value == 0 {
360                break;
361            }
362        }
363        if let Some(precision) = formatter.precision {
364            fractional.end = precision;
365        } else {
366            while fractional.end > 0
367                && fractional.buf[fractional.end as usize - 1] == b'0'
368            {
369                fractional.end -= 1;
370            }
371        }
372        fractional
373    }
374
375    /// Returns the ASCII representation of this fractional number as a byte
376    /// slice. The slice returned may be empty.
377    ///
378    /// The slice returned is guaranteed to be valid ASCII.
379    pub(crate) fn as_bytes(&self) -> &[u8] {
380        &self.buf[..usize::from(self.end)]
381    }
382
383    /// Returns the ASCII representation of this fractional number as a string
384    /// slice. The slice returned may be empty.
385    pub(crate) fn as_str(&self) -> &str {
386        // SAFETY: This is safe because all bytes written to `self.buf` are
387        // guaranteed to be ASCII (including in its initial state), and thus,
388        // any subsequence is guaranteed to be valid UTF-8.
389        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
390    }
391}
392
393/// A container for holding a partially parsed duration.
394///
395/// This is used for parsing into `Span`, `SignedDuration` and (hopefully
396/// soon) `std::time::Duration`. It's _also_ used for both the ISO 8601
397/// duration and "friendly" format.
398///
399/// This replaced a significant chunk of code that was bespoke to each
400/// combination of duration type _and_ format.
401///
402/// The idea behind it is that we parse each duration component as an unsigned
403/// 64-bit integer and keep track of the sign separately. This is a critical
404/// aspect that was motivated by being able to roundtrip all legal values of
405/// a 96-bit signed integer number of nanoseconds (i.e., `SignedDuration`).
406/// In particular, if we used `i64` to represent each component, then it
407/// makes it much more difficult to parse, e.g., `9223372036854775808
408/// seconds ago`. Namely, `9223372036854775808` is not a valid `i64` but
409/// `-9223372036854775808` is. Notably, the sign is indicated by a suffix,
410/// so we don't know it's negative when parsing the integer itself. So we
411/// represent all components as their unsigned absolute value and apply the
412/// sign at the end.
413///
414/// This also centralizes a lot of thorny duration math and opens up the
415/// opportunity for tighter optimization.
416#[derive(Debug, Default)]
417pub(crate) struct DurationUnits {
418    /// The parsed unit values in descending order. That is, nanoseconds are
419    /// at index 0 while years are at index 9.
420    values: [u64; 10],
421    /// Any fractional component parsed. The fraction is necessarily a fraction
422    /// of the minimum unit if present.
423    fraction: Option<u32>,
424    /// The sign of the duration. This may be set at any time.
425    ///
426    /// Note that this defaults to zero! So callers will always want to set
427    /// this.
428    sign: Sign,
429    /// The smallest unit value that was explicitly set.
430    min: Option<Unit>,
431    /// The largest unit value that was explicitly set.
432    max: Option<Unit>,
433    /// Whether there are any non-zero units.
434    any_non_zero_units: bool,
435}
436
437impl DurationUnits {
438    /// Set the duration component value for the given unit.
439    ///
440    /// The value here is always unsigned. To deal with negative values, set
441    /// the sign independently. It will be accounted for when using one of this
442    /// type's methods for converting to a concrete duration type.
443    ///
444    /// # Panics
445    ///
446    /// When this is called after `set_fraction`.
447    ///
448    /// # Errors
449    ///
450    /// Since this is meant to be used in service of duration parsing and all
451    /// duration parsing proceeds from largest to smallest units, this will
452    /// return an error if the given unit is bigger than or equal to any
453    /// previously set unit. This also implies that this can only be called
454    /// at most once for each unit value.
455    #[cfg_attr(feature = "perf-inline", inline(always))]
456    pub(crate) fn set_unit_value(
457        &mut self,
458        unit: Unit,
459        value: u64,
460    ) -> Result<(), Error> {
461        assert!(self.fraction.is_none());
462
463        if let Some(min) = self.min {
464            if min <= unit {
465                return Err(err!(
466                    "found value {value:?} with unit {unit} \
467                     after unit {prev_unit}, but units must be \
468                     written from largest to smallest \
469                     (and they can't be repeated)",
470                    unit = unit.singular(),
471                    prev_unit = min.singular(),
472                ));
473            }
474        }
475        // Given the above check, the given unit must be smaller than any we
476        // have seen so far.
477        self.min = Some(unit);
478        // The maximum unit is always the first unit set, since we can never
479        // see a unit bigger than it without an error occurring.
480        if self.max.is_none() {
481            self.max = Some(unit);
482        }
483        self.values[unit.as_usize()] = value;
484        self.any_non_zero_units = self.any_non_zero_units || value != 0;
485        Ok(())
486    }
487
488    /// A convenience routine for setting values parsed from an `HH:MM:SS`
489    /// format (including the fraction).
490    ///
491    /// # Errors
492    ///
493    /// This forwards errors from `DurationUnits::set_unit_value`. It will also
494    /// return an error is the minimum parsed unit (so far) is smaller than
495    /// days. (Since `HH:MM:SS` can only appear after units of years, months,
496    /// weeks or days.)
497    pub(crate) fn set_hms(
498        &mut self,
499        hours: u64,
500        minutes: u64,
501        seconds: u64,
502        fraction: Option<u32>,
503    ) -> Result<(), Error> {
504        if let Some(min) = self.min {
505            if min <= Unit::Hour {
506                return Err(err!(
507                    "found `HH:MM:SS` after unit {min}, \
508                             but `HH:MM:SS` can only appear after \
509                             years, months, weeks or days",
510                    min = min.singular(),
511                ));
512            }
513        }
514        self.set_unit_value(Unit::Hour, hours)?;
515        self.set_unit_value(Unit::Minute, minutes)?;
516        self.set_unit_value(Unit::Second, seconds)?;
517        if let Some(fraction) = fraction {
518            self.set_fraction(fraction)?;
519        }
520        Ok(())
521    }
522
523    /// Set the fractional value.
524    ///
525    /// This is always interpreted as a fraction of the minimal unit.
526    ///
527    /// Callers must ensure this is called after the last call to
528    /// `DurationUnits::set_unit_value`.
529    ///
530    /// # Panics
531    ///
532    /// When `fraction` is not in the range `0..=999_999_999`. Callers are
533    /// expected to uphold this invariant.
534    ///
535    /// # Errors
536    ///
537    /// This will return an error if the minimum unit is `Unit::Nanosecond`.
538    /// (Because fractional nanoseconds are not supported.) This will also
539    /// return an error if the minimum unit is bigger than `Unit::Hour`.
540    pub(crate) fn set_fraction(&mut self, fraction: u32) -> Result<(), Error> {
541        assert!(fraction <= 999_999_999);
542        if self.min == Some(Unit::Nanosecond) {
543            return Err(err!("fractional nanoseconds are not supported"));
544        }
545        if let Some(min) = self.min {
546            if min > Unit::Hour {
547                return Err(err!(
548                    "fractional {plural} are not supported",
549                    plural = min.plural()
550                ));
551            }
552        }
553        self.fraction = Some(fraction);
554        Ok(())
555    }
556
557    /// Set the sign associated with the components.
558    ///
559    /// The sign applies to the entire duration. There is no support for
560    /// having some components signed and some unsigned.
561    ///
562    /// If no sign is set, then it is assumed to be zero. Note also that
563    /// even if a sign is explicitly set *and* all unit values are zero,
564    /// then the sign will be set to zero.
565    pub(crate) fn set_sign(&mut self, sign: Sign) {
566        self.sign = sign;
567    }
568
569    /// Convert these duration components to a `Span`.
570    ///
571    /// # Errors
572    ///
573    /// If any individual unit exceeds the limits of a `Span`, or if the units
574    /// combine to exceed what can be represented by a `Span`, then this
575    /// returns an error.
576    ///
577    /// This also returns an error if no units were set.
578    #[cfg_attr(feature = "perf-inline", inline(always))]
579    pub(crate) fn to_span(&self) -> Result<Span, Error> {
580        // When every unit value is less than this, *and* there is
581        // no fractional component, then we trigger a fast path that
582        // doesn't need to bother with error handling and careful
583        // handling of the sign.
584        //
585        // Why do we use the maximum year value? Because years are
586        // the "biggest" unit, it follows that there can't be any
587        // other unit whose limit is smaller than years as a
588        // dimenionless quantity. That is, if all parsed unit values
589        // are no bigger than the maximum year, then we know all
590        // parsed unit values are necessarily within their
591        // appropriate limits.
592        const LIMIT: u64 = t::SpanYears::MAX_SELF.get_unchecked() as u64;
593
594        // If we have a fraction or a particularly large unit,
595        // bail out to the general case.
596        if self.fraction.is_some()
597            || self.values.iter().any(|&value| value > LIMIT)
598            // If no unit was set, it's an error case.
599            || self.max.is_none()
600        {
601            return self.to_span_general();
602        }
603
604        let mut span = Span::new();
605
606        let years = self.values[Unit::Year.as_usize()] as i16;
607        let months = self.values[Unit::Month.as_usize()] as i32;
608        let weeks = self.values[Unit::Week.as_usize()] as i32;
609        let days = self.values[Unit::Day.as_usize()] as i32;
610        let hours = self.values[Unit::Hour.as_usize()] as i32;
611        let mins = self.values[Unit::Minute.as_usize()] as i64;
612        let secs = self.values[Unit::Second.as_usize()] as i64;
613        let millis = self.values[Unit::Millisecond.as_usize()] as i64;
614        let micros = self.values[Unit::Microsecond.as_usize()] as i64;
615        let nanos = self.values[Unit::Nanosecond.as_usize()] as i64;
616
617        span = span.years_unchecked(years);
618        span = span.months_unchecked(months);
619        span = span.weeks_unchecked(weeks);
620        span = span.days_unchecked(days);
621        span = span.hours_unchecked(hours);
622        span = span.minutes_unchecked(mins);
623        span = span.seconds_unchecked(secs);
624        span = span.milliseconds_unchecked(millis);
625        span = span.microseconds_unchecked(micros);
626        span = span.nanoseconds_unchecked(nanos);
627
628        // The unchecked setters above don't manipulate
629        // the sign, which defaults to zero. So we need to
630        // set it even when it's positive.
631        span = span.sign_unchecked(self.get_sign().as_ranged_integer());
632
633        Ok(span)
634    }
635
636    /// The "general" implementation of `DurationUnits::to_span`.
637    ///
638    /// This handles all possible cases, including fractional units, with good
639    /// error handling. Basically, we take this path when we think an error
640    /// _could_ occur. But this function is more bloaty and does more work, so
641    /// the more it can be avoided, the better.
642    #[cold]
643    #[inline(never)]
644    fn to_span_general(&self) -> Result<Span, Error> {
645        fn error_context(unit: Unit, value: i64) -> Error {
646            err!(
647                "failed to set value {value:?} as {unit} unit on span",
648                unit = unit.singular(),
649            )
650        }
651
652        #[cfg_attr(feature = "perf-inline", inline(always))]
653        fn set_time_unit(
654            unit: Unit,
655            value: i64,
656            span: Span,
657            set: impl FnOnce(Span) -> Result<Span, Error>,
658        ) -> Result<Span, Error> {
659            #[cold]
660            #[inline(never)]
661            fn fractional_fallback(
662                err: Error,
663                unit: Unit,
664                value: i64,
665                span: Span,
666            ) -> Result<Span, Error> {
667                // Fractional calendar units aren't supported. Neither are
668                // fractional nanoseconds. So there's nothing we can do in
669                // this case.
670                if unit > Unit::Hour || unit == Unit::Nanosecond {
671                    Err(err)
672                } else {
673                    // This is annoying, but because we can write out a larger
674                    // number of hours/minutes/seconds than what we actually
675                    // support, we need to be prepared to parse an unbalanced
676                    // span if our time units are too big here. In essence,
677                    // this lets a single time unit "overflow" into smaller
678                    // units if it exceeds the limits.
679                    fractional_time_to_span(unit, value, 0, span)
680                }
681            }
682
683            set(span)
684                .or_else(|err| fractional_fallback(err, unit, value, span))
685                .with_context(|| error_context(unit, value))
686        }
687
688        let (min, _) = self.get_min_max_units()?;
689        let mut span = Span::new();
690
691        if self.values[Unit::Year.as_usize()] != 0 {
692            let value = self.get_unit_value(Unit::Year)?;
693            span = span
694                .try_years(value)
695                .with_context(|| error_context(Unit::Year, value))?;
696        }
697        if self.values[Unit::Month.as_usize()] != 0 {
698            let value = self.get_unit_value(Unit::Month)?;
699            span = span
700                .try_months(value)
701                .with_context(|| error_context(Unit::Month, value))?;
702        }
703        if self.values[Unit::Week.as_usize()] != 0 {
704            let value = self.get_unit_value(Unit::Week)?;
705            span = span
706                .try_weeks(value)
707                .with_context(|| error_context(Unit::Week, value))?;
708        }
709        if self.values[Unit::Day.as_usize()] != 0 {
710            let value = self.get_unit_value(Unit::Day)?;
711            span = span
712                .try_days(value)
713                .with_context(|| error_context(Unit::Day, value))?;
714        }
715        if self.values[Unit::Hour.as_usize()] != 0 {
716            let value = self.get_unit_value(Unit::Hour)?;
717            span = set_time_unit(Unit::Hour, value, span, |span| {
718                span.try_hours(value)
719            })?;
720        }
721        if self.values[Unit::Minute.as_usize()] != 0 {
722            let value = self.get_unit_value(Unit::Minute)?;
723            span = set_time_unit(Unit::Minute, value, span, |span| {
724                span.try_minutes(value)
725            })?;
726        }
727        if self.values[Unit::Second.as_usize()] != 0 {
728            let value = self.get_unit_value(Unit::Second)?;
729            span = set_time_unit(Unit::Second, value, span, |span| {
730                span.try_seconds(value)
731            })?;
732        }
733        if self.values[Unit::Millisecond.as_usize()] != 0 {
734            let value = self.get_unit_value(Unit::Millisecond)?;
735            span = set_time_unit(Unit::Millisecond, value, span, |span| {
736                span.try_milliseconds(value)
737            })?;
738        }
739        if self.values[Unit::Microsecond.as_usize()] != 0 {
740            let value = self.get_unit_value(Unit::Microsecond)?;
741            span = set_time_unit(Unit::Microsecond, value, span, |span| {
742                span.try_microseconds(value)
743            })?;
744        }
745        if self.values[Unit::Nanosecond.as_usize()] != 0 {
746            let value = self.get_unit_value(Unit::Nanosecond)?;
747            span = set_time_unit(Unit::Nanosecond, value, span, |span| {
748                span.try_nanoseconds(value)
749            })?;
750        }
751
752        if let Some(fraction) = self.get_fraction()? {
753            let value = self.get_unit_value(min)?;
754            span = fractional_time_to_span(min, value, fraction, span)?;
755        }
756
757        Ok(span)
758    }
759
760    /// Convert these duration components to a `SignedDuration`.
761    ///
762    /// # Errors
763    ///
764    /// If the total number of nanoseconds represented by all units combined
765    /// exceeds what can bit in a 96-bit signed integer, then an error is
766    /// returned.
767    ///
768    /// An error is also returned if any calendar units (days or greater) were
769    /// set or if no units were set.
770    #[cfg_attr(feature = "perf-inline", inline(always))]
771    pub(crate) fn to_signed_duration(&self) -> Result<SignedDuration, Error> {
772        // When every unit value is less than this, *and* there is
773        // no fractional component, then we trigger a fast path that
774        // doesn't need to bother with error handling and careful
775        // handling of the sign.
776        //
777        // Why `999`? Well, I think it's nice to use one limit for all
778        // units to make the comparisons simpler (although we could
779        // use more targeted values to admit more cases, I didn't try
780        // that). But specifically, this means we can have `999ms 999us
781        // 999ns` as a maximal subsecond value without overflowing
782        // the nanosecond component of a `SignedDuration`. This lets
783        // us "just do math" without needing to check each result and
784        // handle errors.
785        const LIMIT: u64 = 999;
786
787        if self.fraction.is_some()
788            || self.values[..Unit::Day.as_usize()]
789                .iter()
790                .any(|&value| value > LIMIT)
791            || self.max.map_or(true, |max| max > Unit::Hour)
792        {
793            return self.to_signed_duration_general();
794        }
795
796        let hours = self.values[Unit::Hour.as_usize()] as i64;
797        let mins = self.values[Unit::Minute.as_usize()] as i64;
798        let secs = self.values[Unit::Second.as_usize()] as i64;
799        let millis = self.values[Unit::Millisecond.as_usize()] as i32;
800        let micros = self.values[Unit::Microsecond.as_usize()] as i32;
801        let nanos = self.values[Unit::Nanosecond.as_usize()] as i32;
802
803        let total_secs = (hours * 3600) + (mins * 60) + secs;
804        let total_nanos = (millis * 1_000_000) + (micros * 1_000) + nanos;
805        let mut sdur =
806            SignedDuration::new_without_nano_overflow(total_secs, total_nanos);
807        if self.get_sign().is_negative() {
808            sdur = -sdur;
809        }
810
811        Ok(sdur)
812    }
813
814    /// The "general" implementation of `DurationUnits::to_signed_duration`.
815    ///
816    /// This handles all possible cases, including fractional units, with good
817    /// error handling. Basically, we take this path when we think an error
818    /// _could_ occur. But this function is more bloaty and does more work, so
819    /// the more it can be avoided, the better.
820    #[cold]
821    #[inline(never)]
822    fn to_signed_duration_general(&self) -> Result<SignedDuration, Error> {
823        let (min, max) = self.get_min_max_units()?;
824        if max > Unit::Hour {
825            return Err(err!(
826                "parsing {unit} units into a `SignedDuration` is not supported \
827                 (perhaps try parsing into a `Span` instead)",
828                unit = max.singular(),
829            ));
830        }
831
832        let mut sdur = SignedDuration::ZERO;
833        if self.values[Unit::Hour.as_usize()] != 0 {
834            let value = self.get_unit_value(Unit::Hour)?;
835            sdur = SignedDuration::try_from_hours(value)
836                .and_then(|nanos| sdur.checked_add(nanos))
837                .ok_or_else(|| {
838                    err!(
839                        "accumulated `SignedDuration` of `{sdur:?}` \
840                         overflowed when adding {value} of unit {unit}",
841                        unit = Unit::Hour.singular(),
842                    )
843                })?;
844        }
845        if self.values[Unit::Minute.as_usize()] != 0 {
846            let value = self.get_unit_value(Unit::Minute)?;
847            sdur = SignedDuration::try_from_mins(value)
848                .and_then(|nanos| sdur.checked_add(nanos))
849                .ok_or_else(|| {
850                    err!(
851                        "accumulated `SignedDuration` of `{sdur:?}` \
852                         overflowed when adding {value} of unit {unit}",
853                        unit = Unit::Minute.singular(),
854                    )
855                })?;
856        }
857        if self.values[Unit::Second.as_usize()] != 0 {
858            let value = self.get_unit_value(Unit::Second)?;
859            sdur = SignedDuration::from_secs(value)
860                .checked_add(sdur)
861                .ok_or_else(|| {
862                    err!(
863                        "accumulated `SignedDuration` of `{sdur:?}` \
864                         overflowed when adding {value} of unit {unit}",
865                        unit = Unit::Second.singular(),
866                    )
867                })?;
868        }
869        if self.values[Unit::Millisecond.as_usize()] != 0 {
870            let value = self.get_unit_value(Unit::Millisecond)?;
871            sdur = SignedDuration::from_millis(value)
872                .checked_add(sdur)
873                .ok_or_else(|| {
874                    err!(
875                        "accumulated `SignedDuration` of `{sdur:?}` \
876                         overflowed when adding {value} of unit {unit}",
877                        unit = Unit::Millisecond.singular(),
878                    )
879                })?;
880        }
881        if self.values[Unit::Microsecond.as_usize()] != 0 {
882            let value = self.get_unit_value(Unit::Microsecond)?;
883            sdur = SignedDuration::from_micros(value)
884                .checked_add(sdur)
885                .ok_or_else(|| {
886                    err!(
887                        "accumulated `SignedDuration` of `{sdur:?}` \
888                         overflowed when adding {value} of unit {unit}",
889                        unit = Unit::Microsecond.singular(),
890                    )
891                })?;
892        }
893        if self.values[Unit::Nanosecond.as_usize()] != 0 {
894            let value = self.get_unit_value(Unit::Nanosecond)?;
895            sdur = SignedDuration::from_nanos(value)
896                .checked_add(sdur)
897                .ok_or_else(|| {
898                    err!(
899                        "accumulated `SignedDuration` of `{sdur:?}` \
900                         overflowed when adding {value} of unit {unit}",
901                        unit = Unit::Nanosecond.singular(),
902                    )
903                })?;
904        }
905
906        if let Some(fraction) = self.get_fraction()? {
907            sdur = sdur
908                .checked_add(fractional_duration(min, fraction)?)
909                .ok_or_else(|| {
910                    err!(
911                        "accumulated `SignedDuration` of `{sdur:?}` \
912                         overflowed when adding 0.{fraction} of unit {unit}",
913                        unit = min.singular(),
914                    )
915                })?;
916        }
917
918        Ok(sdur)
919    }
920
921    /// Convert these duration components to a `core::time::Duration`.
922    ///
923    /// # Errors
924    ///
925    /// If the total number of nanoseconds represented by all units combined
926    /// exceeds what can bit in a 96-bit signed integer, then an error is
927    /// returned.
928    ///
929    /// An error is also returned if any calendar units (days or greater) were
930    /// set or if no units were set.
931    #[cfg_attr(feature = "perf-inline", inline(always))]
932    pub(crate) fn to_unsigned_duration(
933        &self,
934    ) -> Result<core::time::Duration, Error> {
935        // When every unit value is less than this, *and* there is
936        // no fractional component, then we trigger a fast path that
937        // doesn't need to bother with error handling and careful
938        // handling of the sign.
939        //
940        // Why `999`? Well, I think it's nice to use one limit for all
941        // units to make the comparisons simpler (although we could
942        // use more targeted values to admit more cases, I didn't try
943        // that). But specifically, this means we can have `999ms 999us
944        // 999ns` as a maximal subsecond value without overflowing
945        // the nanosecond component of a `core::time::Duration`. This lets
946        // us "just do math" without needing to check each result and
947        // handle errors.
948        const LIMIT: u64 = 999;
949
950        if self.fraction.is_some()
951            || self.values[..Unit::Day.as_usize()]
952                .iter()
953                .any(|&value| value > LIMIT)
954            || self.max.map_or(true, |max| max > Unit::Hour)
955            || self.sign.is_negative()
956        {
957            return self.to_unsigned_duration_general();
958        }
959
960        let hours = self.values[Unit::Hour.as_usize()];
961        let mins = self.values[Unit::Minute.as_usize()];
962        let secs = self.values[Unit::Second.as_usize()];
963        let millis = self.values[Unit::Millisecond.as_usize()] as u32;
964        let micros = self.values[Unit::Microsecond.as_usize()] as u32;
965        let nanos = self.values[Unit::Nanosecond.as_usize()] as u32;
966
967        let total_secs = (hours * 3600) + (mins * 60) + secs;
968        let total_nanos = (millis * 1_000_000) + (micros * 1_000) + nanos;
969        let sdur = core::time::Duration::new(total_secs, total_nanos);
970
971        Ok(sdur)
972    }
973
974    /// The "general" implementation of `DurationUnits::to_unsigned_duration`.
975    ///
976    /// This handles all possible cases, including fractional units, with good
977    /// error handling. Basically, we take this path when we think an error
978    /// _could_ occur. But this function is more bloaty and does more work, so
979    /// the more it can be avoided, the better.
980    #[cold]
981    #[inline(never)]
982    fn to_unsigned_duration_general(
983        &self,
984    ) -> Result<core::time::Duration, Error> {
985        #[inline]
986        const fn try_from_hours(hours: u64) -> Option<core::time::Duration> {
987            // OK because (SECS_PER_MINUTE*MINS_PER_HOUR)!={-1,0}.
988            const MAX_HOUR: u64 = u64::MAX / (60 * 60);
989            if hours > MAX_HOUR {
990                return None;
991            }
992            Some(core::time::Duration::from_secs(hours * 60 * 60))
993        }
994
995        #[inline]
996        const fn try_from_mins(mins: u64) -> Option<core::time::Duration> {
997            // OK because SECS_PER_MINUTE!={-1,0}.
998            const MAX_MINUTE: u64 = u64::MAX / 60;
999            if mins > MAX_MINUTE {
1000                return None;
1001            }
1002            Some(core::time::Duration::from_secs(mins * 60))
1003        }
1004
1005        if self.sign.is_negative() {
1006            return Err(err!(
1007                "cannot parse negative duration into unsigned \
1008                 `std::time::Duration`",
1009            ));
1010        }
1011
1012        let (min, max) = self.get_min_max_units()?;
1013        if max > Unit::Hour {
1014            return Err(err!(
1015                "parsing {unit} units into a `std::time::Duration` \
1016                 is not supported (perhaps try parsing into a `Span` instead)",
1017                unit = max.singular(),
1018            ));
1019        }
1020
1021        let mut sdur = core::time::Duration::ZERO;
1022        if self.values[Unit::Hour.as_usize()] != 0 {
1023            let value = self.values[Unit::Hour.as_usize()];
1024            sdur = try_from_hours(value)
1025                .and_then(|nanos| sdur.checked_add(nanos))
1026                .ok_or_else(|| {
1027                    err!(
1028                        "accumulated `std::time::Duration` of `{sdur:?}` \
1029                         overflowed when adding {value} of unit {unit}",
1030                        unit = Unit::Hour.singular(),
1031                    )
1032                })?;
1033        }
1034        if self.values[Unit::Minute.as_usize()] != 0 {
1035            let value = self.values[Unit::Minute.as_usize()];
1036            sdur = try_from_mins(value)
1037                .and_then(|nanos| sdur.checked_add(nanos))
1038                .ok_or_else(|| {
1039                    err!(
1040                        "accumulated `std::time::Duration` of `{sdur:?}` \
1041                         overflowed when adding {value} of unit {unit}",
1042                        unit = Unit::Minute.singular(),
1043                    )
1044                })?;
1045        }
1046        if self.values[Unit::Second.as_usize()] != 0 {
1047            let value = self.values[Unit::Second.as_usize()];
1048            sdur = core::time::Duration::from_secs(value)
1049                .checked_add(sdur)
1050                .ok_or_else(|| {
1051                    err!(
1052                        "accumulated `std::time::Duration` of `{sdur:?}` \
1053                         overflowed when adding {value} of unit {unit}",
1054                        unit = Unit::Second.singular(),
1055                    )
1056                })?;
1057        }
1058        if self.values[Unit::Millisecond.as_usize()] != 0 {
1059            let value = self.values[Unit::Millisecond.as_usize()];
1060            sdur = core::time::Duration::from_millis(value)
1061                .checked_add(sdur)
1062                .ok_or_else(|| {
1063                    err!(
1064                        "accumulated `std::time::Duration` of `{sdur:?}` \
1065                         overflowed when adding {value} of unit {unit}",
1066                        unit = Unit::Millisecond.singular(),
1067                    )
1068                })?;
1069        }
1070        if self.values[Unit::Microsecond.as_usize()] != 0 {
1071            let value = self.values[Unit::Microsecond.as_usize()];
1072            sdur = core::time::Duration::from_micros(value)
1073                .checked_add(sdur)
1074                .ok_or_else(|| {
1075                    err!(
1076                        "accumulated `std::time::Duration` of `{sdur:?}` \
1077                         overflowed when adding {value} of unit {unit}",
1078                        unit = Unit::Microsecond.singular(),
1079                    )
1080                })?;
1081        }
1082        if self.values[Unit::Nanosecond.as_usize()] != 0 {
1083            let value = self.values[Unit::Nanosecond.as_usize()];
1084            sdur = core::time::Duration::from_nanos(value)
1085                .checked_add(sdur)
1086                .ok_or_else(|| {
1087                err!(
1088                    "accumulated `std::time::Duration` of `{sdur:?}` \
1089                         overflowed when adding {value} of unit {unit}",
1090                    unit = Unit::Nanosecond.singular(),
1091                )
1092            })?;
1093        }
1094
1095        if let Some(fraction) = self.get_fraction()? {
1096            sdur = sdur
1097                .checked_add(
1098                    fractional_duration(min, fraction)?.unsigned_abs(),
1099                )
1100                .ok_or_else(|| {
1101                    err!(
1102                        "accumulated `std::time::Duration` of `{sdur:?}` \
1103                         overflowed when adding 0.{fraction} of unit {unit}",
1104                        unit = min.singular(),
1105                    )
1106                })?;
1107        }
1108
1109        Ok(sdur)
1110    }
1111
1112    /// Returns the minimum unit set.
1113    ///
1114    /// This only returns `None` when no units have been set.
1115    pub(crate) fn get_min(&self) -> Option<Unit> {
1116        self.min
1117    }
1118
1119    /// Returns the minimum and maximum units set.
1120    ///
1121    /// This returns an error if no units were set. (Since this means there
1122    /// were no parsed duration components.)
1123    fn get_min_max_units(&self) -> Result<(Unit, Unit), Error> {
1124        let (Some(min), Some(max)) = (self.min, self.max) else {
1125            return Err(err!("no parsed duration components"));
1126        };
1127        Ok((min, max))
1128    }
1129
1130    /// Returns the corresponding unit value using the set signed-ness.
1131    #[cfg_attr(feature = "perf-inline", inline(always))]
1132    fn get_unit_value(&self, unit: Unit) -> Result<i64, Error> {
1133        const I64_MIN_ABS: u64 = i64::MIN.unsigned_abs();
1134
1135        #[cold]
1136        #[inline(never)]
1137        fn general(unit: Unit, value: u64, sign: Sign) -> Result<i64, Error> {
1138            // As a weird special case, when we need to represent i64::MIN,
1139            // we'll have a unit value of `|i64::MIN|` as a `u64`. We can't
1140            // convert that to a positive `i64` first, since it will overflow.
1141            if sign.is_negative() && value == I64_MIN_ABS {
1142                return Ok(i64::MIN);
1143            }
1144            // Otherwise, if a conversion to `i64` fails, then that failure
1145            // is correct.
1146            let mut value = i64::try_from(value).map_err(|_| {
1147                err!(
1148                    "`{sign}{value}` {unit} is too big (or small) \
1149                     to fit into a signed 64-bit integer",
1150                    unit = unit.plural()
1151                )
1152            })?;
1153            if sign.is_negative() {
1154                value = value.checked_neg().ok_or_else(|| {
1155                    err!(
1156                        "`{sign}{value}` {unit} is too big (or small) \
1157                         to fit into a signed 64-bit integer",
1158                        unit = unit.plural()
1159                    )
1160                })?;
1161            }
1162            Ok(value)
1163        }
1164
1165        let sign = self.get_sign();
1166        let value = self.values[unit.as_usize()];
1167        if value >= I64_MIN_ABS {
1168            return general(unit, value, sign);
1169        }
1170        let mut value = value as i64;
1171        if sign.is_negative() {
1172            value = -value;
1173        }
1174        Ok(value)
1175    }
1176
1177    /// Returns the fraction using the set signed-ness.
1178    ///
1179    /// This returns `None` when no fraction has been set.
1180    fn get_fraction(&self) -> Result<Option<i32>, Error> {
1181        let Some(fraction) = self.fraction else {
1182            return Ok(None);
1183        };
1184        // OK because `set_fraction` guarantees `0..=999_999_999`.
1185        let mut fraction = fraction as i32;
1186        if self.get_sign().is_negative() {
1187            // OK because `set_fraction` guarantees `0..=999_999_999`.
1188            fraction = -fraction;
1189        }
1190        Ok(Some(fraction))
1191    }
1192
1193    /// Returns the sign that should be applied to each individual unit.
1194    fn get_sign(&self) -> Sign {
1195        if self.any_non_zero_units {
1196            self.sign
1197        } else {
1198            Sign::Zero
1199        }
1200    }
1201}
1202
1203/// Parses an optional fractional number from the start of `input`.
1204///
1205/// If `input` does not begin with a `.` (or a `,`), then this returns `None`
1206/// and no input is consumed. Otherwise, up to 9 ASCII digits are parsed after
1207/// the decimal separator.
1208///
1209/// While this is most typically used to parse the fractional component of
1210/// second units, it is also used to parse the fractional component of hours or
1211/// minutes in ISO 8601 duration parsing, and milliseconds and microseconds in
1212/// the "friendly" duration format. The return type in that case is obviously a
1213/// misnomer, but the range of possible values is still correct. (That is, the
1214/// fractional component of an hour is still limited to 9 decimal places per
1215/// the Temporal spec.)
1216///
1217/// The number returned is guaranteed to be in the range `0..=999_999_999`.
1218#[cfg_attr(feature = "perf-inline", inline(always))]
1219pub(crate) fn parse_temporal_fraction<'i>(
1220    input: &'i [u8],
1221) -> Result<Parsed<'i, Option<u32>>, Error> {
1222    // TimeFraction :::
1223    //   TemporalDecimalFraction
1224    //
1225    // TemporalDecimalFraction :::
1226    //   TemporalDecimalSeparator DecimalDigit
1227    //   TemporalDecimalSeparator DecimalDigit DecimalDigit
1228    //   TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit
1229    //   TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit
1230    //                            DecimalDigit
1231    //   TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit
1232    //                            DecimalDigit DecimalDigit
1233    //   TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit
1234    //                            DecimalDigit DecimalDigit DecimalDigit
1235    //   TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit
1236    //                            DecimalDigit DecimalDigit DecimalDigit
1237    //                            DecimalDigit
1238    //   TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit
1239    //                            DecimalDigit DecimalDigit DecimalDigit
1240    //                            DecimalDigit DecimalDigit
1241    //   TemporalDecimalSeparator DecimalDigit DecimalDigit DecimalDigit
1242    //                            DecimalDigit DecimalDigit DecimalDigit
1243    //                            DecimalDigit DecimalDigit DecimalDigit
1244    //
1245    // TemporalDecimalSeparator ::: one of
1246    //   . ,
1247    //
1248    // DecimalDigit :: one of
1249    //   0 1 2 3 4 5 6 7 8 9
1250
1251    #[inline(never)]
1252    fn imp<'i>(mut input: &'i [u8]) -> Result<Parsed<'i, Option<u32>>, Error> {
1253        let mkdigits = parse::slicer(input);
1254        while mkdigits(input).len() <= 8
1255            && input.first().map_or(false, u8::is_ascii_digit)
1256        {
1257            input = &input[1..];
1258        }
1259        let digits = mkdigits(input);
1260        if digits.is_empty() {
1261            return Err(err!(
1262                "found decimal after seconds component, \
1263                 but did not find any decimal digits after decimal",
1264            ));
1265        }
1266        // I believe this error can never happen, since we know we have no more
1267        // than 9 ASCII digits. Any sequence of 9 ASCII digits can be parsed
1268        // into an `i64`.
1269        let nanoseconds = parse::fraction(digits).map_err(|err| {
1270            err!(
1271                "failed to parse {digits:?} as fractional component \
1272                 (up to 9 digits, nanosecond precision): {err}",
1273                digits = escape::Bytes(digits),
1274            )
1275        })?;
1276        // OK because parsing is forcefully limited to 9 digits,
1277        // which can never be greater than `999_999_99`,
1278        // which is less than `u32::MAX`.
1279        let nanoseconds = nanoseconds as u32;
1280        Ok(Parsed { value: Some(nanoseconds), input })
1281    }
1282
1283    if input.is_empty() || (input[0] != b'.' && input[0] != b',') {
1284        return Ok(Parsed { value: None, input });
1285    }
1286    imp(&input[1..])
1287}
1288
1289/// This routine returns a span based on the given unit and value with
1290/// fractional time applied to it.
1291///
1292/// For example, given a span like `P1dT1.5h`, the `unit` would be
1293/// `Unit::Hour`, the `value` would be `1` and the `fraction` would be
1294/// `500_000_000`. The span given would just be `1d`. The span returned would
1295/// be `P1dT1h30m`.
1296///
1297/// Note that `fraction` can be a fractional hour, minute, second, millisecond
1298/// or microsecond (even though its type suggests its only a fraction of a
1299/// second). When milliseconds or microseconds, the given fraction has any
1300/// sub-nanosecond precision truncated.
1301///
1302/// # Errors
1303///
1304/// This can error if the resulting units would be too large for the limits on
1305/// a `span`. This also errors if `unit` is not `Hour`, `Minute`, `Second`,
1306/// `Millisecond` or `Microsecond`.
1307#[inline(never)]
1308fn fractional_time_to_span(
1309    unit: Unit,
1310    value: i64,
1311    fraction: i32,
1312    mut span: Span,
1313) -> Result<Span, Error> {
1314    const MAX_HOURS: i64 = t::SpanHours::MAX_SELF.get_unchecked() as i64;
1315    const MAX_MINS: i64 = t::SpanMinutes::MAX_SELF.get_unchecked() as i64;
1316    const MAX_SECS: i64 = t::SpanSeconds::MAX_SELF.get_unchecked() as i64;
1317    const MAX_MILLIS: i128 =
1318        t::SpanMilliseconds::MAX_SELF.get_unchecked() as i128;
1319    const MAX_MICROS: i128 =
1320        t::SpanMicroseconds::MAX_SELF.get_unchecked() as i128;
1321    const MIN_HOURS: i64 = t::SpanHours::MIN_SELF.get_unchecked() as i64;
1322    const MIN_MINS: i64 = t::SpanMinutes::MIN_SELF.get_unchecked() as i64;
1323    const MIN_SECS: i64 = t::SpanSeconds::MIN_SELF.get_unchecked() as i64;
1324    const MIN_MILLIS: i128 =
1325        t::SpanMilliseconds::MIN_SELF.get_unchecked() as i128;
1326    const MIN_MICROS: i128 =
1327        t::SpanMicroseconds::MIN_SELF.get_unchecked() as i128;
1328
1329    // We switch everything over to nanoseconds and then divy that up as
1330    // appropriate. In general, we always create a balanced span, but there
1331    // are some cases where we can't. For example, if one serializes a span
1332    // with both the maximum number of seconds and the maximum number of
1333    // milliseconds, then this just can't be balanced due to the limits on
1334    // each of the units. When this kind of span is serialized to a string,
1335    // it results in a second value that is actually bigger than the maximum
1336    // allowed number of seconds in a span. So here, we have to reverse that
1337    // operation and spread the seconds over smaller units. This in turn
1338    // creates an unbalanced span. Annoying.
1339    //
1340    // The above is why we have `if unit_value > MAX { <do adjustments> }` in
1341    // the balancing code below. Basically, if we overshoot our limit, we back
1342    // out anything over the limit and carry it over to the lesser units. If
1343    // our value is truly too big, then the final call to set nanoseconds will
1344    // fail.
1345    let mut sdur = fractional_time_to_duration(unit, value, fraction)?;
1346
1347    if unit >= Unit::Hour && !sdur.is_zero() {
1348        let (mut hours, rem) = sdur.as_hours_with_remainder();
1349        sdur = rem;
1350        if hours > MAX_HOURS {
1351            sdur += SignedDuration::from_hours(hours - MAX_HOURS);
1352            hours = MAX_HOURS;
1353        } else if hours < MIN_HOURS {
1354            sdur += SignedDuration::from_hours(hours - MIN_HOURS);
1355            hours = MIN_HOURS;
1356        }
1357        // OK because we just checked that our units are in range.
1358        span = span.hours(hours);
1359    }
1360    if unit >= Unit::Minute && !sdur.is_zero() {
1361        let (mut mins, rem) = sdur.as_mins_with_remainder();
1362        sdur = rem;
1363        if mins > MAX_MINS {
1364            sdur += SignedDuration::from_mins(mins - MAX_MINS);
1365            mins = MAX_MINS;
1366        } else if mins < MIN_MINS {
1367            sdur += SignedDuration::from_mins(mins - MIN_MINS);
1368            mins = MIN_MINS;
1369        }
1370        // OK because we just checked that our units are in range.
1371        span = span.minutes(mins);
1372    }
1373    if unit >= Unit::Second && !sdur.is_zero() {
1374        let (mut secs, rem) = sdur.as_secs_with_remainder();
1375        sdur = rem;
1376        if secs > MAX_SECS {
1377            sdur += SignedDuration::from_secs(secs - MAX_SECS);
1378            secs = MAX_SECS;
1379        } else if secs < MIN_SECS {
1380            sdur += SignedDuration::from_secs(secs - MIN_SECS);
1381            secs = MIN_SECS;
1382        }
1383        // OK because we just checked that our units are in range.
1384        span = span.seconds(secs);
1385    }
1386    if unit >= Unit::Millisecond && !sdur.is_zero() {
1387        let (mut millis, rem) = sdur.as_millis_with_remainder();
1388        sdur = rem;
1389        if millis > MAX_MILLIS {
1390            sdur += SignedDuration::from_millis_i128(millis - MAX_MILLIS);
1391            millis = MAX_MILLIS;
1392        } else if millis < MIN_MILLIS {
1393            sdur += SignedDuration::from_millis_i128(millis - MIN_MILLIS);
1394            millis = MIN_MILLIS;
1395        }
1396        // OK because we just checked that our units are in range.
1397        span = span.milliseconds(i64::try_from(millis).unwrap());
1398    }
1399    if unit >= Unit::Microsecond && !sdur.is_zero() {
1400        let (mut micros, rem) = sdur.as_micros_with_remainder();
1401        sdur = rem;
1402        if micros > MAX_MICROS {
1403            sdur += SignedDuration::from_micros_i128(micros - MAX_MICROS);
1404            micros = MAX_MICROS;
1405        } else if micros < MIN_MICROS {
1406            sdur += SignedDuration::from_micros_i128(micros - MIN_MICROS);
1407            micros = MIN_MICROS;
1408        }
1409        // OK because we just checked that our units are in range.
1410        span = span.microseconds(i64::try_from(micros).unwrap());
1411    }
1412    if !sdur.is_zero() {
1413        let nanos = sdur.as_nanos();
1414        let nanos64 = i64::try_from(nanos).map_err(|_| {
1415            err!(
1416                "failed to set nanosecond value {nanos} (it overflows \
1417                 `i64`) on span determined from {value}.{fraction}",
1418            )
1419        })?;
1420        span = span.try_nanoseconds(nanos64).with_context(|| {
1421            err!(
1422                "failed to set nanosecond value {nanos64} on span \
1423                 determined from {value}.{fraction}",
1424            )
1425        })?;
1426    }
1427
1428    Ok(span)
1429}
1430
1431/// Like `fractional_time_to_span`, but just converts the fraction of the given
1432/// unit to a signed duration.
1433///
1434/// Since a signed duration doesn't keep track of individual units, there is
1435/// no loss of fidelity between it and ISO 8601 durations like there is for
1436/// `Span`.
1437///
1438/// Note that `fraction` can be a fractional hour, minute, second, millisecond
1439/// or microsecond (even though its type suggests it's only a fraction of a
1440/// second). When milliseconds or microseconds, the given fraction has any
1441/// sub-nanosecond precision truncated.
1442///
1443/// # Errors
1444///
1445/// This returns an error if `unit` is not `Hour`, `Minute`, `Second`,
1446/// `Millisecond` or `Microsecond`.
1447#[inline(never)]
1448fn fractional_time_to_duration(
1449    unit: Unit,
1450    value: i64,
1451    fraction: i32,
1452) -> Result<SignedDuration, Error> {
1453    let sdur = duration_unit_value(unit, value)?;
1454    let fraction_dur = fractional_duration(unit, fraction)?;
1455    sdur.checked_add(fraction_dur).ok_or_else(|| {
1456        err!(
1457            "accumulated `SignedDuration` of `{sdur:?}` overflowed \
1458             when adding `{fraction_dur:?}` (from fractional {unit} units)",
1459            unit = unit.singular(),
1460        )
1461    })
1462}
1463
1464/// Converts the fraction of the given unit to a signed duration.
1465///
1466/// Since a signed duration doesn't keep track of individual units, there is
1467/// no loss of fidelity between it and ISO 8601 durations like there is for
1468/// `Span`. Thus, we can do something far less complicated.
1469///
1470/// # Panics
1471///
1472/// When `fraction` isn't in the range `-999_999_999..=999_999_999`.
1473///
1474/// # Errors
1475///
1476/// This returns an error if `unit` is not `Hour`, `Minute`, `Second`,
1477/// `Millisecond` or `Microsecond`.
1478#[inline(never)]
1479fn fractional_duration(
1480    unit: Unit,
1481    fraction: i32,
1482) -> Result<SignedDuration, Error> {
1483    let fraction = i64::from(fraction);
1484    let nanos = match unit {
1485        Unit::Hour => fraction * t::SECONDS_PER_HOUR.value(),
1486        Unit::Minute => fraction * t::SECONDS_PER_MINUTE.value(),
1487        Unit::Second => fraction,
1488        Unit::Millisecond => fraction / t::NANOS_PER_MICRO.value(),
1489        Unit::Microsecond => fraction / t::NANOS_PER_MILLI.value(),
1490        unit => {
1491            return Err(err!(
1492                "fractional {unit} units are not allowed",
1493                unit = unit.singular(),
1494            ))
1495        }
1496    };
1497    Ok(SignedDuration::from_nanos(nanos))
1498}
1499
1500/// Returns the given parsed value, interpreted as the given unit, as a
1501/// `SignedDuration`.
1502///
1503/// If the given unit is not supported for signed durations (i.e., calendar
1504/// units), or if converting the given value to a `SignedDuration` for the
1505/// given units overflows, then an error is returned.
1506#[cfg_attr(feature = "perf-inline", inline(always))]
1507fn duration_unit_value(
1508    unit: Unit,
1509    value: i64,
1510) -> Result<SignedDuration, Error> {
1511    // Convert our parsed unit into a number of nanoseconds.
1512    //
1513    // Note also that overflow isn't possible here for units less than minutes,
1514    // since a `SignedDuration` supports all `i64` second values.
1515    let sdur = match unit {
1516        Unit::Hour => {
1517            let seconds = value
1518                .checked_mul(t::SECONDS_PER_HOUR.value())
1519                .ok_or_else(|| {
1520                    err!("converting {value} hours to seconds overflows i64")
1521                })?;
1522            SignedDuration::from_secs(seconds)
1523        }
1524        Unit::Minute => {
1525            let seconds = value
1526                .checked_mul(t::SECONDS_PER_MINUTE.value())
1527                .ok_or_else(|| {
1528                    err!("converting {value} minutes to seconds overflows i64")
1529                })?;
1530            SignedDuration::from_secs(seconds)
1531        }
1532        Unit::Second => SignedDuration::from_secs(value),
1533        Unit::Millisecond => SignedDuration::from_millis(value),
1534        Unit::Microsecond => SignedDuration::from_micros(value),
1535        Unit::Nanosecond => SignedDuration::from_nanos(value),
1536        unsupported => {
1537            return Err(err!(
1538                "parsing {unit} units into a `SignedDuration` is not supported \
1539                 (perhaps try parsing into a `Span` instead)",
1540                unit = unsupported.singular(),
1541            ));
1542        }
1543    };
1544    Ok(sdur)
1545}
1546
1547#[cfg(test)]
1548mod tests {
1549    use alloc::string::ToString;
1550
1551    use super::*;
1552
1553    #[test]
1554    fn decimal() {
1555        let x = DecimalFormatter::new().format_signed(i64::MIN);
1556        assert_eq!(x.as_str(), "-9223372036854775808");
1557
1558        let x = DecimalFormatter::new().format_signed(i64::MIN + 1);
1559        assert_eq!(x.as_str(), "-9223372036854775807");
1560
1561        let x = DecimalFormatter::new().format_signed(i64::MAX);
1562        assert_eq!(x.as_str(), "9223372036854775807");
1563
1564        let x =
1565            DecimalFormatter::new().force_sign(true).format_signed(i64::MAX);
1566        assert_eq!(x.as_str(), "+9223372036854775807");
1567
1568        let x = DecimalFormatter::new().format_signed(0);
1569        assert_eq!(x.as_str(), "0");
1570
1571        let x = DecimalFormatter::new().force_sign(true).format_signed(0);
1572        assert_eq!(x.as_str(), "+0");
1573
1574        let x = DecimalFormatter::new().force_sign(false).format_signed(0);
1575        assert_eq!(x.as_str(), "-0");
1576
1577        let x = DecimalFormatter::new().padding(4).format_signed(0);
1578        assert_eq!(x.as_str(), "0000");
1579
1580        let x = DecimalFormatter::new().padding(4).format_signed(789);
1581        assert_eq!(x.as_str(), "0789");
1582
1583        let x = DecimalFormatter::new().padding(4).format_signed(-789);
1584        assert_eq!(x.as_str(), "-0789");
1585
1586        let x = DecimalFormatter::new()
1587            .force_sign(true)
1588            .padding(4)
1589            .format_signed(789);
1590        assert_eq!(x.as_str(), "+0789");
1591    }
1592
1593    #[test]
1594    fn fractional_auto() {
1595        let f = |n| FractionalFormatter::new().format(n).as_str().to_string();
1596
1597        assert_eq!(f(0), "");
1598        assert_eq!(f(123_000_000), "123");
1599        assert_eq!(f(123_456_000), "123456");
1600        assert_eq!(f(123_456_789), "123456789");
1601        assert_eq!(f(456_789), "000456789");
1602        assert_eq!(f(789), "000000789");
1603    }
1604
1605    #[test]
1606    fn fractional_precision() {
1607        let f = |precision, n| {
1608            FractionalFormatter::new()
1609                .precision(Some(precision))
1610                .format(n)
1611                .as_str()
1612                .to_string()
1613        };
1614
1615        assert_eq!(f(0, 0), "");
1616        assert_eq!(f(1, 0), "0");
1617        assert_eq!(f(9, 0), "000000000");
1618
1619        assert_eq!(f(3, 123_000_000), "123");
1620        assert_eq!(f(6, 123_000_000), "123000");
1621        assert_eq!(f(9, 123_000_000), "123000000");
1622
1623        assert_eq!(f(3, 123_456_000), "123");
1624        assert_eq!(f(6, 123_456_000), "123456");
1625        assert_eq!(f(9, 123_456_000), "123456000");
1626
1627        assert_eq!(f(3, 123_456_789), "123");
1628        assert_eq!(f(6, 123_456_789), "123456");
1629        assert_eq!(f(9, 123_456_789), "123456789");
1630
1631        // We use truncation, no rounding.
1632        assert_eq!(f(2, 889_000_000), "88");
1633        assert_eq!(f(2, 999_000_000), "99");
1634    }
1635}