1mod component_provider;
4pub(crate) mod formattable;
5mod iso8601;
6mod metadata;
7
8use core::mem::MaybeUninit;
9use core::num::NonZero;
10use std::io;
11
12use deranged::{Option_ri32, Option_ru8, ri8, ri16, ri32, ru8, ru16, ru32};
13use num_conv::prelude::*;
14
15use self::component_provider::ComponentProvider;
16pub use self::formattable::Formattable;
17use crate::format_description::{Period, modifier};
18use crate::internal_macros::try_likely_ok;
19use crate::time::{Hours, Minutes, Nanoseconds, Seconds};
20use crate::utc_offset::{Hours as OffsetHours, Minutes as OffsetMinutes, Seconds as OffsetSeconds};
21use crate::{Month, Weekday, error, num_fmt};
22
23type Day = ru8<1, 31>;
24type OptionDay = Option_ru8<1, 31>;
25type Ordinal = ru16<1, 366>;
26type IsoWeekNumber = ru8<1, 53>;
27type OptionIsoWeekNumber = Option_ru8<1, 53>;
28type MondayBasedWeek = ru8<0, 53>;
29type SundayBasedWeek = ru8<0, 53>;
30type Year = ri32<-999_999, 999_999>;
31type StandardYear = ri16<-9_999, 9_999>;
32type OptionYear = Option_ri32<-999_999, 999_999>;
33type ExtendedCentury = ri16<-9_999, 9_999>;
34type StandardCentury = ri8<-99, 99>;
35type LastTwo = ru8<0, 99>;
36
37const MONTH_NAMES: [&str; 12] = [
38 "January",
39 "February",
40 "March",
41 "April",
42 "May",
43 "June",
44 "July",
45 "August",
46 "September",
47 "October",
48 "November",
49 "December",
50];
51
52const WEEKDAY_NAMES: [&str; 7] = [
53 "Monday",
54 "Tuesday",
55 "Wednesday",
56 "Thursday",
57 "Friday",
58 "Saturday",
59 "Sunday",
60];
61
62#[inline]
64pub(crate) fn write_bytes(
65 output: &mut (impl io::Write + ?Sized),
66 bytes: &[u8],
67) -> io::Result<usize> {
68 try_likely_ok!(output.write_all(bytes));
69 Ok(bytes.len())
70}
71
72#[inline]
74pub(crate) fn write(output: &mut (impl io::Write + ?Sized), s: &str) -> io::Result<usize> {
75 try_likely_ok!(output.write_all(s.as_bytes()));
76 Ok(s.len())
77}
78
79#[inline]
81pub(crate) fn write_many<const N: usize>(
82 output: &mut (impl io::Write + ?Sized),
83 arr: [&str; N],
84) -> io::Result<usize> {
85 let mut bytes = 0;
86 for s in arr {
87 try_likely_ok!(output.write_all(s.as_bytes()));
88 bytes += s.len();
89 }
90 Ok(bytes)
91}
92
93#[inline]
95pub(crate) fn write_if(
96 output: &mut (impl io::Write + ?Sized),
97 pred: bool,
98 s: &str,
99) -> io::Result<usize> {
100 if pred { write(output, s) } else { Ok(0) }
101}
102
103#[inline]
105pub(crate) fn write_if_else(
106 output: &mut (impl io::Write + ?Sized),
107 pred: bool,
108 true_str: &str,
109 false_str: &str,
110) -> io::Result<usize> {
111 write(output, if pred { true_str } else { false_str })
112}
113
114#[inline]
119fn f64_10_pow_x(x: NonZero<u8>) -> f64 {
120 match x.get() {
121 1 => 10.,
122 2 => 100.,
123 3 => 1_000.,
124 4 => 10_000.,
125 5 => 100_000.,
126 6 => 1_000_000.,
127 7 => 10_000_000.,
128 8 => 100_000_000.,
129 9 => 1_000_000_000.,
130 x => 10_f64.powi(x.cast_signed().widen()),
131 }
132}
133
134#[inline]
139fn format_int_padded(
140 output: &mut (impl io::Write + ?Sized),
141 value: u64,
142 width: u8,
143) -> io::Result<usize> {
144 let s = num_fmt::u64_pad_none(value);
145 let digit_count = s.len() as u8;
146 for _ in digit_count..width {
147 try_likely_ok!(output.write_all(b"0"));
148 }
149 try_likely_ok!(output.write_all(s.as_bytes()));
150 Ok(width as usize)
151}
152
153#[inline]
158pub(crate) fn format_float(
159 output: &mut (impl io::Write + ?Sized),
160 mut value: f64,
161 digits_before_decimal: u8,
162 digits_after_decimal: Option<NonZero<u8>>,
163) -> io::Result<usize> {
164 match digits_after_decimal {
165 Some(digits_after_decimal) => {
166 if digits_after_decimal.get() < 9 {
179 let trunc_num = f64_10_pow_x(digits_after_decimal);
180 value = f64::trunc(value * trunc_num) / trunc_num;
181
182 let int_part = value.trunc() as u64;
183 let frac_part =
184 f64::round(value.fract() * f64_10_pow_x(digits_after_decimal)) as u64;
185
186 let width = digits_before_decimal.widen::<usize>()
187 + 1
188 + digits_after_decimal.get().widen::<usize>();
189
190 try_likely_ok!(format_int_padded(
191 output,
192 int_part,
193 digits_before_decimal.widen()
194 ));
195 try_likely_ok!(output.write_all(b"."));
196 try_likely_ok!(format_int_padded(
197 output,
198 frac_part,
199 digits_after_decimal.get().widen()
200 ));
201
202 Ok(width)
203 } else {
204 let digits_after = digits_after_decimal.get().widen::<usize>();
208 let width = digits_before_decimal.widen::<usize>() + 1 + digits_after;
209 try_likely_ok!(write!(output, "{value:0>width$.digits_after$}"));
210 Ok(width)
211 }
212 }
213 None => format_int_padded(output, value.trunc() as u64, digits_before_decimal),
214 }
215}
216
217#[inline]
219pub(crate) fn format_single_digit(
220 output: &mut (impl io::Write + ?Sized),
221 value: ru8<0, 9>,
222) -> io::Result<usize> {
223 write(output, num_fmt::single_digit(value))
224}
225
226#[inline]
228pub(crate) fn format_two_digits(
229 output: &mut (impl io::Write + ?Sized),
230 value: ru8<0, 99>,
231 padding: modifier::Padding,
232) -> io::Result<usize> {
233 let s = match padding {
234 modifier::Padding::Space => num_fmt::two_digits_space_padded(value),
235 modifier::Padding::Zero => num_fmt::two_digits_zero_padded(value),
236 modifier::Padding::None => num_fmt::one_to_two_digits_no_padding(value),
237 };
238 write(output, s)
239}
240
241#[inline]
243pub(crate) fn format_three_digits(
244 output: &mut (impl io::Write + ?Sized),
245 value: ru16<0, 999>,
246 padding: modifier::Padding,
247) -> io::Result<usize> {
248 let [first, second_and_third] = match padding {
249 modifier::Padding::Space => num_fmt::three_digits_space_padded(value),
250 modifier::Padding::Zero => num_fmt::three_digits_zero_padded(value),
251 modifier::Padding::None => num_fmt::one_to_three_digits_no_padding(value),
252 };
253 write_many(output, [first, second_and_third])
254}
255
256#[inline]
258pub(crate) fn format_four_digits(
259 output: &mut (impl io::Write + ?Sized),
260 value: ru16<0, 9_999>,
261 padding: modifier::Padding,
262) -> io::Result<usize> {
263 let [first_and_second, third_and_fourth] = match padding {
264 modifier::Padding::Space => num_fmt::four_digits_space_padded(value),
265 modifier::Padding::Zero => num_fmt::four_digits_zero_padded(value),
266 modifier::Padding::None => num_fmt::one_to_four_digits_no_padding(value),
267 };
268 write_many(output, [first_and_second, third_and_fourth])
269}
270
271#[inline]
273pub(crate) fn format_four_digits_pad_zero(
274 output: &mut (impl io::Write + ?Sized),
275 value: ru16<0, 9_999>,
276) -> io::Result<usize> {
277 write_many(output, num_fmt::four_digits_zero_padded(value))
278}
279
280#[inline]
282pub(crate) fn format_five_digits_pad_zero(
283 output: &mut (impl io::Write + ?Sized),
284 value: ru32<0, 99_999>,
285) -> io::Result<usize> {
286 write_many(output, num_fmt::five_digits_zero_padded(value))
287}
288
289#[inline]
291pub(crate) fn format_six_digits_pad_zero(
292 output: &mut (impl io::Write + ?Sized),
293 value: ru32<0, 999_999>,
294) -> io::Result<usize> {
295 write_many(output, num_fmt::six_digits_zero_padded(value))
296}
297
298#[inline]
302pub(crate) fn format_u64_pad_none(
303 output: &mut (impl io::Write + ?Sized),
304 value: u64,
305) -> io::Result<usize> {
306 write(output, &num_fmt::u64_pad_none(value))
307}
308
309#[inline]
313pub(crate) fn format_u128_pad_none(
314 output: &mut (impl io::Write + ?Sized),
315 value: u128,
316) -> io::Result<usize> {
317 write(output, &num_fmt::u128_pad_none(value))
318}
319
320#[inline]
322fn fmt_day(
323 output: &mut (impl io::Write + ?Sized),
324 day: Day,
325 modifier::Day { padding }: modifier::Day,
326) -> Result<usize, io::Error> {
327 format_two_digits(output, day.expand(), padding)
328}
329
330#[inline]
332fn fmt_month_short(
333 output: &mut (impl io::Write + ?Sized),
334 month: Month,
335 modifier::MonthShort {
336 case_sensitive: _, }: modifier::MonthShort,
338) -> io::Result<usize> {
339 write(output, unsafe {
341 MONTH_NAMES[u8::from(month).widen::<usize>() - 1].get_unchecked(..3)
342 })
343}
344
345#[inline]
347fn fmt_month_long(
348 output: &mut (impl io::Write + ?Sized),
349 month: Month,
350 modifier::MonthLong {
351 case_sensitive: _, }: modifier::MonthLong,
353) -> io::Result<usize> {
354 write(output, MONTH_NAMES[u8::from(month).widen::<usize>() - 1])
355}
356
357#[inline]
359fn fmt_month_numerical(
360 output: &mut (impl io::Write + ?Sized),
361 month: Month,
362 modifier::MonthNumerical { padding }: modifier::MonthNumerical,
363) -> io::Result<usize> {
364 format_two_digits(
365 output,
366 unsafe { ru8::new_unchecked(u8::from(month)) },
368 padding,
369 )
370}
371
372#[inline]
374fn fmt_ordinal(
375 output: &mut (impl io::Write + ?Sized),
376 ordinal: Ordinal,
377 modifier::Ordinal { padding }: modifier::Ordinal,
378) -> Result<usize, io::Error> {
379 format_three_digits(output, ordinal.expand(), padding)
380}
381
382#[inline]
384fn fmt_weekday_short(
385 output: &mut (impl io::Write + ?Sized),
386 weekday: Weekday,
387 modifier::WeekdayShort {
388 case_sensitive: _, }: modifier::WeekdayShort,
390) -> io::Result<usize> {
391 write(output, unsafe {
393 WEEKDAY_NAMES[weekday.number_days_from_monday().widen::<usize>()].get_unchecked(..3)
394 })
395}
396
397#[inline]
399fn fmt_weekday_long(
400 output: &mut (impl io::Write + ?Sized),
401 weekday: Weekday,
402 modifier::WeekdayLong {
403 case_sensitive: _, }: modifier::WeekdayLong,
405) -> io::Result<usize> {
406 write(
407 output,
408 WEEKDAY_NAMES[weekday.number_days_from_monday().widen::<usize>()],
409 )
410}
411
412#[inline]
415fn fmt_weekday_sunday(
416 output: &mut (impl io::Write + ?Sized),
417 weekday: Weekday,
418 modifier::WeekdaySunday { one_indexed }: modifier::WeekdaySunday,
419) -> io::Result<usize> {
420 format_single_digit(output, unsafe {
422 ru8::new_unchecked(weekday.number_days_from_sunday() + u8::from(one_indexed))
423 })
424}
425
426#[inline]
429fn fmt_weekday_monday(
430 output: &mut (impl io::Write + ?Sized),
431 weekday: Weekday,
432 modifier::WeekdayMonday { one_indexed }: modifier::WeekdayMonday,
433) -> io::Result<usize> {
434 format_single_digit(output, unsafe {
436 ru8::new_unchecked(weekday.number_days_from_monday() + u8::from(one_indexed))
437 })
438}
439
440#[inline]
441fn fmt_week_number_iso(
442 output: &mut (impl io::Write + ?Sized),
443 week_number: IsoWeekNumber,
444 modifier::WeekNumberIso { padding }: modifier::WeekNumberIso,
445) -> io::Result<usize> {
446 format_two_digits(output, week_number.expand(), padding)
447}
448
449#[inline]
450fn fmt_week_number_sunday(
451 output: &mut (impl io::Write + ?Sized),
452 week_number: SundayBasedWeek,
453 modifier::WeekNumberSunday { padding }: modifier::WeekNumberSunday,
454) -> io::Result<usize> {
455 format_two_digits(output, week_number.expand(), padding)
456}
457
458#[inline]
459fn fmt_week_number_monday(
460 output: &mut (impl io::Write + ?Sized),
461 week_number: MondayBasedWeek,
462 modifier::WeekNumberMonday { padding }: modifier::WeekNumberMonday,
463) -> io::Result<usize> {
464 format_two_digits(output, week_number.expand(), padding)
465}
466
467#[inline]
468fn fmt_calendar_year_full_extended_range(
469 output: &mut (impl io::Write + ?Sized),
470 full_year: Year,
471 modifier::CalendarYearFullExtendedRange {
472 padding,
473 sign_is_mandatory,
474 }: modifier::CalendarYearFullExtendedRange,
475) -> io::Result<usize> {
476 let mut bytes = 0;
477 bytes += try_likely_ok!(fmt_sign(
478 output,
479 full_year.is_negative(),
480 sign_is_mandatory || full_year.get() >= 10_000
481 ));
482 let value: ru32<0, 999_999> =
485 unsafe { full_year.abs().narrow_unchecked::<0, 999_999>().into() };
486
487 bytes += if let Some(value) = value.narrow::<0, 9_999>() {
488 try_likely_ok!(format_four_digits(output, value.into(), padding))
489 } else if let Some(value) = value.narrow::<0, 99_999>() {
490 try_likely_ok!(format_five_digits_pad_zero(output, value))
491 } else {
492 try_likely_ok!(format_six_digits_pad_zero(output, value))
493 };
494 Ok(bytes)
495}
496
497#[inline]
498fn fmt_calendar_year_full_standard_range(
499 output: &mut (impl io::Write + ?Sized),
500 full_year: StandardYear,
501 modifier::CalendarYearFullStandardRange {
502 padding,
503 sign_is_mandatory,
504 }: modifier::CalendarYearFullStandardRange,
505) -> io::Result<usize> {
506 let mut bytes = 0;
507 bytes += try_likely_ok!(fmt_sign(output, full_year.is_negative(), sign_is_mandatory));
508 bytes += try_likely_ok!(format_four_digits(
510 output,
511 unsafe { full_year.abs().narrow_unchecked::<0, 9_999>().into() },
512 padding
513 ));
514 Ok(bytes)
515}
516
517#[inline]
518fn fmt_iso_year_full_extended_range(
519 output: &mut (impl io::Write + ?Sized),
520 full_year: Year,
521 modifier::IsoYearFullExtendedRange {
522 padding,
523 sign_is_mandatory,
524 }: modifier::IsoYearFullExtendedRange,
525) -> io::Result<usize> {
526 let mut bytes = 0;
527 bytes += try_likely_ok!(fmt_sign(
528 output,
529 full_year.is_negative(),
530 sign_is_mandatory || full_year.get() >= 10_000,
531 ));
532 let value: ru32<0, 999_999> =
534 unsafe { full_year.abs().narrow_unchecked::<0, 999_999>().into() };
535
536 bytes += if let Some(value) = value.narrow::<0, 9_999>() {
537 try_likely_ok!(format_four_digits(output, value.into(), padding))
538 } else if let Some(value) = value.narrow::<0, 99_999>() {
539 try_likely_ok!(format_five_digits_pad_zero(output, value))
540 } else {
541 try_likely_ok!(format_six_digits_pad_zero(output, value))
542 };
543 Ok(bytes)
544}
545
546#[inline]
547fn fmt_iso_year_full_standard_range(
548 output: &mut (impl io::Write + ?Sized),
549 year: StandardYear,
550 modifier::IsoYearFullStandardRange {
551 padding,
552 sign_is_mandatory,
553 }: modifier::IsoYearFullStandardRange,
554) -> io::Result<usize> {
555 let mut bytes = 0;
556 bytes += try_likely_ok!(fmt_sign(output, year.is_negative(), sign_is_mandatory));
557 bytes += try_likely_ok!(format_four_digits(
559 output,
560 unsafe { year.abs().narrow_unchecked::<0, 9_999>().into() },
561 padding
562 ));
563 Ok(bytes)
564}
565
566#[inline]
567fn fmt_calendar_year_century_extended_range(
568 output: &mut (impl io::Write + ?Sized),
569 century: ExtendedCentury,
570 is_negative: bool,
571 modifier::CalendarYearCenturyExtendedRange {
572 padding,
573 sign_is_mandatory,
574 }: modifier::CalendarYearCenturyExtendedRange,
575) -> io::Result<usize> {
576 let mut bytes = 0;
577 bytes += try_likely_ok!(fmt_sign(
578 output,
579 is_negative,
580 sign_is_mandatory || century.get() >= 100
581 ));
582 let century: ru16<0, 9_999> = unsafe { century.abs().narrow_unchecked::<0, 9_999>().into() };
584
585 bytes += if let Some(century) = century.narrow::<0, 99>() {
586 try_likely_ok!(format_two_digits(output, century.into(), padding))
587 } else if let Some(century) = century.narrow::<0, 999>() {
588 try_likely_ok!(format_three_digits(output, century, padding))
589 } else {
590 try_likely_ok!(format_four_digits(output, century, padding))
591 };
592 Ok(bytes)
593}
594
595#[inline]
596fn fmt_calendar_year_century_standard_range(
597 output: &mut (impl io::Write + ?Sized),
598 century: StandardCentury,
599 is_negative: bool,
600 modifier::CalendarYearCenturyStandardRange {
601 padding,
602 sign_is_mandatory,
603 }: modifier::CalendarYearCenturyStandardRange,
604) -> io::Result<usize> {
605 let mut bytes = 0;
606 bytes += try_likely_ok!(fmt_sign(output, is_negative, sign_is_mandatory));
607 let century = unsafe { century.abs().narrow_unchecked::<0, 99>() };
609 bytes += try_likely_ok!(format_two_digits(output, century.into(), padding));
610 Ok(bytes)
611}
612
613#[inline]
614fn fmt_iso_year_century_extended_range(
615 output: &mut (impl io::Write + ?Sized),
616 century: ExtendedCentury,
617 is_negative: bool,
618 modifier::IsoYearCenturyExtendedRange {
619 padding,
620 sign_is_mandatory,
621 }: modifier::IsoYearCenturyExtendedRange,
622) -> io::Result<usize> {
623 let mut bytes = 0;
624 bytes += try_likely_ok!(fmt_sign(
625 output,
626 is_negative,
627 sign_is_mandatory || century.get() >= 100,
628 ));
629 let century: ru16<0, 9_999> = unsafe { century.abs().narrow_unchecked::<0, 9_999>().into() };
631
632 bytes += if let Some(century) = century.narrow::<0, 99>() {
633 try_likely_ok!(format_two_digits(output, century.into(), padding))
634 } else if let Some(century) = century.narrow::<0, 999>() {
635 try_likely_ok!(format_three_digits(output, century, padding))
636 } else {
637 try_likely_ok!(format_four_digits(output, century, padding))
638 };
639 Ok(bytes)
640}
641
642#[inline]
643fn fmt_iso_year_century_standard_range(
644 output: &mut (impl io::Write + ?Sized),
645 century: StandardCentury,
646 is_negative: bool,
647 modifier::IsoYearCenturyStandardRange {
648 padding,
649 sign_is_mandatory,
650 }: modifier::IsoYearCenturyStandardRange,
651) -> io::Result<usize> {
652 let mut bytes = 0;
653 bytes += try_likely_ok!(fmt_sign(output, is_negative, sign_is_mandatory));
654 let century = unsafe { century.abs().narrow_unchecked::<0, 99>() };
656 bytes += try_likely_ok!(format_two_digits(output, century.into(), padding));
657 Ok(bytes)
658}
659
660#[inline]
661fn fmt_calendar_year_last_two(
662 output: &mut (impl io::Write + ?Sized),
663 last_two: LastTwo,
664 modifier::CalendarYearLastTwo { padding }: modifier::CalendarYearLastTwo,
665) -> io::Result<usize> {
666 format_two_digits(output, last_two, padding)
667}
668
669#[inline]
670fn fmt_iso_year_last_two(
671 output: &mut (impl io::Write + ?Sized),
672 last_two: LastTwo,
673 modifier::IsoYearLastTwo { padding }: modifier::IsoYearLastTwo,
674) -> io::Result<usize> {
675 format_two_digits(output, last_two, padding)
676}
677
678#[inline]
680fn fmt_hour_12(
681 output: &mut (impl io::Write + ?Sized),
682 hour: Hours,
683 modifier::Hour12 { padding }: modifier::Hour12,
684) -> io::Result<usize> {
685 format_two_digits(
687 output,
688 unsafe { ru8::new_unchecked((hour.get() + 11) % 12 + 1) },
689 padding,
690 )
691}
692
693#[inline]
695fn fmt_hour_24(
696 output: &mut (impl io::Write + ?Sized),
697 hour: Hours,
698 modifier::Hour24 { padding }: modifier::Hour24,
699) -> io::Result<usize> {
700 format_two_digits(output, hour.expand(), padding)
701}
702
703#[inline]
705fn fmt_minute(
706 output: &mut (impl io::Write + ?Sized),
707 minute: Minutes,
708 modifier::Minute { padding }: modifier::Minute,
709) -> Result<usize, io::Error> {
710 format_two_digits(output, minute.expand(), padding)
711}
712
713#[inline]
715fn fmt_period(
716 output: &mut (impl io::Write + ?Sized),
717 period: Period,
718 modifier::Period {
719 is_uppercase,
720 case_sensitive: _, }: modifier::Period,
722) -> Result<usize, io::Error> {
723 write(
724 output,
725 match (period, is_uppercase) {
726 (Period::Am, false) => "am",
727 (Period::Am, true) => "AM",
728 (Period::Pm, false) => "pm",
729 (Period::Pm, true) => "PM",
730 },
731 )
732}
733
734#[inline]
736fn fmt_second(
737 output: &mut (impl io::Write + ?Sized),
738 second: Seconds,
739 modifier::Second { padding }: modifier::Second,
740) -> Result<usize, io::Error> {
741 format_two_digits(output, second.expand(), padding)
742}
743
744#[inline]
746fn fmt_subsecond(
747 output: &mut (impl io::Write + ?Sized),
748 nanos: Nanoseconds,
749 modifier::Subsecond { digits }: modifier::Subsecond,
750) -> Result<usize, io::Error> {
751 use modifier::SubsecondDigits::*;
752
753 #[repr(C, align(8))]
754 #[derive(Clone, Copy)]
755 struct Digits {
756 _padding: MaybeUninit<[u8; 7]>,
757 digit_1: u8,
758 digits_2_thru_9: [u8; 8],
759 }
760
761 let [
762 digit_1,
763 digits_2_and_3,
764 digits_4_and_5,
765 digits_6_and_7,
766 digits_8_and_9,
767 ] = num_fmt::subsecond_from_nanos(nanos);
768
769 let buf = Digits {
772 _padding: MaybeUninit::uninit(),
773 digit_1: digit_1.as_bytes()[0],
774 digits_2_thru_9: [
775 digits_2_and_3.as_bytes()[0],
776 digits_2_and_3.as_bytes()[1],
777 digits_4_and_5.as_bytes()[0],
778 digits_4_and_5.as_bytes()[1],
779 digits_6_and_7.as_bytes()[0],
780 digits_6_and_7.as_bytes()[1],
781 digits_8_and_9.as_bytes()[0],
782 digits_8_and_9.as_bytes()[1],
783 ],
784 };
785
786 let len = match digits {
787 One => 1,
788 Two => 2,
789 Three => 3,
790 Four => 4,
791 Five => 5,
792 Six => 6,
793 Seven => 7,
794 Eight => 8,
795 Nine => 9,
796 OneOrMore => {
797 let bitmask = u64::from_le_bytes(buf.digits_2_thru_9) ^ u64::from_le_bytes([b'0'; 8]);
801 let digits_to_truncate = bitmask.leading_zeros() / 8;
802 9 - digits_to_truncate as usize
803 }
804 };
805
806 let s = unsafe {
810 num_fmt::StackStr::new(
811 *(&raw const buf)
812 .byte_add(core::mem::offset_of!(Digits, digit_1))
813 .cast::<[MaybeUninit<u8>; 9]>(),
814 len,
815 )
816 };
817 write(output, &s)
818}
819
820#[inline]
821fn fmt_sign(
822 output: &mut (impl io::Write + ?Sized),
823 is_negative: bool,
824 sign_is_mandatory: bool,
825) -> Result<usize, io::Error> {
826 if is_negative {
827 write(output, "-")
828 } else if sign_is_mandatory {
829 write(output, "+")
830 } else {
831 Ok(0)
832 }
833}
834
835#[inline]
837fn fmt_offset_hour(
838 output: &mut (impl io::Write + ?Sized),
839 is_negative: bool,
840 hour: OffsetHours,
841 modifier::OffsetHour {
842 padding,
843 sign_is_mandatory,
844 }: modifier::OffsetHour,
845) -> Result<usize, io::Error> {
846 let mut bytes = 0;
847 bytes += try_likely_ok!(fmt_sign(output, is_negative, sign_is_mandatory));
848 bytes += try_likely_ok!(format_two_digits(
850 output,
851 unsafe { ru8::new_unchecked(hour.get().unsigned_abs()) },
852 padding,
853 ));
854 Ok(bytes)
855}
856
857#[inline]
859fn fmt_offset_minute(
860 output: &mut (impl io::Write + ?Sized),
861 offset_minute: OffsetMinutes,
862 modifier::OffsetMinute { padding }: modifier::OffsetMinute,
863) -> Result<usize, io::Error> {
864 format_two_digits(
865 output,
866 unsafe { ru8::new_unchecked(offset_minute.get().unsigned_abs()) },
869 padding,
870 )
871}
872
873#[inline]
875fn fmt_offset_second(
876 output: &mut (impl io::Write + ?Sized),
877 offset_second: OffsetSeconds,
878 modifier::OffsetSecond { padding }: modifier::OffsetSecond,
879) -> Result<usize, io::Error> {
880 format_two_digits(
881 output,
882 unsafe { ru8::new_unchecked(offset_second.get().unsigned_abs()) },
885 padding,
886 )
887}
888
889#[inline]
891fn fmt_unix_timestamp_second(
892 output: &mut (impl io::Write + ?Sized),
893 timestamp: i64,
894 modifier::UnixTimestampSecond { sign_is_mandatory }: modifier::UnixTimestampSecond,
895) -> Result<usize, io::Error> {
896 let mut bytes = 0;
897 bytes += try_likely_ok!(fmt_sign(output, timestamp < 0, sign_is_mandatory));
898 bytes += try_likely_ok!(format_u64_pad_none(output, timestamp.unsigned_abs()));
899 Ok(bytes)
900}
901
902#[inline]
904fn fmt_unix_timestamp_millisecond(
905 output: &mut (impl io::Write + ?Sized),
906 timestamp_millis: i64,
907 modifier::UnixTimestampMillisecond { sign_is_mandatory }: modifier::UnixTimestampMillisecond,
908) -> Result<usize, io::Error> {
909 let mut bytes = 0;
910 bytes += try_likely_ok!(fmt_sign(output, timestamp_millis < 0, sign_is_mandatory));
911 bytes += try_likely_ok!(format_u64_pad_none(output, timestamp_millis.unsigned_abs()));
912 Ok(bytes)
913}
914
915#[inline]
917fn fmt_unix_timestamp_microsecond(
918 output: &mut (impl io::Write + ?Sized),
919 timestamp_micros: i128,
920 modifier::UnixTimestampMicrosecond { sign_is_mandatory }: modifier::UnixTimestampMicrosecond,
921) -> Result<usize, io::Error> {
922 let mut bytes = 0;
923 bytes += try_likely_ok!(fmt_sign(output, timestamp_micros < 0, sign_is_mandatory));
924 bytes += try_likely_ok!(format_u128_pad_none(
925 output,
926 timestamp_micros.unsigned_abs()
927 ));
928 Ok(bytes)
929}
930
931#[inline]
933fn fmt_unix_timestamp_nanosecond(
934 output: &mut (impl io::Write + ?Sized),
935 timestamp_nanos: i128,
936 modifier::UnixTimestampNanosecond { sign_is_mandatory }: modifier::UnixTimestampNanosecond,
937) -> Result<usize, io::Error> {
938 let mut bytes = 0;
939 bytes += try_likely_ok!(fmt_sign(output, timestamp_nanos < 0, sign_is_mandatory));
940 bytes += try_likely_ok!(format_u128_pad_none(output, timestamp_nanos.unsigned_abs()));
941 Ok(bytes)
942}