Coverage Report

Created: 2026-04-01 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jiff-0.2.16/src/fmt/util.rs
Line
Count
Source
1
use 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)]
20
pub(crate) struct DecimalFormatter {
21
    force_sign: Option<bool>,
22
    minimum_digits: u8,
23
    padding_byte: u8,
24
}
25
26
impl DecimalFormatter {
27
    /// Creates a new decimal formatter using the default configuration.
28
0
    pub(crate) const fn new() -> DecimalFormatter {
29
0
        DecimalFormatter {
30
0
            force_sign: None,
31
0
            minimum_digits: 0,
32
0
            padding_byte: b'0',
33
0
        }
34
0
    }
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
0
    pub(crate) const fn format_signed(&self, value: i64) -> Decimal {
40
0
        Decimal::signed(self, value)
41
0
    }
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
0
    pub(crate) const fn format_unsigned(&self, value: u64) -> Decimal {
47
0
        Decimal::unsigned(self, value)
48
0
    }
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
0
    pub(crate) const fn padding(self, mut digits: u8) -> DecimalFormatter {
73
0
        if digits > Decimal::MAX_I64_DIGITS {
74
0
            digits = Decimal::MAX_I64_DIGITS;
75
0
        }
76
0
        DecimalFormatter { minimum_digits: digits, ..self }
77
0
    }
78
79
    /// The padding byte to use when `padding` is set.
80
    ///
81
    /// The default is `0`.
82
0
    pub(crate) const fn padding_byte(self, byte: u8) -> DecimalFormatter {
83
0
        DecimalFormatter { padding_byte: byte, ..self }
84
0
    }
85
86
    /// Returns the minimum number of digits for a signed value.
87
0
    const fn get_signed_minimum_digits(&self) -> u8 {
88
0
        if self.minimum_digits <= Decimal::MAX_I64_DIGITS {
89
0
            self.minimum_digits
90
        } else {
91
0
            Decimal::MAX_I64_DIGITS
92
        }
93
0
    }
94
95
    /// Returns the minimum number of digits for an unsigned value.
96
0
    const fn get_unsigned_minimum_digits(&self) -> u8 {
97
0
        if self.minimum_digits <= Decimal::MAX_U64_DIGITS {
98
0
            self.minimum_digits
99
        } else {
100
0
            Decimal::MAX_U64_DIGITS
101
        }
102
0
    }
103
}
104
105
impl Default for DecimalFormatter {
106
0
    fn default() -> DecimalFormatter {
107
0
        DecimalFormatter::new()
108
0
    }
109
}
110
111
/// A formatted decimal number that can be converted to a sequence of bytes.
112
#[derive(Debug)]
113
pub(crate) struct Decimal {
114
    buf: [u8; Self::MAX_LEN as usize],
115
    start: u8,
116
    end: u8,
117
}
118
119
impl 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
0
    const fn unsigned(
132
0
        formatter: &DecimalFormatter,
133
0
        mut value: u64,
134
0
    ) -> Decimal {
135
0
        let mut decimal = Decimal {
136
0
            buf: [0; Self::MAX_LEN as usize],
137
0
            start: Self::MAX_LEN,
138
0
            end: Self::MAX_LEN,
139
0
        };
140
        loop {
141
0
            decimal.start -= 1;
142
143
0
            let digit = (value % 10) as u8;
144
0
            value /= 10;
145
0
            decimal.buf[decimal.start as usize] = b'0' + digit;
146
0
            if value == 0 {
147
0
                break;
148
0
            }
149
        }
150
151
0
        while decimal.len() < formatter.get_unsigned_minimum_digits() {
152
0
            decimal.start -= 1;
153
0
            decimal.buf[decimal.start as usize] = formatter.padding_byte;
154
0
        }
155
0
        decimal
156
0
    }
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
0
    const fn signed(formatter: &DecimalFormatter, mut value: i64) -> Decimal {
162
        // Specialize the common case to generate tighter codegen.
163
0
        if value >= 0 && formatter.force_sign.is_none() {
164
0
            let mut decimal = Decimal {
165
0
                buf: [0; Self::MAX_LEN as usize],
166
0
                start: Self::MAX_LEN,
167
0
                end: Self::MAX_LEN,
168
0
            };
169
            loop {
170
0
                decimal.start -= 1;
171
172
0
                let digit = (value % 10) as u8;
173
0
                value /= 10;
174
0
                decimal.buf[decimal.start as usize] = b'0' + digit;
175
0
                if value == 0 {
176
0
                    break;
177
0
                }
178
            }
179
180
0
            while decimal.len() < formatter.get_signed_minimum_digits() {
181
0
                decimal.start -= 1;
182
0
                decimal.buf[decimal.start as usize] = formatter.padding_byte;
183
0
            }
184
0
            return decimal;
185
0
        }
186
0
        Decimal::signed_cold(formatter, value)
187
0
    }
188
189
    #[cold]
190
    #[inline(never)]
191
0
    const fn signed_cold(formatter: &DecimalFormatter, value: i64) -> Decimal {
192
0
        let sign = value.signum();
193
0
        let Some(mut value) = value.checked_abs() else {
194
0
            let buf = [
195
0
                b'-', b'9', b'2', b'2', b'3', b'3', b'7', b'2', b'0', b'3',
196
0
                b'6', b'8', b'5', b'4', b'7', b'7', b'5', b'8', b'0', b'8',
197
0
            ];
198
0
            return Decimal { buf, start: 0, end: Self::MAX_LEN };
199
        };
200
0
        let mut decimal = Decimal {
201
0
            buf: [0; Self::MAX_LEN as usize],
202
0
            start: Self::MAX_LEN,
203
0
            end: Self::MAX_LEN,
204
0
        };
205
        loop {
206
0
            decimal.start -= 1;
207
208
0
            let digit = (value % 10) as u8;
209
0
            value /= 10;
210
0
            decimal.buf[decimal.start as usize] = b'0' + digit;
211
0
            if value == 0 {
212
0
                break;
213
0
            }
214
        }
215
0
        while decimal.len() < formatter.get_signed_minimum_digits() {
216
0
            decimal.start -= 1;
217
0
            decimal.buf[decimal.start as usize] = formatter.padding_byte;
218
0
        }
219
0
        if sign < 0 {
220
0
            decimal.start -= 1;
221
0
            decimal.buf[decimal.start as usize] = b'-';
222
0
        } else if let Some(zero_is_positive) = formatter.force_sign {
223
0
            let ascii_sign =
224
0
                if sign > 0 || zero_is_positive { b'+' } else { b'-' };
225
0
            decimal.start -= 1;
226
0
            decimal.buf[decimal.start as usize] = ascii_sign;
227
0
        }
228
0
        decimal
229
0
    }
230
231
    /// Returns the total number of ASCII bytes (including the sign) that are
232
    /// used to represent this decimal number.
233
    #[inline]
234
0
    const fn len(&self) -> u8 {
235
0
        self.end - self.start
236
0
    }
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
0
    fn as_bytes(&self) -> &[u8] {
243
0
        &self.buf[usize::from(self.start)..usize::from(self.end)]
244
0
    }
245
246
    /// Returns the ASCII representation of this decimal as a string slice.
247
    #[inline]
248
0
    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
0
        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
253
0
    }
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)]
262
pub(crate) struct FractionalFormatter {
263
    precision: Option<u8>,
264
}
265
266
impl FractionalFormatter {
267
    /// Creates a new fractional formatter using the given precision settings.
268
0
    pub(crate) const fn new() -> FractionalFormatter {
269
0
        FractionalFormatter { precision: None }
270
0
    }
271
272
    /// Format the given value using this configuration as a decimal ASCII
273
    /// fractional number.
274
0
    pub(crate) const fn format(&self, value: u32) -> Fractional {
275
0
        Fractional::new(self, value)
276
0
    }
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
0
    pub(crate) const fn precision(
285
0
        self,
286
0
        precision: Option<u8>,
287
0
    ) -> FractionalFormatter {
288
0
        let precision = match precision {
289
0
            None => None,
290
0
            Some(p) if p > 9 => Some(9),
291
0
            Some(p) => Some(p),
292
        };
293
0
        FractionalFormatter { precision, ..self }
294
0
    }
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
0
    pub(crate) fn will_write_digits(self, value: u32) -> bool {
302
0
        self.precision.map_or_else(|| value != 0, |p| p > 0)
303
0
    }
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
0
    pub(crate) fn has_non_zero_fixed_precision(self) -> bool {
312
0
        self.precision.map_or(false, |p| p > 0)
313
0
    }
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
0
    pub(crate) fn has_zero_fixed_precision(self) -> bool {
318
0
        self.precision.map_or(false, |p| p == 0)
319
0
    }
320
}
321
322
/// A formatted fractional number that can be converted to a sequence of bytes.
323
#[derive(Debug)]
324
pub(crate) struct Fractional {
325
    buf: [u8; Self::MAX_LEN as usize],
326
    end: u8,
327
}
328
329
impl 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
0
    pub(crate) const fn new(
344
0
        formatter: &FractionalFormatter,
345
0
        mut value: u32,
346
0
    ) -> Fractional {
347
0
        assert!(value <= 999_999_999);
348
0
        let mut fractional = Fractional {
349
0
            buf: [b'0'; Self::MAX_LEN as usize],
350
0
            end: Self::MAX_LEN,
351
0
        };
352
0
        let mut i = 9;
353
        loop {
354
0
            i -= 1;
355
356
0
            let digit = (value % 10) as u8;
357
0
            value /= 10;
358
0
            fractional.buf[i] += digit;
359
0
            if value == 0 {
360
0
                break;
361
0
            }
362
        }
363
0
        if let Some(precision) = formatter.precision {
364
0
            fractional.end = precision;
365
0
        } else {
366
0
            while fractional.end > 0
367
0
                && fractional.buf[fractional.end as usize - 1] == b'0'
368
0
            {
369
0
                fractional.end -= 1;
370
0
            }
371
        }
372
0
        fractional
373
0
    }
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
0
    pub(crate) fn as_bytes(&self) -> &[u8] {
380
0
        &self.buf[..usize::from(self.end)]
381
0
    }
382
383
    /// Returns the ASCII representation of this fractional number as a string
384
    /// slice. The slice returned may be empty.
385
0
    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
0
        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
390
0
    }
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)]
417
pub(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
437
impl 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
0
    pub(crate) fn set_unit_value(
457
0
        &mut self,
458
0
        unit: Unit,
459
0
        value: u64,
460
0
    ) -> Result<(), Error> {
461
0
        assert!(self.fraction.is_none());
462
463
0
        if let Some(min) = self.min {
464
0
            if min <= unit {
465
0
                return Err(err!(
466
0
                    "found value {value:?} with unit {unit} \
467
0
                     after unit {prev_unit}, but units must be \
468
0
                     written from largest to smallest \
469
0
                     (and they can't be repeated)",
470
0
                    unit = unit.singular(),
471
0
                    prev_unit = min.singular(),
472
0
                ));
473
0
            }
474
0
        }
475
        // Given the above check, the given unit must be smaller than any we
476
        // have seen so far.
477
0
        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
0
        if self.max.is_none() {
481
0
            self.max = Some(unit);
482
0
        }
483
0
        self.values[unit.as_usize()] = value;
484
0
        self.any_non_zero_units = self.any_non_zero_units || value != 0;
485
0
        Ok(())
486
0
    }
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
0
    pub(crate) fn set_hms(
498
0
        &mut self,
499
0
        hours: u64,
500
0
        minutes: u64,
501
0
        seconds: u64,
502
0
        fraction: Option<u32>,
503
0
    ) -> Result<(), Error> {
504
0
        if let Some(min) = self.min {
505
0
            if min <= Unit::Hour {
506
0
                return Err(err!(
507
0
                    "found `HH:MM:SS` after unit {min}, \
508
0
                             but `HH:MM:SS` can only appear after \
509
0
                             years, months, weeks or days",
510
0
                    min = min.singular(),
511
0
                ));
512
0
            }
513
0
        }
514
0
        self.set_unit_value(Unit::Hour, hours)?;
515
0
        self.set_unit_value(Unit::Minute, minutes)?;
516
0
        self.set_unit_value(Unit::Second, seconds)?;
517
0
        if let Some(fraction) = fraction {
518
0
            self.set_fraction(fraction)?;
519
0
        }
520
0
        Ok(())
521
0
    }
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
0
    pub(crate) fn set_fraction(&mut self, fraction: u32) -> Result<(), Error> {
541
0
        assert!(fraction <= 999_999_999);
542
0
        if self.min == Some(Unit::Nanosecond) {
543
0
            return Err(err!("fractional nanoseconds are not supported"));
544
0
        }
545
0
        if let Some(min) = self.min {
546
0
            if min > Unit::Hour {
547
0
                return Err(err!(
548
0
                    "fractional {plural} are not supported",
549
0
                    plural = min.plural()
550
0
                ));
551
0
            }
552
0
        }
553
0
        self.fraction = Some(fraction);
554
0
        Ok(())
555
0
    }
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
0
    pub(crate) fn set_sign(&mut self, sign: Sign) {
566
0
        self.sign = sign;
567
0
    }
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
0
    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
0
        if self.fraction.is_some()
597
0
            || self.values.iter().any(|&value| value > LIMIT)
598
            // If no unit was set, it's an error case.
599
0
            || self.max.is_none()
600
        {
601
0
            return self.to_span_general();
602
0
        }
603
604
0
        let mut span = Span::new();
605
606
0
        let years = self.values[Unit::Year.as_usize()] as i16;
607
0
        let months = self.values[Unit::Month.as_usize()] as i32;
608
0
        let weeks = self.values[Unit::Week.as_usize()] as i32;
609
0
        let days = self.values[Unit::Day.as_usize()] as i32;
610
0
        let hours = self.values[Unit::Hour.as_usize()] as i32;
611
0
        let mins = self.values[Unit::Minute.as_usize()] as i64;
612
0
        let secs = self.values[Unit::Second.as_usize()] as i64;
613
0
        let millis = self.values[Unit::Millisecond.as_usize()] as i64;
614
0
        let micros = self.values[Unit::Microsecond.as_usize()] as i64;
615
0
        let nanos = self.values[Unit::Nanosecond.as_usize()] as i64;
616
617
0
        span = span.years_unchecked(years);
618
0
        span = span.months_unchecked(months);
619
0
        span = span.weeks_unchecked(weeks);
620
0
        span = span.days_unchecked(days);
621
0
        span = span.hours_unchecked(hours);
622
0
        span = span.minutes_unchecked(mins);
623
0
        span = span.seconds_unchecked(secs);
624
0
        span = span.milliseconds_unchecked(millis);
625
0
        span = span.microseconds_unchecked(micros);
626
0
        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
0
        span = span.sign_unchecked(self.get_sign().as_ranged_integer());
632
633
0
        Ok(span)
634
0
    }
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
0
    fn to_span_general(&self) -> Result<Span, Error> {
645
0
        fn error_context(unit: Unit, value: i64) -> Error {
646
0
            err!(
647
0
                "failed to set value {value:?} as {unit} unit on span",
648
0
                unit = unit.singular(),
649
            )
650
0
        }
651
652
        #[cfg_attr(feature = "perf-inline", inline(always))]
653
0
        fn set_time_unit(
654
0
            unit: Unit,
655
0
            value: i64,
656
0
            span: Span,
657
0
            set: impl FnOnce(Span) -> Result<Span, Error>,
658
0
        ) -> Result<Span, Error> {
659
            #[cold]
660
            #[inline(never)]
661
0
            fn fractional_fallback(
662
0
                err: Error,
663
0
                unit: Unit,
664
0
                value: i64,
665
0
                span: Span,
666
0
            ) -> 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
0
                if unit > Unit::Hour || unit == Unit::Nanosecond {
671
0
                    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
0
                    fractional_time_to_span(unit, value, 0, span)
680
                }
681
0
            }
682
683
0
            set(span)
684
0
                .or_else(|err| fractional_fallback(err, unit, value, span))
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#4}>::{closure#0}
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#5}>::{closure#0}
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#6}>::{closure#0}
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#7}>::{closure#0}
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#8}>::{closure#0}
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#9}>::{closure#0}
685
0
                .with_context(|| error_context(unit, value))
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#4}>::{closure#1}
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#5}>::{closure#1}
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#6}>::{closure#1}
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#7}>::{closure#1}
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#8}>::{closure#1}
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#9}>::{closure#1}
686
0
        }
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#4}>
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#5}>
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#6}>
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#7}>
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#8}>
Unexecuted instantiation: <jiff::fmt::util::DurationUnits>::to_span_general::set_time_unit::<<jiff::fmt::util::DurationUnits>::to_span_general::{closure#9}>
687
688
0
        let (min, _) = self.get_min_max_units()?;
689
0
        let mut span = Span::new();
690
691
0
        if self.values[Unit::Year.as_usize()] != 0 {
692
0
            let value = self.get_unit_value(Unit::Year)?;
693
0
            span = span
694
0
                .try_years(value)
695
0
                .with_context(|| error_context(Unit::Year, value))?;
696
0
        }
697
0
        if self.values[Unit::Month.as_usize()] != 0 {
698
0
            let value = self.get_unit_value(Unit::Month)?;
699
0
            span = span
700
0
                .try_months(value)
701
0
                .with_context(|| error_context(Unit::Month, value))?;
702
0
        }
703
0
        if self.values[Unit::Week.as_usize()] != 0 {
704
0
            let value = self.get_unit_value(Unit::Week)?;
705
0
            span = span
706
0
                .try_weeks(value)
707
0
                .with_context(|| error_context(Unit::Week, value))?;
708
0
        }
709
0
        if self.values[Unit::Day.as_usize()] != 0 {
710
0
            let value = self.get_unit_value(Unit::Day)?;
711
0
            span = span
712
0
                .try_days(value)
713
0
                .with_context(|| error_context(Unit::Day, value))?;
714
0
        }
715
0
        if self.values[Unit::Hour.as_usize()] != 0 {
716
0
            let value = self.get_unit_value(Unit::Hour)?;
717
0
            span = set_time_unit(Unit::Hour, value, span, |span| {
718
0
                span.try_hours(value)
719
0
            })?;
720
0
        }
721
0
        if self.values[Unit::Minute.as_usize()] != 0 {
722
0
            let value = self.get_unit_value(Unit::Minute)?;
723
0
            span = set_time_unit(Unit::Minute, value, span, |span| {
724
0
                span.try_minutes(value)
725
0
            })?;
726
0
        }
727
0
        if self.values[Unit::Second.as_usize()] != 0 {
728
0
            let value = self.get_unit_value(Unit::Second)?;
729
0
            span = set_time_unit(Unit::Second, value, span, |span| {
730
0
                span.try_seconds(value)
731
0
            })?;
732
0
        }
733
0
        if self.values[Unit::Millisecond.as_usize()] != 0 {
734
0
            let value = self.get_unit_value(Unit::Millisecond)?;
735
0
            span = set_time_unit(Unit::Millisecond, value, span, |span| {
736
0
                span.try_milliseconds(value)
737
0
            })?;
738
0
        }
739
0
        if self.values[Unit::Microsecond.as_usize()] != 0 {
740
0
            let value = self.get_unit_value(Unit::Microsecond)?;
741
0
            span = set_time_unit(Unit::Microsecond, value, span, |span| {
742
0
                span.try_microseconds(value)
743
0
            })?;
744
0
        }
745
0
        if self.values[Unit::Nanosecond.as_usize()] != 0 {
746
0
            let value = self.get_unit_value(Unit::Nanosecond)?;
747
0
            span = set_time_unit(Unit::Nanosecond, value, span, |span| {
748
0
                span.try_nanoseconds(value)
749
0
            })?;
750
0
        }
751
752
0
        if let Some(fraction) = self.get_fraction()? {
753
0
            let value = self.get_unit_value(min)?;
754
0
            span = fractional_time_to_span(min, value, fraction, span)?;
755
0
        }
756
757
0
        Ok(span)
758
0
    }
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
0
    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
0
        if self.fraction.is_some()
788
0
            || self.values[..Unit::Day.as_usize()]
789
0
                .iter()
790
0
                .any(|&value| value > LIMIT)
791
0
            || self.max.map_or(true, |max| max > Unit::Hour)
792
        {
793
0
            return self.to_signed_duration_general();
794
0
        }
795
796
0
        let hours = self.values[Unit::Hour.as_usize()] as i64;
797
0
        let mins = self.values[Unit::Minute.as_usize()] as i64;
798
0
        let secs = self.values[Unit::Second.as_usize()] as i64;
799
0
        let millis = self.values[Unit::Millisecond.as_usize()] as i32;
800
0
        let micros = self.values[Unit::Microsecond.as_usize()] as i32;
801
0
        let nanos = self.values[Unit::Nanosecond.as_usize()] as i32;
802
803
0
        let total_secs = (hours * 3600) + (mins * 60) + secs;
804
0
        let total_nanos = (millis * 1_000_000) + (micros * 1_000) + nanos;
805
0
        let mut sdur =
806
0
            SignedDuration::new_without_nano_overflow(total_secs, total_nanos);
807
0
        if self.get_sign().is_negative() {
808
0
            sdur = -sdur;
809
0
        }
810
811
0
        Ok(sdur)
812
0
    }
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
0
    fn to_signed_duration_general(&self) -> Result<SignedDuration, Error> {
823
0
        let (min, max) = self.get_min_max_units()?;
824
0
        if max > Unit::Hour {
825
0
            return Err(err!(
826
0
                "parsing {unit} units into a `SignedDuration` is not supported \
827
0
                 (perhaps try parsing into a `Span` instead)",
828
0
                unit = max.singular(),
829
0
            ));
830
0
        }
831
832
0
        let mut sdur = SignedDuration::ZERO;
833
0
        if self.values[Unit::Hour.as_usize()] != 0 {
834
0
            let value = self.get_unit_value(Unit::Hour)?;
835
0
            sdur = SignedDuration::try_from_hours(value)
836
0
                .and_then(|nanos| sdur.checked_add(nanos))
837
0
                .ok_or_else(|| {
838
0
                    err!(
839
0
                        "accumulated `SignedDuration` of `{sdur:?}` \
840
0
                         overflowed when adding {value} of unit {unit}",
841
0
                        unit = Unit::Hour.singular(),
842
                    )
843
0
                })?;
844
0
        }
845
0
        if self.values[Unit::Minute.as_usize()] != 0 {
846
0
            let value = self.get_unit_value(Unit::Minute)?;
847
0
            sdur = SignedDuration::try_from_mins(value)
848
0
                .and_then(|nanos| sdur.checked_add(nanos))
849
0
                .ok_or_else(|| {
850
0
                    err!(
851
0
                        "accumulated `SignedDuration` of `{sdur:?}` \
852
0
                         overflowed when adding {value} of unit {unit}",
853
0
                        unit = Unit::Minute.singular(),
854
                    )
855
0
                })?;
856
0
        }
857
0
        if self.values[Unit::Second.as_usize()] != 0 {
858
0
            let value = self.get_unit_value(Unit::Second)?;
859
0
            sdur = SignedDuration::from_secs(value)
860
0
                .checked_add(sdur)
861
0
                .ok_or_else(|| {
862
0
                    err!(
863
0
                        "accumulated `SignedDuration` of `{sdur:?}` \
864
0
                         overflowed when adding {value} of unit {unit}",
865
0
                        unit = Unit::Second.singular(),
866
                    )
867
0
                })?;
868
0
        }
869
0
        if self.values[Unit::Millisecond.as_usize()] != 0 {
870
0
            let value = self.get_unit_value(Unit::Millisecond)?;
871
0
            sdur = SignedDuration::from_millis(value)
872
0
                .checked_add(sdur)
873
0
                .ok_or_else(|| {
874
0
                    err!(
875
0
                        "accumulated `SignedDuration` of `{sdur:?}` \
876
0
                         overflowed when adding {value} of unit {unit}",
877
0
                        unit = Unit::Millisecond.singular(),
878
                    )
879
0
                })?;
880
0
        }
881
0
        if self.values[Unit::Microsecond.as_usize()] != 0 {
882
0
            let value = self.get_unit_value(Unit::Microsecond)?;
883
0
            sdur = SignedDuration::from_micros(value)
884
0
                .checked_add(sdur)
885
0
                .ok_or_else(|| {
886
0
                    err!(
887
0
                        "accumulated `SignedDuration` of `{sdur:?}` \
888
0
                         overflowed when adding {value} of unit {unit}",
889
0
                        unit = Unit::Microsecond.singular(),
890
                    )
891
0
                })?;
892
0
        }
893
0
        if self.values[Unit::Nanosecond.as_usize()] != 0 {
894
0
            let value = self.get_unit_value(Unit::Nanosecond)?;
895
0
            sdur = SignedDuration::from_nanos(value)
896
0
                .checked_add(sdur)
897
0
                .ok_or_else(|| {
898
0
                    err!(
899
0
                        "accumulated `SignedDuration` of `{sdur:?}` \
900
0
                         overflowed when adding {value} of unit {unit}",
901
0
                        unit = Unit::Nanosecond.singular(),
902
                    )
903
0
                })?;
904
0
        }
905
906
0
        if let Some(fraction) = self.get_fraction()? {
907
0
            sdur = sdur
908
0
                .checked_add(fractional_duration(min, fraction)?)
909
0
                .ok_or_else(|| {
910
0
                    err!(
911
0
                        "accumulated `SignedDuration` of `{sdur:?}` \
912
0
                         overflowed when adding 0.{fraction} of unit {unit}",
913
0
                        unit = min.singular(),
914
                    )
915
0
                })?;
916
0
        }
917
918
0
        Ok(sdur)
919
0
    }
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
0
    pub(crate) fn to_unsigned_duration(
933
0
        &self,
934
0
    ) -> 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
0
        if self.fraction.is_some()
951
0
            || self.values[..Unit::Day.as_usize()]
952
0
                .iter()
953
0
                .any(|&value| value > LIMIT)
954
0
            || self.max.map_or(true, |max| max > Unit::Hour)
955
0
            || self.sign.is_negative()
956
        {
957
0
            return self.to_unsigned_duration_general();
958
0
        }
959
960
0
        let hours = self.values[Unit::Hour.as_usize()];
961
0
        let mins = self.values[Unit::Minute.as_usize()];
962
0
        let secs = self.values[Unit::Second.as_usize()];
963
0
        let millis = self.values[Unit::Millisecond.as_usize()] as u32;
964
0
        let micros = self.values[Unit::Microsecond.as_usize()] as u32;
965
0
        let nanos = self.values[Unit::Nanosecond.as_usize()] as u32;
966
967
0
        let total_secs = (hours * 3600) + (mins * 60) + secs;
968
0
        let total_nanos = (millis * 1_000_000) + (micros * 1_000) + nanos;
969
0
        let sdur = core::time::Duration::new(total_secs, total_nanos);
970
971
0
        Ok(sdur)
972
0
    }
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
0
    fn to_unsigned_duration_general(
983
0
        &self,
984
0
    ) -> Result<core::time::Duration, Error> {
985
        #[inline]
986
0
        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
0
            if hours > MAX_HOUR {
990
0
                return None;
991
0
            }
992
0
            Some(core::time::Duration::from_secs(hours * 60 * 60))
993
0
        }
994
995
        #[inline]
996
0
        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
0
            if mins > MAX_MINUTE {
1000
0
                return None;
1001
0
            }
1002
0
            Some(core::time::Duration::from_secs(mins * 60))
1003
0
        }
1004
1005
0
        if self.sign.is_negative() {
1006
0
            return Err(err!(
1007
0
                "cannot parse negative duration into unsigned \
1008
0
                 `std::time::Duration`",
1009
0
            ));
1010
0
        }
1011
1012
0
        let (min, max) = self.get_min_max_units()?;
1013
0
        if max > Unit::Hour {
1014
0
            return Err(err!(
1015
0
                "parsing {unit} units into a `std::time::Duration` \
1016
0
                 is not supported (perhaps try parsing into a `Span` instead)",
1017
0
                unit = max.singular(),
1018
0
            ));
1019
0
        }
1020
1021
0
        let mut sdur = core::time::Duration::ZERO;
1022
0
        if self.values[Unit::Hour.as_usize()] != 0 {
1023
0
            let value = self.values[Unit::Hour.as_usize()];
1024
0
            sdur = try_from_hours(value)
1025
0
                .and_then(|nanos| sdur.checked_add(nanos))
1026
0
                .ok_or_else(|| {
1027
0
                    err!(
1028
0
                        "accumulated `std::time::Duration` of `{sdur:?}` \
1029
0
                         overflowed when adding {value} of unit {unit}",
1030
0
                        unit = Unit::Hour.singular(),
1031
                    )
1032
0
                })?;
1033
0
        }
1034
0
        if self.values[Unit::Minute.as_usize()] != 0 {
1035
0
            let value = self.values[Unit::Minute.as_usize()];
1036
0
            sdur = try_from_mins(value)
1037
0
                .and_then(|nanos| sdur.checked_add(nanos))
1038
0
                .ok_or_else(|| {
1039
0
                    err!(
1040
0
                        "accumulated `std::time::Duration` of `{sdur:?}` \
1041
0
                         overflowed when adding {value} of unit {unit}",
1042
0
                        unit = Unit::Minute.singular(),
1043
                    )
1044
0
                })?;
1045
0
        }
1046
0
        if self.values[Unit::Second.as_usize()] != 0 {
1047
0
            let value = self.values[Unit::Second.as_usize()];
1048
0
            sdur = core::time::Duration::from_secs(value)
1049
0
                .checked_add(sdur)
1050
0
                .ok_or_else(|| {
1051
0
                    err!(
1052
0
                        "accumulated `std::time::Duration` of `{sdur:?}` \
1053
0
                         overflowed when adding {value} of unit {unit}",
1054
0
                        unit = Unit::Second.singular(),
1055
                    )
1056
0
                })?;
1057
0
        }
1058
0
        if self.values[Unit::Millisecond.as_usize()] != 0 {
1059
0
            let value = self.values[Unit::Millisecond.as_usize()];
1060
0
            sdur = core::time::Duration::from_millis(value)
1061
0
                .checked_add(sdur)
1062
0
                .ok_or_else(|| {
1063
0
                    err!(
1064
0
                        "accumulated `std::time::Duration` of `{sdur:?}` \
1065
0
                         overflowed when adding {value} of unit {unit}",
1066
0
                        unit = Unit::Millisecond.singular(),
1067
                    )
1068
0
                })?;
1069
0
        }
1070
0
        if self.values[Unit::Microsecond.as_usize()] != 0 {
1071
0
            let value = self.values[Unit::Microsecond.as_usize()];
1072
0
            sdur = core::time::Duration::from_micros(value)
1073
0
                .checked_add(sdur)
1074
0
                .ok_or_else(|| {
1075
0
                    err!(
1076
0
                        "accumulated `std::time::Duration` of `{sdur:?}` \
1077
0
                         overflowed when adding {value} of unit {unit}",
1078
0
                        unit = Unit::Microsecond.singular(),
1079
                    )
1080
0
                })?;
1081
0
        }
1082
0
        if self.values[Unit::Nanosecond.as_usize()] != 0 {
1083
0
            let value = self.values[Unit::Nanosecond.as_usize()];
1084
0
            sdur = core::time::Duration::from_nanos(value)
1085
0
                .checked_add(sdur)
1086
0
                .ok_or_else(|| {
1087
0
                err!(
1088
0
                    "accumulated `std::time::Duration` of `{sdur:?}` \
1089
0
                         overflowed when adding {value} of unit {unit}",
1090
0
                    unit = Unit::Nanosecond.singular(),
1091
                )
1092
0
            })?;
1093
0
        }
1094
1095
0
        if let Some(fraction) = self.get_fraction()? {
1096
0
            sdur = sdur
1097
0
                .checked_add(
1098
0
                    fractional_duration(min, fraction)?.unsigned_abs(),
1099
                )
1100
0
                .ok_or_else(|| {
1101
0
                    err!(
1102
0
                        "accumulated `std::time::Duration` of `{sdur:?}` \
1103
0
                         overflowed when adding 0.{fraction} of unit {unit}",
1104
0
                        unit = min.singular(),
1105
                    )
1106
0
                })?;
1107
0
        }
1108
1109
0
        Ok(sdur)
1110
0
    }
1111
1112
    /// Returns the minimum unit set.
1113
    ///
1114
    /// This only returns `None` when no units have been set.
1115
0
    pub(crate) fn get_min(&self) -> Option<Unit> {
1116
0
        self.min
1117
0
    }
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
0
    fn get_min_max_units(&self) -> Result<(Unit, Unit), Error> {
1124
0
        let (Some(min), Some(max)) = (self.min, self.max) else {
1125
0
            return Err(err!("no parsed duration components"));
1126
        };
1127
0
        Ok((min, max))
1128
0
    }
1129
1130
    /// Returns the corresponding unit value using the set signed-ness.
1131
    #[cfg_attr(feature = "perf-inline", inline(always))]
1132
0
    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
0
        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
0
            if sign.is_negative() && value == I64_MIN_ABS {
1142
0
                return Ok(i64::MIN);
1143
0
            }
1144
            // Otherwise, if a conversion to `i64` fails, then that failure
1145
            // is correct.
1146
0
            let mut value = i64::try_from(value).map_err(|_| {
1147
0
                err!(
1148
0
                    "`{sign}{value}` {unit} is too big (or small) \
1149
0
                     to fit into a signed 64-bit integer",
1150
0
                    unit = unit.plural()
1151
                )
1152
0
            })?;
1153
0
            if sign.is_negative() {
1154
0
                value = value.checked_neg().ok_or_else(|| {
1155
0
                    err!(
1156
0
                        "`{sign}{value}` {unit} is too big (or small) \
1157
0
                         to fit into a signed 64-bit integer",
1158
0
                        unit = unit.plural()
1159
                    )
1160
0
                })?;
1161
0
            }
1162
0
            Ok(value)
1163
0
        }
1164
1165
0
        let sign = self.get_sign();
1166
0
        let value = self.values[unit.as_usize()];
1167
0
        if value >= I64_MIN_ABS {
1168
0
            return general(unit, value, sign);
1169
0
        }
1170
0
        let mut value = value as i64;
1171
0
        if sign.is_negative() {
1172
0
            value = -value;
1173
0
        }
1174
0
        Ok(value)
1175
0
    }
1176
1177
    /// Returns the fraction using the set signed-ness.
1178
    ///
1179
    /// This returns `None` when no fraction has been set.
1180
0
    fn get_fraction(&self) -> Result<Option<i32>, Error> {
1181
0
        let Some(fraction) = self.fraction else {
1182
0
            return Ok(None);
1183
        };
1184
        // OK because `set_fraction` guarantees `0..=999_999_999`.
1185
0
        let mut fraction = fraction as i32;
1186
0
        if self.get_sign().is_negative() {
1187
0
            // OK because `set_fraction` guarantees `0..=999_999_999`.
1188
0
            fraction = -fraction;
1189
0
        }
1190
0
        Ok(Some(fraction))
1191
0
    }
1192
1193
    /// Returns the sign that should be applied to each individual unit.
1194
0
    fn get_sign(&self) -> Sign {
1195
0
        if self.any_non_zero_units {
1196
0
            self.sign
1197
        } else {
1198
0
            Sign::Zero
1199
        }
1200
0
    }
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))]
1219
0
pub(crate) fn parse_temporal_fraction<'i>(
1220
0
    input: &'i [u8],
1221
0
) -> 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
0
    fn imp<'i>(mut input: &'i [u8]) -> Result<Parsed<'i, Option<u32>>, Error> {
1253
0
        let mkdigits = parse::slicer(input);
1254
0
        while mkdigits(input).len() <= 8
1255
0
            && input.first().map_or(false, u8::is_ascii_digit)
1256
0
        {
1257
0
            input = &input[1..];
1258
0
        }
1259
0
        let digits = mkdigits(input);
1260
0
        if digits.is_empty() {
1261
0
            return Err(err!(
1262
0
                "found decimal after seconds component, \
1263
0
                 but did not find any decimal digits after decimal",
1264
0
            ));
1265
0
        }
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
0
        let nanoseconds = parse::fraction(digits).map_err(|err| {
1270
0
            err!(
1271
0
                "failed to parse {digits:?} as fractional component \
1272
0
                 (up to 9 digits, nanosecond precision): {err}",
1273
0
                digits = escape::Bytes(digits),
1274
            )
1275
0
        })?;
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
0
        let nanoseconds = nanoseconds as u32;
1280
0
        Ok(Parsed { value: Some(nanoseconds), input })
1281
0
    }
1282
1283
0
    if input.is_empty() || (input[0] != b'.' && input[0] != b',') {
1284
0
        return Ok(Parsed { value: None, input });
1285
0
    }
1286
0
    imp(&input[1..])
1287
0
}
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)]
1308
0
fn fractional_time_to_span(
1309
0
    unit: Unit,
1310
0
    value: i64,
1311
0
    fraction: i32,
1312
0
    mut span: Span,
1313
0
) -> 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
0
    let mut sdur = fractional_time_to_duration(unit, value, fraction)?;
1346
1347
0
    if unit >= Unit::Hour && !sdur.is_zero() {
1348
0
        let (mut hours, rem) = sdur.as_hours_with_remainder();
1349
0
        sdur = rem;
1350
0
        if hours > MAX_HOURS {
1351
0
            sdur += SignedDuration::from_hours(hours - MAX_HOURS);
1352
0
            hours = MAX_HOURS;
1353
0
        } else if hours < MIN_HOURS {
1354
0
            sdur += SignedDuration::from_hours(hours - MIN_HOURS);
1355
0
            hours = MIN_HOURS;
1356
0
        }
1357
        // OK because we just checked that our units are in range.
1358
0
        span = span.hours(hours);
1359
0
    }
1360
0
    if unit >= Unit::Minute && !sdur.is_zero() {
1361
0
        let (mut mins, rem) = sdur.as_mins_with_remainder();
1362
0
        sdur = rem;
1363
0
        if mins > MAX_MINS {
1364
0
            sdur += SignedDuration::from_mins(mins - MAX_MINS);
1365
0
            mins = MAX_MINS;
1366
0
        } else if mins < MIN_MINS {
1367
0
            sdur += SignedDuration::from_mins(mins - MIN_MINS);
1368
0
            mins = MIN_MINS;
1369
0
        }
1370
        // OK because we just checked that our units are in range.
1371
0
        span = span.minutes(mins);
1372
0
    }
1373
0
    if unit >= Unit::Second && !sdur.is_zero() {
1374
0
        let (mut secs, rem) = sdur.as_secs_with_remainder();
1375
0
        sdur = rem;
1376
0
        if secs > MAX_SECS {
1377
0
            sdur += SignedDuration::from_secs(secs - MAX_SECS);
1378
0
            secs = MAX_SECS;
1379
0
        } else if secs < MIN_SECS {
1380
0
            sdur += SignedDuration::from_secs(secs - MIN_SECS);
1381
0
            secs = MIN_SECS;
1382
0
        }
1383
        // OK because we just checked that our units are in range.
1384
0
        span = span.seconds(secs);
1385
0
    }
1386
0
    if unit >= Unit::Millisecond && !sdur.is_zero() {
1387
0
        let (mut millis, rem) = sdur.as_millis_with_remainder();
1388
0
        sdur = rem;
1389
0
        if millis > MAX_MILLIS {
1390
0
            sdur += SignedDuration::from_millis_i128(millis - MAX_MILLIS);
1391
0
            millis = MAX_MILLIS;
1392
0
        } else if millis < MIN_MILLIS {
1393
0
            sdur += SignedDuration::from_millis_i128(millis - MIN_MILLIS);
1394
0
            millis = MIN_MILLIS;
1395
0
        }
1396
        // OK because we just checked that our units are in range.
1397
0
        span = span.milliseconds(i64::try_from(millis).unwrap());
1398
0
    }
1399
0
    if unit >= Unit::Microsecond && !sdur.is_zero() {
1400
0
        let (mut micros, rem) = sdur.as_micros_with_remainder();
1401
0
        sdur = rem;
1402
0
        if micros > MAX_MICROS {
1403
0
            sdur += SignedDuration::from_micros_i128(micros - MAX_MICROS);
1404
0
            micros = MAX_MICROS;
1405
0
        } else if micros < MIN_MICROS {
1406
0
            sdur += SignedDuration::from_micros_i128(micros - MIN_MICROS);
1407
0
            micros = MIN_MICROS;
1408
0
        }
1409
        // OK because we just checked that our units are in range.
1410
0
        span = span.microseconds(i64::try_from(micros).unwrap());
1411
0
    }
1412
0
    if !sdur.is_zero() {
1413
0
        let nanos = sdur.as_nanos();
1414
0
        let nanos64 = i64::try_from(nanos).map_err(|_| {
1415
0
            err!(
1416
0
                "failed to set nanosecond value {nanos} (it overflows \
1417
0
                 `i64`) on span determined from {value}.{fraction}",
1418
            )
1419
0
        })?;
1420
0
        span = span.try_nanoseconds(nanos64).with_context(|| {
1421
0
            err!(
1422
0
                "failed to set nanosecond value {nanos64} on span \
1423
0
                 determined from {value}.{fraction}",
1424
            )
1425
0
        })?;
1426
0
    }
1427
1428
0
    Ok(span)
1429
0
}
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)]
1448
0
fn fractional_time_to_duration(
1449
0
    unit: Unit,
1450
0
    value: i64,
1451
0
    fraction: i32,
1452
0
) -> Result<SignedDuration, Error> {
1453
0
    let sdur = duration_unit_value(unit, value)?;
1454
0
    let fraction_dur = fractional_duration(unit, fraction)?;
1455
0
    sdur.checked_add(fraction_dur).ok_or_else(|| {
1456
0
        err!(
1457
0
            "accumulated `SignedDuration` of `{sdur:?}` overflowed \
1458
0
             when adding `{fraction_dur:?}` (from fractional {unit} units)",
1459
0
            unit = unit.singular(),
1460
        )
1461
0
    })
1462
0
}
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)]
1479
0
fn fractional_duration(
1480
0
    unit: Unit,
1481
0
    fraction: i32,
1482
0
) -> Result<SignedDuration, Error> {
1483
0
    let fraction = i64::from(fraction);
1484
0
    let nanos = match unit {
1485
0
        Unit::Hour => fraction * t::SECONDS_PER_HOUR.value(),
1486
0
        Unit::Minute => fraction * t::SECONDS_PER_MINUTE.value(),
1487
0
        Unit::Second => fraction,
1488
0
        Unit::Millisecond => fraction / t::NANOS_PER_MICRO.value(),
1489
0
        Unit::Microsecond => fraction / t::NANOS_PER_MILLI.value(),
1490
0
        unit => {
1491
0
            return Err(err!(
1492
0
                "fractional {unit} units are not allowed",
1493
0
                unit = unit.singular(),
1494
0
            ))
1495
        }
1496
    };
1497
0
    Ok(SignedDuration::from_nanos(nanos))
1498
0
}
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))]
1507
0
fn duration_unit_value(
1508
0
    unit: Unit,
1509
0
    value: i64,
1510
0
) -> 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
0
    let sdur = match unit {
1516
        Unit::Hour => {
1517
0
            let seconds = value
1518
0
                .checked_mul(t::SECONDS_PER_HOUR.value())
1519
0
                .ok_or_else(|| {
1520
0
                    err!("converting {value} hours to seconds overflows i64")
1521
0
                })?;
1522
0
            SignedDuration::from_secs(seconds)
1523
        }
1524
        Unit::Minute => {
1525
0
            let seconds = value
1526
0
                .checked_mul(t::SECONDS_PER_MINUTE.value())
1527
0
                .ok_or_else(|| {
1528
0
                    err!("converting {value} minutes to seconds overflows i64")
1529
0
                })?;
1530
0
            SignedDuration::from_secs(seconds)
1531
        }
1532
0
        Unit::Second => SignedDuration::from_secs(value),
1533
0
        Unit::Millisecond => SignedDuration::from_millis(value),
1534
0
        Unit::Microsecond => SignedDuration::from_micros(value),
1535
0
        Unit::Nanosecond => SignedDuration::from_nanos(value),
1536
0
        unsupported => {
1537
0
            return Err(err!(
1538
0
                "parsing {unit} units into a `SignedDuration` is not supported \
1539
0
                 (perhaps try parsing into a `Span` instead)",
1540
0
                unit = unsupported.singular(),
1541
0
            ));
1542
        }
1543
    };
1544
0
    Ok(sdur)
1545
0
}
1546
1547
#[cfg(test)]
1548
mod 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
}