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, format_description_v3, 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().extend()),
131 }
132}
133
134#[inline]
139pub(crate) fn format_float(
140 output: &mut (impl io::Write + ?Sized),
141 mut value: f64,
142 digits_before_decimal: u8,
143 digits_after_decimal: Option<NonZero<u8>>,
144) -> io::Result<usize> {
145 match digits_after_decimal {
146 Some(digits_after_decimal) => {
147 if digits_after_decimal.get() < 9 {
160 let trunc_num = f64_10_pow_x(digits_after_decimal);
161 value = f64::trunc(value * trunc_num) / trunc_num;
162 }
163
164 let digits_after_decimal = digits_after_decimal.get().extend();
165 let width = digits_before_decimal.extend::<usize>() + 1 + digits_after_decimal;
166 try_likely_ok!(write!(output, "{value:0>width$.digits_after_decimal$}"));
167 Ok(width)
168 }
169 None => {
170 let value = value.trunc() as u64;
171 let width = digits_before_decimal.extend();
172 try_likely_ok!(write!(output, "{value:0>width$}"));
173 Ok(width)
174 }
175 }
176}
177
178#[inline]
180pub(crate) fn format_single_digit(
181 output: &mut (impl io::Write + ?Sized),
182 value: ru8<0, 9>,
183) -> io::Result<usize> {
184 write(output, num_fmt::single_digit(value))
185}
186
187#[inline]
189pub(crate) fn format_two_digits(
190 output: &mut (impl io::Write + ?Sized),
191 value: ru8<0, 99>,
192 padding: modifier::Padding,
193) -> io::Result<usize> {
194 let s = match padding {
195 modifier::Padding::Space => num_fmt::two_digits_space_padded(value),
196 modifier::Padding::Zero => num_fmt::two_digits_zero_padded(value),
197 modifier::Padding::None => num_fmt::one_to_two_digits_no_padding(value),
198 };
199 write(output, s)
200}
201
202#[inline]
204pub(crate) fn format_three_digits(
205 output: &mut (impl io::Write + ?Sized),
206 value: ru16<0, 999>,
207 padding: modifier::Padding,
208) -> io::Result<usize> {
209 let [first, second_and_third] = match padding {
210 modifier::Padding::Space => num_fmt::three_digits_space_padded(value),
211 modifier::Padding::Zero => num_fmt::three_digits_zero_padded(value),
212 modifier::Padding::None => num_fmt::one_to_three_digits_no_padding(value),
213 };
214 write_many(output, [first, second_and_third])
215}
216
217#[inline]
219pub(crate) fn format_four_digits(
220 output: &mut (impl io::Write + ?Sized),
221 value: ru16<0, 9_999>,
222 padding: modifier::Padding,
223) -> io::Result<usize> {
224 let [first_and_second, third_and_fourth] = match padding {
225 modifier::Padding::Space => num_fmt::four_digits_space_padded(value),
226 modifier::Padding::Zero => num_fmt::four_digits_zero_padded(value),
227 modifier::Padding::None => num_fmt::one_to_four_digits_no_padding(value),
228 };
229 write_many(output, [first_and_second, third_and_fourth])
230}
231
232#[inline]
234pub(crate) fn format_four_digits_pad_zero(
235 output: &mut (impl io::Write + ?Sized),
236 value: ru16<0, 9_999>,
237) -> io::Result<usize> {
238 write_many(output, num_fmt::four_digits_zero_padded(value))
239}
240
241#[inline]
243pub(crate) fn format_five_digits_pad_zero(
244 output: &mut (impl io::Write + ?Sized),
245 value: ru32<0, 99_999>,
246) -> io::Result<usize> {
247 write_many(output, num_fmt::five_digits_zero_padded(value))
248}
249
250#[inline]
252pub(crate) fn format_six_digits_pad_zero(
253 output: &mut (impl io::Write + ?Sized),
254 value: ru32<0, 999_999>,
255) -> io::Result<usize> {
256 write_many(output, num_fmt::six_digits_zero_padded(value))
257}
258
259#[inline]
263pub(crate) fn format_number_pad_none(
264 output: &mut (impl io::Write + ?Sized),
265 value: impl itoa::Integer + Copy,
266) -> Result<usize, io::Error> {
267 write(output, itoa::Buffer::new().format(value))
268}
269
270#[inline]
274fn fmt_component_v3<V>(
275 output: &mut (impl io::Write + ?Sized),
276 value: &V,
277 state: &mut <V as ComponentProvider>::State,
278 component: &format_description_v3::Component,
279) -> Result<usize, error::Format>
280where
281 V: ComponentProvider,
282{
283 use format_description_v3::Component::*;
284
285 use crate::formatting::*;
286
287 match component {
288 Day(modifier) if V::SUPPLIES_DATE => fmt_day(output, value.day(state), *modifier),
289 MonthShort(modifier) if V::SUPPLIES_DATE => {
290 fmt_month_short(output, value.month(state), *modifier)
291 }
292 MonthLong(modifier) if V::SUPPLIES_DATE => {
293 fmt_month_long(output, value.month(state), *modifier)
294 }
295 MonthNumerical(modifier) if V::SUPPLIES_DATE => {
296 fmt_month_numerical(output, value.month(state), *modifier)
297 }
298 Ordinal(modifier) if V::SUPPLIES_DATE => {
299 fmt_ordinal(output, value.ordinal(state), *modifier)
300 }
301 WeekdayShort(modifier) if V::SUPPLIES_DATE => {
302 fmt_weekday_short(output, value.weekday(state), *modifier)
303 }
304 WeekdayLong(modifier) if V::SUPPLIES_DATE => {
305 fmt_weekday_long(output, value.weekday(state), *modifier)
306 }
307 WeekdaySunday(modifier) if V::SUPPLIES_DATE => {
308 fmt_weekday_sunday(output, value.weekday(state), *modifier)
309 }
310 WeekdayMonday(modifier) if V::SUPPLIES_DATE => {
311 fmt_weekday_monday(output, value.weekday(state), *modifier)
312 }
313 WeekNumberIso(modifier) if V::SUPPLIES_DATE => {
314 fmt_week_number_iso(output, value.iso_week_number(state), *modifier)
315 }
316 WeekNumberSunday(modifier) if V::SUPPLIES_DATE => {
317 fmt_week_number_sunday(output, value.sunday_based_week(state), *modifier)
318 }
319 WeekNumberMonday(modifier) if V::SUPPLIES_DATE => {
320 fmt_week_number_monday(output, value.monday_based_week(state), *modifier)
321 }
322 CalendarYearFullExtendedRange(modifier) if V::SUPPLIES_DATE => {
323 fmt_calendar_year_full_extended_range(output, value.calendar_year(state), *modifier)
324 }
325 CalendarYearFullStandardRange(modifier) if V::SUPPLIES_DATE => {
326 fmt_calendar_year_full_standard_range(
327 output,
328 try_likely_ok!(
329 value
330 .calendar_year(state)
331 .narrow::<-9_999, 9_999>()
332 .ok_or_else(|| error::ComponentRange::conditional("year"))
333 )
334 .into(),
335 *modifier,
336 )
337 }
338 IsoYearFullExtendedRange(modifier) if V::SUPPLIES_DATE => {
339 fmt_iso_year_full_extended_range(output, value.iso_year(state), *modifier)
340 }
341 IsoYearFullStandardRange(modifier) if V::SUPPLIES_DATE => fmt_iso_year_full_standard_range(
342 output,
343 try_likely_ok!(
344 value
345 .iso_year(state)
346 .narrow::<-9_999, 9_999>()
347 .ok_or_else(|| error::ComponentRange::conditional("year"))
348 )
349 .into(),
350 *modifier,
351 ),
352 CalendarYearCenturyExtendedRange(modifier) if V::SUPPLIES_DATE => {
353 let year = value.calendar_year(state);
354 let century = unsafe { ri16::new_unchecked((year.get() / 100).truncate()) };
357 fmt_calendar_year_century_extended_range(output, century, year.is_negative(), *modifier)
358 }
359 CalendarYearCenturyStandardRange(modifier) if V::SUPPLIES_DATE => {
360 let year = value.calendar_year(state);
361 let is_negative = year.is_negative();
362 let year = unsafe { ri16::<0, 9_999>::new_unchecked((year.get() / 100).truncate()) };
365 fmt_calendar_year_century_standard_range(
366 output,
367 year.narrow::<0, 99>()
368 .ok_or_else(|| error::ComponentRange::conditional("year"))?
369 .into(),
370 is_negative,
371 *modifier,
372 )
373 }
374 IsoYearCenturyExtendedRange(modifier) if V::SUPPLIES_DATE => {
375 let year = value.iso_year(state);
376 let century = unsafe { ri16::new_unchecked((year.get() / 100).truncate()) };
379 fmt_iso_year_century_extended_range(output, century, year.is_negative(), *modifier)
380 }
381 IsoYearCenturyStandardRange(modifier) if V::SUPPLIES_DATE => {
382 let year = value.iso_year(state);
383 let year = unsafe { ri16::<0, 9_999>::new_unchecked((year.get() / 100).truncate()) };
386 fmt_iso_year_century_standard_range(
387 output,
388 year.narrow::<0, 99>()
389 .ok_or_else(|| error::ComponentRange::conditional("year"))?
390 .into(),
391 year.is_negative(),
392 *modifier,
393 )
394 }
395 CalendarYearLastTwo(modifier) if V::SUPPLIES_DATE => {
396 let last_two = unsafe {
399 ru8::new_unchecked(
400 (value.calendar_year(state).get().unsigned_abs() % 100).truncate(),
401 )
402 };
403 fmt_calendar_year_last_two(output, last_two, *modifier)
404 }
405 IsoYearLastTwo(modifier) if V::SUPPLIES_DATE => {
406 let last_two = unsafe {
409 ru8::new_unchecked((value.iso_year(state).get().unsigned_abs() % 100).truncate())
410 };
411 fmt_iso_year_last_two(output, last_two, *modifier)
412 }
413 Hour12(modifier) if V::SUPPLIES_TIME => fmt_hour_12(output, value.hour(state), *modifier),
414 Hour24(modifier) if V::SUPPLIES_TIME => fmt_hour_24(output, value.hour(state), *modifier),
415 Minute(modifier) if V::SUPPLIES_TIME => fmt_minute(output, value.minute(state), *modifier),
416 Period(modifier) if V::SUPPLIES_TIME => fmt_period(output, value.period(state), *modifier),
417 Second(modifier) if V::SUPPLIES_TIME => fmt_second(output, value.second(state), *modifier),
418 Subsecond(modifier) if V::SUPPLIES_TIME => {
419 fmt_subsecond(output, value.nanosecond(state), *modifier)
420 }
421 OffsetHour(modifier) if V::SUPPLIES_OFFSET => fmt_offset_hour(
422 output,
423 value.offset_is_negative(state),
424 value.offset_hour(state),
425 *modifier,
426 ),
427 OffsetMinute(modifier) if V::SUPPLIES_OFFSET => {
428 fmt_offset_minute(output, value.offset_minute(state), *modifier)
429 }
430 OffsetSecond(modifier) if V::SUPPLIES_OFFSET => {
431 fmt_offset_second(output, value.offset_second(state), *modifier)
432 }
433 Ignore(_) => return Ok(0),
434 UnixTimestampSecond(modifier) if V::SUPPLIES_TIMESTAMP => {
435 fmt_unix_timestamp_second(output, value.unix_timestamp_seconds(state), *modifier)
436 }
437 UnixTimestampMillisecond(modifier) if V::SUPPLIES_TIMESTAMP => {
438 fmt_unix_timestamp_millisecond(
439 output,
440 value.unix_timestamp_milliseconds(state),
441 *modifier,
442 )
443 }
444 UnixTimestampMicrosecond(modifier) if V::SUPPLIES_TIMESTAMP => {
445 fmt_unix_timestamp_microsecond(
446 output,
447 value.unix_timestamp_microseconds(state),
448 *modifier,
449 )
450 }
451 UnixTimestampNanosecond(modifier) if V::SUPPLIES_TIMESTAMP => {
452 fmt_unix_timestamp_nanosecond(
453 output,
454 value.unix_timestamp_nanoseconds(state),
455 *modifier,
456 )
457 }
458 End(modifier::End { trailing_input: _ }) => return Ok(0),
459
460 #[allow(unreachable_patterns)]
465 Day(_)
466 | MonthShort(_)
467 | MonthLong(_)
468 | MonthNumerical(_)
469 | Ordinal(_)
470 | WeekdayShort(_)
471 | WeekdayLong(_)
472 | WeekdaySunday(_)
473 | WeekdayMonday(_)
474 | WeekNumberIso(_)
475 | WeekNumberSunday(_)
476 | WeekNumberMonday(_)
477 | CalendarYearFullExtendedRange(_)
478 | CalendarYearFullStandardRange(_)
479 | IsoYearFullExtendedRange(_)
480 | IsoYearFullStandardRange(_)
481 | CalendarYearCenturyExtendedRange(_)
482 | CalendarYearCenturyStandardRange(_)
483 | IsoYearCenturyExtendedRange(_)
484 | IsoYearCenturyStandardRange(_)
485 | CalendarYearLastTwo(_)
486 | IsoYearLastTwo(_)
487 | Hour12(_)
488 | Hour24(_)
489 | Minute(_)
490 | Period(_)
491 | Second(_)
492 | Subsecond(_)
493 | OffsetHour(_)
494 | OffsetMinute(_)
495 | OffsetSecond(_)
496 | Ignore(_)
497 | UnixTimestampSecond(_)
498 | UnixTimestampMillisecond(_)
499 | UnixTimestampMicrosecond(_)
500 | UnixTimestampNanosecond(_)
501 | End(_) => return Err(error::Format::InsufficientTypeInformation),
502 }
503 .map_err(Into::into)
504}
505
506#[inline]
508fn fmt_day(
509 output: &mut (impl io::Write + ?Sized),
510 day: Day,
511 modifier::Day { padding }: modifier::Day,
512) -> Result<usize, io::Error> {
513 format_two_digits(output, day.expand(), padding)
514}
515
516#[inline]
518fn fmt_month_short(
519 output: &mut (impl io::Write + ?Sized),
520 month: Month,
521 modifier::MonthShort {
522 case_sensitive: _, }: modifier::MonthShort,
524) -> io::Result<usize> {
525 write(output, unsafe {
527 MONTH_NAMES[u8::from(month).extend::<usize>() - 1].get_unchecked(..3)
528 })
529}
530
531#[inline]
533fn fmt_month_long(
534 output: &mut (impl io::Write + ?Sized),
535 month: Month,
536 modifier::MonthLong {
537 case_sensitive: _, }: modifier::MonthLong,
539) -> io::Result<usize> {
540 write(output, MONTH_NAMES[u8::from(month).extend::<usize>() - 1])
541}
542
543#[inline]
545fn fmt_month_numerical(
546 output: &mut (impl io::Write + ?Sized),
547 month: Month,
548 modifier::MonthNumerical { padding }: modifier::MonthNumerical,
549) -> io::Result<usize> {
550 format_two_digits(
551 output,
552 unsafe { ru8::new_unchecked(u8::from(month)) },
554 padding,
555 )
556}
557
558#[inline]
560fn fmt_ordinal(
561 output: &mut (impl io::Write + ?Sized),
562 ordinal: Ordinal,
563 modifier::Ordinal { padding }: modifier::Ordinal,
564) -> Result<usize, io::Error> {
565 format_three_digits(output, ordinal.expand(), padding)
566}
567
568#[inline]
570fn fmt_weekday_short(
571 output: &mut (impl io::Write + ?Sized),
572 weekday: Weekday,
573 modifier::WeekdayShort {
574 case_sensitive: _, }: modifier::WeekdayShort,
576) -> io::Result<usize> {
577 write(output, unsafe {
579 WEEKDAY_NAMES[weekday.number_days_from_monday().extend::<usize>()].get_unchecked(..3)
580 })
581}
582
583#[inline]
585fn fmt_weekday_long(
586 output: &mut (impl io::Write + ?Sized),
587 weekday: Weekday,
588 modifier::WeekdayLong {
589 case_sensitive: _, }: modifier::WeekdayLong,
591) -> io::Result<usize> {
592 write(
593 output,
594 WEEKDAY_NAMES[weekday.number_days_from_monday().extend::<usize>()],
595 )
596}
597
598#[inline]
601fn fmt_weekday_sunday(
602 output: &mut (impl io::Write + ?Sized),
603 weekday: Weekday,
604 modifier::WeekdaySunday { one_indexed }: modifier::WeekdaySunday,
605) -> io::Result<usize> {
606 format_single_digit(output, unsafe {
608 ru8::new_unchecked(weekday.number_days_from_sunday() + u8::from(one_indexed))
609 })
610}
611
612#[inline]
615fn fmt_weekday_monday(
616 output: &mut (impl io::Write + ?Sized),
617 weekday: Weekday,
618 modifier::WeekdayMonday { one_indexed }: modifier::WeekdayMonday,
619) -> io::Result<usize> {
620 format_single_digit(output, unsafe {
622 ru8::new_unchecked(weekday.number_days_from_monday() + u8::from(one_indexed))
623 })
624}
625
626#[inline]
627fn fmt_week_number_iso(
628 output: &mut (impl io::Write + ?Sized),
629 week_number: IsoWeekNumber,
630 modifier::WeekNumberIso { padding }: modifier::WeekNumberIso,
631) -> io::Result<usize> {
632 format_two_digits(output, week_number.expand(), padding)
633}
634
635#[inline]
636fn fmt_week_number_sunday(
637 output: &mut (impl io::Write + ?Sized),
638 week_number: SundayBasedWeek,
639 modifier::WeekNumberSunday { padding }: modifier::WeekNumberSunday,
640) -> io::Result<usize> {
641 format_two_digits(output, week_number.expand(), padding)
642}
643
644#[inline]
645fn fmt_week_number_monday(
646 output: &mut (impl io::Write + ?Sized),
647 week_number: MondayBasedWeek,
648 modifier::WeekNumberMonday { padding }: modifier::WeekNumberMonday,
649) -> io::Result<usize> {
650 format_two_digits(output, week_number.expand(), padding)
651}
652
653#[inline]
654fn fmt_calendar_year_full_extended_range(
655 output: &mut (impl io::Write + ?Sized),
656 full_year: Year,
657 modifier::CalendarYearFullExtendedRange {
658 padding,
659 sign_is_mandatory,
660 }: modifier::CalendarYearFullExtendedRange,
661) -> io::Result<usize> {
662 let mut bytes = 0;
663 bytes += try_likely_ok!(fmt_sign(
664 output,
665 full_year.is_negative(),
666 sign_is_mandatory || full_year.get() >= 10_000,
667 ));
668 let value: ru32<0, 999_999> =
671 unsafe { full_year.abs().narrow_unchecked::<0, 999_999>().into() };
672
673 bytes += if let Some(value) = value.narrow::<0, 9_999>() {
674 try_likely_ok!(format_four_digits(output, value.into(), padding))
675 } else if let Some(value) = value.narrow::<0, 99_999>() {
676 try_likely_ok!(format_five_digits_pad_zero(output, value))
677 } else {
678 try_likely_ok!(format_six_digits_pad_zero(output, value))
679 };
680 Ok(bytes)
681}
682
683#[inline]
684fn fmt_calendar_year_full_standard_range(
685 output: &mut (impl io::Write + ?Sized),
686 full_year: StandardYear,
687 modifier::CalendarYearFullStandardRange {
688 padding,
689 sign_is_mandatory,
690 }: modifier::CalendarYearFullStandardRange,
691) -> io::Result<usize> {
692 let mut bytes = 0;
693 bytes += try_likely_ok!(fmt_sign(output, full_year.is_negative(), sign_is_mandatory));
694 bytes += try_likely_ok!(format_four_digits(
696 output,
697 unsafe { full_year.abs().narrow_unchecked::<0, 9_999>().into() },
698 padding
699 ));
700 Ok(bytes)
701}
702
703#[inline]
704fn fmt_iso_year_full_extended_range(
705 output: &mut (impl io::Write + ?Sized),
706 full_year: Year,
707 modifier::IsoYearFullExtendedRange {
708 padding,
709 sign_is_mandatory,
710 }: modifier::IsoYearFullExtendedRange,
711) -> io::Result<usize> {
712 let mut bytes = 0;
713 bytes += try_likely_ok!(fmt_sign(
714 output,
715 full_year.is_negative(),
716 sign_is_mandatory || full_year.get() >= 10_000,
717 ));
718 let value: ru32<0, 999_999> =
720 unsafe { full_year.abs().narrow_unchecked::<0, 999_999>().into() };
721
722 bytes += if let Some(value) = value.narrow::<0, 9_999>() {
723 try_likely_ok!(format_four_digits(output, value.into(), padding))
724 } else if let Some(value) = value.narrow::<0, 99_999>() {
725 try_likely_ok!(format_five_digits_pad_zero(output, value))
726 } else {
727 try_likely_ok!(format_six_digits_pad_zero(output, value))
728 };
729 Ok(bytes)
730}
731
732#[inline]
733fn fmt_iso_year_full_standard_range(
734 output: &mut (impl io::Write + ?Sized),
735 year: StandardYear,
736 modifier::IsoYearFullStandardRange {
737 padding,
738 sign_is_mandatory,
739 }: modifier::IsoYearFullStandardRange,
740) -> io::Result<usize> {
741 let mut bytes = 0;
742 bytes += try_likely_ok!(fmt_sign(output, year.is_negative(), sign_is_mandatory));
743 bytes += try_likely_ok!(format_four_digits(
745 output,
746 unsafe { year.abs().narrow_unchecked::<0, 9_999>().into() },
747 padding
748 ));
749 Ok(bytes)
750}
751
752#[inline]
753fn fmt_calendar_year_century_extended_range(
754 output: &mut (impl io::Write + ?Sized),
755 century: ExtendedCentury,
756 is_negative: bool,
757 modifier::CalendarYearCenturyExtendedRange {
758 padding,
759 sign_is_mandatory,
760 }: modifier::CalendarYearCenturyExtendedRange,
761) -> io::Result<usize> {
762 let mut bytes = 0;
763 bytes += try_likely_ok!(fmt_sign(
764 output,
765 is_negative,
766 sign_is_mandatory || century.get() >= 100,
767 ));
768 let century: ru16<0, 9_999> = unsafe { century.abs().narrow_unchecked::<0, 9_999>().into() };
770
771 bytes += if let Some(century) = century.narrow::<0, 99>() {
772 try_likely_ok!(format_two_digits(output, century.into(), padding))
773 } else if let Some(century) = century.narrow::<0, 999>() {
774 try_likely_ok!(format_three_digits(output, century, padding))
775 } else {
776 try_likely_ok!(format_four_digits(output, century, padding))
777 };
778 Ok(bytes)
779}
780
781#[inline]
782fn fmt_calendar_year_century_standard_range(
783 output: &mut (impl io::Write + ?Sized),
784 century: StandardCentury,
785 is_negative: bool,
786 modifier::CalendarYearCenturyStandardRange {
787 padding,
788 sign_is_mandatory,
789 }: modifier::CalendarYearCenturyStandardRange,
790) -> io::Result<usize> {
791 let mut bytes = 0;
792 bytes += try_likely_ok!(fmt_sign(output, is_negative, sign_is_mandatory));
793 let century = unsafe { century.abs().narrow_unchecked::<0, 99>() };
795 bytes += try_likely_ok!(format_two_digits(output, century.into(), padding));
796 Ok(bytes)
797}
798
799#[inline]
800fn fmt_iso_year_century_extended_range(
801 output: &mut (impl io::Write + ?Sized),
802 century: ExtendedCentury,
803 is_negative: bool,
804 modifier::IsoYearCenturyExtendedRange {
805 padding,
806 sign_is_mandatory,
807 }: modifier::IsoYearCenturyExtendedRange,
808) -> io::Result<usize> {
809 let mut bytes = 0;
810 bytes += try_likely_ok!(fmt_sign(
811 output,
812 is_negative,
813 sign_is_mandatory || century.get() >= 100,
814 ));
815 let century: ru16<0, 9_999> = unsafe { century.abs().narrow_unchecked::<0, 9_999>().into() };
817
818 bytes += if let Some(century) = century.narrow::<0, 99>() {
819 try_likely_ok!(format_two_digits(output, century.into(), padding))
820 } else if let Some(century) = century.narrow::<0, 999>() {
821 try_likely_ok!(format_three_digits(output, century, padding))
822 } else {
823 try_likely_ok!(format_four_digits(output, century, padding))
824 };
825 Ok(bytes)
826}
827
828#[inline]
829fn fmt_iso_year_century_standard_range(
830 output: &mut (impl io::Write + ?Sized),
831 century: StandardCentury,
832 is_negative: bool,
833 modifier::IsoYearCenturyStandardRange {
834 padding,
835 sign_is_mandatory,
836 }: modifier::IsoYearCenturyStandardRange,
837) -> io::Result<usize> {
838 let mut bytes = 0;
839 bytes += try_likely_ok!(fmt_sign(output, is_negative, sign_is_mandatory));
840 let century = unsafe { century.abs().narrow_unchecked::<0, 99>() };
842 bytes += try_likely_ok!(format_two_digits(output, century.into(), padding));
843 Ok(bytes)
844}
845
846#[inline]
847fn fmt_calendar_year_last_two(
848 output: &mut (impl io::Write + ?Sized),
849 last_two: LastTwo,
850 modifier::CalendarYearLastTwo { padding }: modifier::CalendarYearLastTwo,
851) -> io::Result<usize> {
852 format_two_digits(output, last_two, padding)
853}
854
855#[inline]
856fn fmt_iso_year_last_two(
857 output: &mut (impl io::Write + ?Sized),
858 last_two: LastTwo,
859 modifier::IsoYearLastTwo { padding }: modifier::IsoYearLastTwo,
860) -> io::Result<usize> {
861 format_two_digits(output, last_two, padding)
862}
863
864#[inline]
866fn fmt_hour_12(
867 output: &mut (impl io::Write + ?Sized),
868 hour: Hours,
869 modifier::Hour12 { padding }: modifier::Hour12,
870) -> io::Result<usize> {
871 format_two_digits(
873 output,
874 unsafe { ru8::new_unchecked((hour.get() + 11) % 12 + 1) },
875 padding,
876 )
877}
878
879#[inline]
881fn fmt_hour_24(
882 output: &mut (impl io::Write + ?Sized),
883 hour: Hours,
884 modifier::Hour24 { padding }: modifier::Hour24,
885) -> io::Result<usize> {
886 format_two_digits(output, hour.expand(), padding)
887}
888
889#[inline]
891fn fmt_minute(
892 output: &mut (impl io::Write + ?Sized),
893 minute: Minutes,
894 modifier::Minute { padding }: modifier::Minute,
895) -> Result<usize, io::Error> {
896 format_two_digits(output, minute.expand(), padding)
897}
898
899#[inline]
901fn fmt_period(
902 output: &mut (impl io::Write + ?Sized),
903 period: Period,
904 modifier::Period {
905 is_uppercase,
906 case_sensitive: _, }: modifier::Period,
908) -> Result<usize, io::Error> {
909 write(
910 output,
911 match (period, is_uppercase) {
912 (Period::Am, false) => "am",
913 (Period::Am, true) => "AM",
914 (Period::Pm, false) => "pm",
915 (Period::Pm, true) => "PM",
916 },
917 )
918}
919
920#[inline]
922fn fmt_second(
923 output: &mut (impl io::Write + ?Sized),
924 second: Seconds,
925 modifier::Second { padding }: modifier::Second,
926) -> Result<usize, io::Error> {
927 format_two_digits(output, second.expand(), padding)
928}
929
930#[inline]
932fn fmt_subsecond(
933 output: &mut (impl io::Write + ?Sized),
934 nanos: Nanoseconds,
935 modifier::Subsecond { digits }: modifier::Subsecond,
936) -> Result<usize, io::Error> {
937 use modifier::SubsecondDigits::*;
938
939 #[repr(C, align(8))]
940 #[derive(Clone, Copy)]
941 struct Digits {
942 _padding: MaybeUninit<[u8; 7]>,
943 digit_1: u8,
944 digits_2_thru_9: [u8; 8],
945 }
946
947 let [
948 digit_1,
949 digits_2_and_3,
950 digits_4_and_5,
951 digits_6_and_7,
952 digits_8_and_9,
953 ] = num_fmt::subsecond_from_nanos(nanos);
954
955 let buf = Digits {
958 _padding: MaybeUninit::uninit(),
959 digit_1: digit_1.as_bytes()[0],
960 digits_2_thru_9: [
961 digits_2_and_3.as_bytes()[0],
962 digits_2_and_3.as_bytes()[1],
963 digits_4_and_5.as_bytes()[0],
964 digits_4_and_5.as_bytes()[1],
965 digits_6_and_7.as_bytes()[0],
966 digits_6_and_7.as_bytes()[1],
967 digits_8_and_9.as_bytes()[0],
968 digits_8_and_9.as_bytes()[1],
969 ],
970 };
971
972 let len = match digits {
973 One => 1,
974 Two => 2,
975 Three => 3,
976 Four => 4,
977 Five => 5,
978 Six => 6,
979 Seven => 7,
980 Eight => 8,
981 Nine => 9,
982 OneOrMore => {
983 let bitmask = u64::from_le_bytes(buf.digits_2_thru_9) ^ u64::from_le_bytes([b'0'; 8]);
987 let digits_to_truncate = bitmask.leading_zeros() / 8;
988 9 - digits_to_truncate as usize
989 }
990 };
991
992 let s = unsafe {
996 num_fmt::StackStr::new(
997 *(&raw const buf)
998 .byte_add(core::mem::offset_of!(Digits, digit_1))
999 .cast::<[MaybeUninit<u8>; 9]>(),
1000 len,
1001 )
1002 };
1003 write(output, &s)
1004}
1005
1006#[inline]
1007fn fmt_sign(
1008 output: &mut (impl io::Write + ?Sized),
1009 is_negative: bool,
1010 sign_is_mandatory: bool,
1011) -> Result<usize, io::Error> {
1012 if is_negative {
1013 write(output, "-")
1014 } else if sign_is_mandatory {
1015 write(output, "+")
1016 } else {
1017 Ok(0)
1018 }
1019}
1020
1021#[inline]
1023fn fmt_offset_hour(
1024 output: &mut (impl io::Write + ?Sized),
1025 is_negative: bool,
1026 hour: OffsetHours,
1027 modifier::OffsetHour {
1028 padding,
1029 sign_is_mandatory,
1030 }: modifier::OffsetHour,
1031) -> Result<usize, io::Error> {
1032 let mut bytes = 0;
1033 bytes += try_likely_ok!(fmt_sign(output, is_negative, sign_is_mandatory));
1034 bytes += try_likely_ok!(format_two_digits(
1036 output,
1037 unsafe { ru8::new_unchecked(hour.get().unsigned_abs()) },
1038 padding,
1039 ));
1040 Ok(bytes)
1041}
1042
1043#[inline]
1045fn fmt_offset_minute(
1046 output: &mut (impl io::Write + ?Sized),
1047 offset_minute: OffsetMinutes,
1048 modifier::OffsetMinute { padding }: modifier::OffsetMinute,
1049) -> Result<usize, io::Error> {
1050 format_two_digits(
1051 output,
1052 unsafe { ru8::new_unchecked(offset_minute.get().unsigned_abs()) },
1055 padding,
1056 )
1057}
1058
1059#[inline]
1061fn fmt_offset_second(
1062 output: &mut (impl io::Write + ?Sized),
1063 offset_second: OffsetSeconds,
1064 modifier::OffsetSecond { padding }: modifier::OffsetSecond,
1065) -> Result<usize, io::Error> {
1066 format_two_digits(
1067 output,
1068 unsafe { ru8::new_unchecked(offset_second.get().unsigned_abs()) },
1071 padding,
1072 )
1073}
1074
1075#[inline]
1077fn fmt_unix_timestamp_second(
1078 output: &mut (impl io::Write + ?Sized),
1079 timestamp: i64,
1080 modifier::UnixTimestampSecond { sign_is_mandatory }: modifier::UnixTimestampSecond,
1081) -> Result<usize, io::Error> {
1082 let mut bytes = 0;
1083 bytes += try_likely_ok!(fmt_sign(output, timestamp < 0, sign_is_mandatory));
1084 bytes += try_likely_ok!(format_number_pad_none(output, timestamp.unsigned_abs()));
1085 Ok(bytes)
1086}
1087
1088#[inline]
1090fn fmt_unix_timestamp_millisecond(
1091 output: &mut (impl io::Write + ?Sized),
1092 timestamp_millis: i64,
1093 modifier::UnixTimestampMillisecond { sign_is_mandatory }: modifier::UnixTimestampMillisecond,
1094) -> Result<usize, io::Error> {
1095 let mut bytes = 0;
1096 bytes += try_likely_ok!(fmt_sign(output, timestamp_millis < 0, sign_is_mandatory));
1097 bytes += try_likely_ok!(format_number_pad_none(
1098 output,
1099 timestamp_millis.unsigned_abs()
1100 ));
1101 Ok(bytes)
1102}
1103
1104#[inline]
1106fn fmt_unix_timestamp_microsecond(
1107 output: &mut (impl io::Write + ?Sized),
1108 timestamp_micros: i128,
1109 modifier::UnixTimestampMicrosecond { sign_is_mandatory }: modifier::UnixTimestampMicrosecond,
1110) -> Result<usize, io::Error> {
1111 let mut bytes = 0;
1112 bytes += try_likely_ok!(fmt_sign(output, timestamp_micros < 0, sign_is_mandatory));
1113 bytes += try_likely_ok!(format_number_pad_none(
1114 output,
1115 timestamp_micros.unsigned_abs()
1116 ));
1117 Ok(bytes)
1118}
1119
1120#[inline]
1122fn fmt_unix_timestamp_nanosecond(
1123 output: &mut (impl io::Write + ?Sized),
1124 timestamp_nanos: i128,
1125 modifier::UnixTimestampNanosecond { sign_is_mandatory }: modifier::UnixTimestampNanosecond,
1126) -> Result<usize, io::Error> {
1127 let mut bytes = 0;
1128 bytes += try_likely_ok!(fmt_sign(output, timestamp_nanos < 0, sign_is_mandatory));
1129 bytes += try_likely_ok!(format_number_pad_none(
1130 output,
1131 timestamp_nanos.unsigned_abs()
1132 ));
1133 Ok(bytes)
1134}