1use alloc::string::String;
4use alloc::vec::Vec;
5use core::ops::Deref;
6use std::io;
7
8use deranged::{ru8, ru16};
9use num_conv::prelude::*;
10
11use crate::format_description::format_description_v3::FormatDescriptionV3Inner;
12use crate::format_description::modifier::Padding;
13use crate::format_description::well_known::iso8601::EncodedConfig;
14use crate::format_description::well_known::{Iso8601, Rfc2822, Rfc3339};
15use crate::format_description::{
16 BorrowedFormatItem, Component, FormatDescriptionV3, OwnedFormatItem,
17};
18use crate::formatting::{ComponentProvider, MONTH_NAMES, Output, WEEKDAY_NAMES};
19use crate::internal_macros::try_likely_ok;
20use crate::{PrivateMethod, error, num_fmt};
21
22macro_rules! fmt_component_match {
23 (
24 $self:expr,
25 $output:ident,
26 $value:ident,
27 $state:ident,
28 $($extra:tt)*
29 ) => {
30 match $self {
31 Self::Day(modifier) if V::SUPPLIES_DATE => {
32 $output.fmt_day($value.day($state), *modifier).map_err(Into::into)
33 }
34 Self::MonthShort(modifier) if V::SUPPLIES_DATE => {
35 $output.fmt_month_short($value.month($state), *modifier).map_err(Into::into)
36 }
37 Self::MonthLong(modifier) if V::SUPPLIES_DATE => {
38 $output.fmt_month_long($value.month($state), *modifier).map_err(Into::into)
39 }
40 Self::MonthNumerical(modifier) if V::SUPPLIES_DATE => {
41 $output.fmt_month_numerical($value.month($state), *modifier).map_err(Into::into)
42 }
43 Self::Ordinal(modifier) if V::SUPPLIES_DATE => {
44 $output.fmt_ordinal($value.ordinal($state), *modifier).map_err(Into::into)
45 }
46 Self::WeekdayShort(modifier) if V::SUPPLIES_DATE => {
47 $output.fmt_weekday_short($value.weekday($state), *modifier).map_err(Into::into)
48 }
49 Self::WeekdayLong(modifier) if V::SUPPLIES_DATE => {
50 $output.fmt_weekday_long($value.weekday($state), *modifier).map_err(Into::into)
51 }
52 Self::WeekdaySunday(modifier) if V::SUPPLIES_DATE => {
53 $output.fmt_weekday_sunday($value.weekday($state), *modifier).map_err(Into::into)
54 }
55 Self::WeekdayMonday(modifier) if V::SUPPLIES_DATE => {
56 $output.fmt_weekday_monday($value.weekday($state), *modifier).map_err(Into::into)
57 }
58 Self::WeekNumberIso(modifier) if V::SUPPLIES_DATE => {
59 $output.fmt_week_number_iso(
60 $value.iso_week_number($state),
61 *modifier,
62 )
63 .map_err(Into::into)
64 }
65 Self::WeekNumberSunday(modifier) if V::SUPPLIES_DATE => {
66 $output.fmt_week_number_sunday(
67 $value.sunday_based_week($state),
68 *modifier,
69 )
70 .map_err(Into::into)
71 }
72 Self::WeekNumberMonday(modifier) if V::SUPPLIES_DATE => {
73 $output.fmt_week_number_monday(
74 $value.monday_based_week($state),
75 *modifier,
76 )
77 .map_err(Into::into)
78 }
79 Self::CalendarYearFullExtendedRange(modifier) if V::SUPPLIES_DATE => {
80 $output.fmt_calendar_year_full_extended_range(
81 $value.calendar_year($state),
82 *modifier
83 ).map_err(Into::into)
84 }
85 Self::CalendarYearFullStandardRange(modifier) if V::SUPPLIES_DATE => {
86 $output.fmt_calendar_year_full_standard_range(
87 try_likely_ok!(
88 $value
89 .calendar_year($state)
90 .narrow::<-9_999, 9_999>()
91 .ok_or_else(|| error::ComponentRange::conditional("year"))
92 )
93 .into(),
94 *modifier,
95 )
96 .map_err(Into::into)
97 }
98 Self::IsoYearFullExtendedRange(modifier) if V::SUPPLIES_DATE => {
99 $output.fmt_iso_year_full_extended_range(
100 $value.iso_year($state),
101 *modifier,
102 )
103 .map_err(Into::into)
104 }
105 Self::IsoYearFullStandardRange(modifier) if V::SUPPLIES_DATE => {
106 $output.fmt_iso_year_full_standard_range(
107 try_likely_ok!(
108 $value
109 .iso_year($state)
110 .narrow::<-9_999, 9_999>()
111 .ok_or_else(|| error::ComponentRange::conditional("year"))
112 )
113 .into(),
114 *modifier,
115 )
116 .map_err(Into::into)
117 }
118 Self::CalendarYearCenturyExtendedRange(modifier) if V::SUPPLIES_DATE => {
119 let year = $value.calendar_year($state);
120 let century = unsafe { ri16::new_unchecked((year.get() / 100).truncate()) };
122 $output.fmt_calendar_year_century_extended_range(
123 century,
124 year.is_negative(),
125 *modifier,
126 )
127 .map_err(Into::into)
128 }
129 Self::CalendarYearCenturyStandardRange(modifier) if V::SUPPLIES_DATE => {
130 let year = $value.calendar_year($state);
131 let is_negative = year.is_negative();
132 let year = unsafe {
134 ri16::<-9_999, 9_999>::new_unchecked((year.get() / 100).truncate())
135 };
136 $output.fmt_calendar_year_century_standard_range(
137 year.narrow::<-99, 99>()
138 .ok_or_else(|| error::ComponentRange::conditional("year"))?
139 .into(),
140 is_negative,
141 *modifier,
142 )
143 .map_err(Into::into)
144 }
145 Self::IsoYearCenturyExtendedRange(modifier) if V::SUPPLIES_DATE => {
146 let year = $value.iso_year($state);
147 let is_negative = year.is_negative();
148 let century = unsafe { ri16::new_unchecked((year.get() / 100).truncate()) };
150 $output.fmt_iso_year_century_extended_range(
151 century,
152 is_negative,
153 *modifier,
154 )
155 .map_err(Into::into)
156 }
157 Self::IsoYearCenturyStandardRange(modifier) if V::SUPPLIES_DATE => {
158 let year = $value.iso_year($state);
159 let is_negative = year.is_negative();
160 let year = unsafe {
162 ri16::<-9_999, 9_999>::new_unchecked((year.get() / 100).truncate())
163 };
164 $output.fmt_iso_year_century_standard_range(
165 year.narrow::<-99, 99>()
166 .ok_or_else(|| error::ComponentRange::conditional("year"))?
167 .into(),
168 is_negative,
169 *modifier,
170 )
171 .map_err(Into::into)
172 }
173 Self::CalendarYearLastTwo(modifier) if V::SUPPLIES_DATE => {
174 let last_two = unsafe {
177 ru8::new_unchecked(
178 ($value.calendar_year($state).get().unsigned_abs() % 100).truncate(),
179 )
180 };
181 $output.fmt_calendar_year_last_two(last_two, *modifier)
182 .map_err(Into::into)
183 }
184 Self::IsoYearLastTwo(modifier) if V::SUPPLIES_DATE => {
185 let last_two = unsafe {
188 ru8::new_unchecked(
189 ($value.iso_year($state).get().unsigned_abs() % 100).truncate(),
190 )
191 };
192 $output.fmt_iso_year_last_two(last_two, *modifier).map_err(Into::into)
193 }
194 Self::Hour12(modifier) if V::SUPPLIES_TIME => {
195 $output.fmt_hour_12($value.hour($state), *modifier).map_err(Into::into)
196 }
197 Self::Hour24(modifier) if V::SUPPLIES_TIME => {
198 $output.fmt_hour_24($value.hour($state), *modifier).map_err(Into::into)
199 }
200 Self::Minute(modifier) if V::SUPPLIES_TIME => {
201 $output.fmt_minute($value.minute($state), *modifier).map_err(Into::into)
202 }
203 Self::Period(modifier) if V::SUPPLIES_TIME => {
204 $output.fmt_period($value.period($state), *modifier).map_err(Into::into)
205 }
206 Self::Second(modifier) if V::SUPPLIES_TIME => {
207 $output.fmt_second($value.second($state), *modifier).map_err(Into::into)
208 }
209 Self::Subsecond(modifier) if V::SUPPLIES_TIME => {
210 $output.fmt_subsecond($value.nanosecond($state), *modifier).map_err(Into::into)
211 }
212 Self::OffsetHour(modifier) if V::SUPPLIES_OFFSET => {
213 $output.fmt_offset_hour(
214 $value.offset_is_negative($state),
215 $value.offset_hour($state),
216 *modifier,
217 )
218 .map_err(Into::into)
219 }
220 Self::OffsetMinute(modifier) if V::SUPPLIES_OFFSET => {
221 $output.fmt_offset_minute($value.offset_minute($state), *modifier)
222 .map_err(Into::into)
223 }
224 Self::OffsetSecond(modifier) if V::SUPPLIES_OFFSET => {
225 $output.fmt_offset_second($value.offset_second($state), *modifier)
226 .map_err(Into::into)
227 }
228 Self::Ignore(_) => Ok(()),
229 Self::UnixTimestampSecond(modifier) if V::SUPPLIES_TIMESTAMP => {
230 $output.fmt_unix_timestamp_second(
231 $value.unix_timestamp_seconds($state),
232 *modifier,
233 )
234 .map_err(Into::into)
235 }
236 Self::UnixTimestampMillisecond(modifier) if V::SUPPLIES_TIMESTAMP => {
237 $output.fmt_unix_timestamp_millisecond(
238 $value.unix_timestamp_milliseconds($state),
239 *modifier,
240 )
241 .map_err(Into::into)
242 }
243 Self::UnixTimestampMicrosecond(modifier) if V::SUPPLIES_TIMESTAMP => {
244 $output.fmt_unix_timestamp_microsecond(
245 $value.unix_timestamp_microseconds($state),
246 *modifier,
247 )
248 .map_err(Into::into)
249 }
250 Self::UnixTimestampNanosecond(modifier) if V::SUPPLIES_TIMESTAMP => {
251 $output.fmt_unix_timestamp_nanosecond(
252 $value.unix_timestamp_nanoseconds($state),
253 *modifier,
254 )
255 .map_err(Into::into)
256 }
257 Self::End(modifier::End { trailing_input: _ }) => Ok(()),
258 $($extra)*
259 }
260 };
261}
262
263#[cfg_attr(docsrs, doc(notable_trait))]
269pub trait Formattable: sealed::Sealed {}
270impl Formattable for FormatDescriptionV3<'_> {}
271impl Formattable for BorrowedFormatItem<'_> {}
272impl Formattable for [BorrowedFormatItem<'_>] {}
273impl Formattable for OwnedFormatItem {}
274impl Formattable for [OwnedFormatItem] {}
275impl Formattable for Rfc3339 {}
276impl Formattable for Rfc2822 {}
277impl<const CONFIG: EncodedConfig> Formattable for Iso8601<CONFIG> {}
278impl<T> Formattable for T where T: Deref<Target: Formattable> {}
279
280mod sealed {
282 use super::*;
283 use crate::formatting::ComponentProvider;
284 use crate::formatting::metadata::ComputeMetadata;
285
286 #[expect(
288 private_bounds,
289 private_interfaces,
290 reason = "irrelevant due to being a sealed trait"
291 )]
292 pub trait Sealed: ComputeMetadata {
293 fn format_into<V>(
295 &self,
296 output: &mut Output<impl io::Write + ?Sized>,
297 value: &V,
298 state: &mut V::State,
299 _: PrivateMethod,
300 ) -> Result<(), error::Format>
301 where
302 V: ComponentProvider;
303
304 #[inline]
306 fn format<V>(
307 &self,
308 value: &V,
309 state: &mut V::State,
310 _: PrivateMethod,
311 ) -> Result<String, error::Format>
312 where
313 V: ComponentProvider,
314 {
315 let crate::formatting::metadata::Metadata {
316 max_bytes_needed,
317 guaranteed_utf8,
318 } = self.compute_metadata(PrivateMethod);
319
320 let mut output = Output {
321 bytes_written: 0,
322 output: Vec::with_capacity(max_bytes_needed),
323 };
324 try_likely_ok!(self.format_into(&mut output, value, state, PrivateMethod));
325 Ok(if guaranteed_utf8 {
326 unsafe { String::from_utf8_unchecked(output.output) }
328 } else {
329 String::from_utf8_lossy(&output.output).into_owned()
330 })
331 }
332 }
333}
334
335impl sealed::Sealed for FormatDescriptionV3<'_> {
336 #[expect(
337 private_bounds,
338 private_interfaces,
339 reason = "irrelevant due to being a sealed trait"
340 )]
341 #[inline]
342 fn format_into<V>(
343 &self,
344 output: &mut Output<impl io::Write + ?Sized>,
345 value: &V,
346 state: &mut V::State,
347 _: PrivateMethod,
348 ) -> Result<(), error::Format>
349 where
350 V: ComponentProvider,
351 {
352 self.inner.format_into(output, value, state, PrivateMethod)
353 }
354}
355
356impl sealed::Sealed for FormatDescriptionV3Inner<'_> {
357 #[expect(
358 private_bounds,
359 private_interfaces,
360 reason = "irrelevant due to being a sealed trait"
361 )]
362 #[inline]
363 fn format_into<V>(
364 &self,
365 output: &mut Output<impl io::Write + ?Sized>,
366 value: &V,
367 state: &mut V::State,
368 _: PrivateMethod,
369 ) -> Result<(), error::Format>
370 where
371 V: ComponentProvider,
372 {
373 use crate::formatting::*;
374
375 fmt_component_match! { &self, output, value, state,
376 Self::BorrowedLiteral(literal) => output.write(literal).map_err(Into::into),
377 Self::BorrowedCompound(items) => {
378 for item in *items {
379 try_likely_ok!(item.format_into(
380 output,
381 value,
382 state,
383 PrivateMethod,
384 ));
385 }
386 Ok(())
387 }
388 Self::BorrowedOptional {
389 format: should_format,
390 item,
391 } => {
392 if *should_format {
393 item.format_into(output, value, state, PrivateMethod)
394 } else {
395 Ok(())
396 }
397 }
398 Self::BorrowedFirst(items) => match items {
399 [] => Ok(()),
400 [item, ..] => {
401 item.format_into(output, value, state, PrivateMethod)
402 }
403 },
404 Self::OwnedLiteral(literal) => output.write(literal).map_err(Into::into),
405 Self::OwnedCompound(items) => {
406 for item in &**items {
407 try_likely_ok!(item.format_into(
408 output,
409 value,
410 state,
411 PrivateMethod,
412 ));
413 }
414 Ok(())
415 }
416 Self::OwnedOptional {
417 format: should_format,
418 item,
419 } => {
420 if *should_format {
421 item.format_into(output, value, state, PrivateMethod)
422 } else {
423 Ok(())
424 }
425 }
426 Self::OwnedFirst(items) => match &items[..] {
427 [] => Ok(()),
428 [item, ..] => {
429 item.format_into(output, value, state, PrivateMethod)
430 }
431 },
432
433 #[allow(unreachable_patterns)]
438 Self::Day(_)
439 | Self::MonthShort(_)
440 | Self::MonthLong(_)
441 | Self::MonthNumerical(_)
442 | Self::Ordinal(_)
443 | Self::WeekdayShort(_)
444 | Self::WeekdayLong(_)
445 | Self::WeekdaySunday(_)
446 | Self::WeekdayMonday(_)
447 | Self::WeekNumberIso(_)
448 | Self::WeekNumberSunday(_)
449 | Self::WeekNumberMonday(_)
450 | Self::CalendarYearFullExtendedRange(_)
451 | Self::CalendarYearFullStandardRange(_)
452 | Self::IsoYearFullExtendedRange(_)
453 | Self::IsoYearFullStandardRange(_)
454 | Self::CalendarYearCenturyExtendedRange(_)
455 | Self::CalendarYearCenturyStandardRange(_)
456 | Self::IsoYearCenturyExtendedRange(_)
457 | Self::IsoYearCenturyStandardRange(_)
458 | Self::CalendarYearLastTwo(_)
459 | Self::IsoYearLastTwo(_)
460 | Self::Hour12(_)
461 | Self::Hour24(_)
462 | Self::Minute(_)
463 | Self::Period(_)
464 | Self::Second(_)
465 | Self::Subsecond(_)
466 | Self::OffsetHour(_)
467 | Self::OffsetMinute(_)
468 | Self::OffsetSecond(_)
469 | Self::Ignore(_)
470 | Self::UnixTimestampSecond(_)
471 | Self::UnixTimestampMillisecond(_)
472 | Self::UnixTimestampMicrosecond(_)
473 | Self::UnixTimestampNanosecond(_)
474 | Self::End(_) => Err(error::Format::InsufficientTypeInformation),
475 }
476 }
477}
478
479impl Component {
480 #[inline]
482 #[allow(deprecated)]
483 pub(crate) fn format_into<V>(
484 &self,
485 output: &mut Output<impl io::Write + ?Sized>,
486 value: &V,
487 state: &mut V::State,
488 ) -> Result<(), error::Format>
489 where
490 V: ComponentProvider,
491 {
492 use sealed::Sealed;
493
494 use crate::formatting::*;
495
496 fmt_component_match! { self, output, value, state,
497 Self::Month(_) | Self::Weekday(_) | Self::WeekNumber(_)
499 if V::SUPPLIES_DATE =>
500 {
501 FormatDescriptionV3Inner::from(*self)
502 .format_into(output, value, state, PrivateMethod)
503 }
504 Self::Hour(_) if V::SUPPLIES_TIME => {
505 FormatDescriptionV3Inner::from(*self)
506 .format_into(output, value, state, PrivateMethod)
507 }
508 Self::UnixTimestamp(_) if V::SUPPLIES_TIMESTAMP => {
509 FormatDescriptionV3Inner::from(*self)
510 .format_into(output, value, state, PrivateMethod)
511 }
512 Self::Year(_) if V::SUPPLIES_DATE => {
513 FormatDescriptionV3Inner::from(*self)
514 .format_into(output, value, state, PrivateMethod)
515 }
516
517 #[allow(unreachable_patterns)]
519 Self::Day(_)
520 | Self::MonthShort(_)
521 | Self::MonthLong(_)
522 | Self::MonthNumerical(_)
523 | Self::Ordinal(_)
524 | Self::WeekdayShort(_)
525 | Self::WeekdayLong(_)
526 | Self::WeekdaySunday(_)
527 | Self::WeekdayMonday(_)
528 | Self::WeekNumberIso(_)
529 | Self::WeekNumberSunday(_)
530 | Self::WeekNumberMonday(_)
531 | Self::CalendarYearFullExtendedRange(_)
532 | Self::CalendarYearFullStandardRange(_)
533 | Self::IsoYearFullExtendedRange(_)
534 | Self::IsoYearFullStandardRange(_)
535 | Self::CalendarYearCenturyExtendedRange(_)
536 | Self::CalendarYearCenturyStandardRange(_)
537 | Self::IsoYearCenturyExtendedRange(_)
538 | Self::IsoYearCenturyStandardRange(_)
539 | Self::CalendarYearLastTwo(_)
540 | Self::IsoYearLastTwo(_)
541 | Self::Hour12(_)
542 | Self::Hour24(_)
543 | Self::Minute(_)
544 | Self::Period(_)
545 | Self::Second(_)
546 | Self::Subsecond(_)
547 | Self::OffsetHour(_)
548 | Self::OffsetMinute(_)
549 | Self::OffsetSecond(_)
550 | Self::Ignore(_)
551 | Self::UnixTimestampSecond(_)
552 | Self::UnixTimestampMillisecond(_)
553 | Self::UnixTimestampMicrosecond(_)
554 | Self::UnixTimestampNanosecond(_)
555 | Self::Month(_)
557 | Self::Weekday(_)
558 | Self::WeekNumber(_)
559 | Self::Hour(_)
560 | Self::UnixTimestamp(_)
561 | Self::Year(_) => Err(error::Format::InsufficientTypeInformation),
562 }
563 }
564}
565
566impl sealed::Sealed for BorrowedFormatItem<'_> {
567 #[expect(
568 private_bounds,
569 private_interfaces,
570 reason = "irrelevant due to being a sealed trait"
571 )]
572 #[inline]
573 fn format_into<V>(
574 &self,
575 output: &mut Output<impl io::Write + ?Sized>,
576 value: &V,
577 state: &mut V::State,
578 _: PrivateMethod,
579 ) -> Result<(), error::Format>
580 where
581 V: ComponentProvider,
582 {
583 match *self {
584 #[expect(deprecated)]
585 Self::Literal(literal) => try_likely_ok!(output.write_bytes(literal)),
586 Self::StringLiteral(literal) => try_likely_ok!(output.write(literal)),
587 Self::Component(component) => component.format_into(output, value, state)?,
588 Self::Compound(items) => {
589 try_likely_ok!((*items).format_into(output, value, state, PrivateMethod));
590 }
591 Self::Optional(item) => {
592 try_likely_ok!((*item).format_into(output, value, state, PrivateMethod));
593 }
594 Self::First(items) => match items {
595 [] => {}
596 [item, ..] => {
597 try_likely_ok!((*item).format_into(output, value, state, PrivateMethod));
598 }
599 },
600 }
601 Ok(())
602 }
603}
604
605impl sealed::Sealed for [BorrowedFormatItem<'_>] {
606 #[expect(
607 private_bounds,
608 private_interfaces,
609 reason = "irrelevant due to being a sealed trait"
610 )]
611 #[inline]
612 fn format_into<V>(
613 &self,
614 output: &mut Output<impl io::Write + ?Sized>,
615 value: &V,
616 state: &mut V::State,
617 _: PrivateMethod,
618 ) -> Result<(), error::Format>
619 where
620 V: ComponentProvider,
621 {
622 for item in self.iter() {
623 try_likely_ok!(item.format_into(output, value, state, PrivateMethod));
624 }
625 Ok(())
626 }
627}
628
629impl sealed::Sealed for OwnedFormatItem {
630 #[expect(
631 private_bounds,
632 private_interfaces,
633 reason = "irrelevant due to being a sealed trait"
634 )]
635 #[inline]
636 fn format_into<V>(
637 &self,
638 output: &mut Output<impl io::Write + ?Sized>,
639 value: &V,
640 state: &mut V::State,
641 _: PrivateMethod,
642 ) -> Result<(), error::Format>
643 where
644 V: ComponentProvider,
645 {
646 match self {
647 #[expect(deprecated)]
648 Self::Literal(literal) => output.write_bytes(literal).map_err(Into::into),
649 Self::StringLiteral(literal) => output.write(literal).map_err(Into::into),
650 Self::Component(component) => FormatDescriptionV3Inner::<'_>::from(*component)
651 .format_into(output, value, state, PrivateMethod),
652 Self::Compound(items) => (**items).format_into(output, value, state, PrivateMethod),
653 Self::Optional(item) => (**item).format_into(output, value, state, PrivateMethod),
654 Self::First(items) => match &**items {
655 [] => Ok(()),
656 [item, ..] => (*item).format_into(output, value, state, PrivateMethod),
657 },
658 }
659 }
660}
661
662impl sealed::Sealed for [OwnedFormatItem] {
663 #[expect(
664 private_bounds,
665 private_interfaces,
666 reason = "irrelevant due to being a sealed trait"
667 )]
668 #[inline]
669 fn format_into<V>(
670 &self,
671 output: &mut Output<impl io::Write + ?Sized>,
672 value: &V,
673 state: &mut V::State,
674 _: PrivateMethod,
675 ) -> Result<(), error::Format>
676 where
677 V: ComponentProvider,
678 {
679 for item in self.iter() {
680 try_likely_ok!(item.format_into(output, value, state, PrivateMethod));
681 }
682 Ok(())
683 }
684}
685
686impl<T> sealed::Sealed for T
687where
688 T: Deref<Target: sealed::Sealed>,
689{
690 #[expect(
691 private_bounds,
692 private_interfaces,
693 reason = "irrelevant due to being a sealed trait"
694 )]
695 #[inline]
696 fn format_into<V>(
697 &self,
698 output: &mut Output<impl io::Write + ?Sized>,
699 value: &V,
700 state: &mut V::State,
701 _: PrivateMethod,
702 ) -> Result<(), error::Format>
703 where
704 V: ComponentProvider,
705 {
706 self.deref()
707 .format_into(output, value, state, PrivateMethod)
708 }
709}
710
711#[expect(
712 private_bounds,
713 private_interfaces,
714 reason = "irrelevant due to being a sealed trait"
715)]
716impl sealed::Sealed for Rfc2822 {
717 fn format_into<V>(
718 &self,
719 output: &mut Output<impl io::Write + ?Sized>,
720 value: &V,
721 state: &mut V::State,
722 _: PrivateMethod,
723 ) -> Result<(), error::Format>
724 where
725 V: ComponentProvider,
726 {
727 const {
728 assert!(
729 V::SUPPLIES_DATE && V::SUPPLIES_TIME && V::SUPPLIES_OFFSET,
730 "Rfc2822 requires date, time, and offset components, but not all can be provided \
731 by this type"
732 );
733 }
734
735 if value.calendar_year(state).get() < 1900
736 || (cfg!(feature = "large-dates") && value.calendar_year(state).get() >= 10_000)
738 {
739 crate::hint::cold_path();
740 return Err(error::Format::InvalidComponent("year"));
741 }
742 if value.offset_second(state).get() != 0 {
743 crate::hint::cold_path();
744 return Err(error::Format::InvalidComponent("offset_second"));
745 }
746
747 try_likely_ok!(output.write(unsafe {
749 WEEKDAY_NAMES[value
750 .weekday(state)
751 .number_days_from_monday()
752 .widen::<usize>()]
753 .get_unchecked(..3)
754 }));
755 try_likely_ok!(output.write(", "));
756 try_likely_ok!(output.format_two_digits(value.day(state).expand(), Padding::Zero));
757 try_likely_ok!(output.write(" "));
758 try_likely_ok!(output.write(unsafe {
760 MONTH_NAMES[u8::from(value.month(state)).widen::<usize>() - 1].get_unchecked(..3)
761 }));
762 try_likely_ok!(output.write(" "));
763 try_likely_ok!(output.format_four_digits_pad_zero(unsafe {
765 ru16::new_unchecked(value.calendar_year(state).get().cast_unsigned().truncate())
766 }));
767 try_likely_ok!(output.write(" "));
768 try_likely_ok!(output.format_two_digits(value.hour(state).expand(), Padding::Zero));
769 try_likely_ok!(output.write(":"));
770 try_likely_ok!(output.format_two_digits(value.minute(state).expand(), Padding::Zero));
771 try_likely_ok!(output.write(":"));
772 try_likely_ok!(output.format_two_digits(value.second(state).expand(), Padding::Zero));
773 try_likely_ok!(output.write(" "));
774 try_likely_ok!(output.write_if_else(value.offset_is_negative(state), "-", "+"));
775 try_likely_ok!(output.format_two_digits(
776 unsafe { ru8::new_unchecked(value.offset_hour(state).get().unsigned_abs()) },
779 Padding::Zero,
780 ));
781 try_likely_ok!(output.format_two_digits(
782 unsafe { ru8::new_unchecked(value.offset_minute(state).get().unsigned_abs()) },
785 Padding::Zero,
786 ));
787
788 Ok(())
789 }
790}
791
792#[expect(
793 private_bounds,
794 private_interfaces,
795 reason = "irrelevant due to being a sealed trait"
796)]
797impl sealed::Sealed for Rfc3339 {
798 fn format_into<V>(
799 &self,
800 output: &mut Output<impl io::Write + ?Sized>,
801 value: &V,
802 state: &mut V::State,
803 _: PrivateMethod,
804 ) -> Result<(), error::Format>
805 where
806 V: ComponentProvider,
807 {
808 const {
809 assert!(
810 V::SUPPLIES_DATE && V::SUPPLIES_TIME && V::SUPPLIES_OFFSET,
811 "Rfc3339 requires date, time, and offset components, but not all can be provided \
812 by this type"
813 );
814 }
815
816 let offset_hour = value.offset_hour(state);
817
818 if !(0..10_000).contains(&value.calendar_year(state).get()) {
819 crate::hint::cold_path();
820 return Err(error::Format::InvalidComponent("year"));
821 }
822 if offset_hour.get().unsigned_abs() > 23 {
823 crate::hint::cold_path();
824 return Err(error::Format::InvalidComponent("offset_hour"));
825 }
826 if value.offset_second(state).get() != 0 {
827 crate::hint::cold_path();
828 return Err(error::Format::InvalidComponent("offset_second"));
829 }
830
831 try_likely_ok!(output.format_four_digits_pad_zero(unsafe {
833 ru16::new_unchecked(value.calendar_year(state).get().cast_unsigned().truncate())
834 }));
835 try_likely_ok!(output.write("-"));
836 try_likely_ok!(output.format_two_digits(
837 unsafe { ru8::new_unchecked(u8::from(value.month(state))) },
839 Padding::Zero,
840 ));
841 try_likely_ok!(output.write("-"));
842 try_likely_ok!(output.format_two_digits(value.day(state).expand(), Padding::Zero));
843 try_likely_ok!(output.write("T"));
844 try_likely_ok!(output.format_two_digits(value.hour(state).expand(), Padding::Zero));
845 try_likely_ok!(output.write(":"));
846 try_likely_ok!(output.format_two_digits(value.minute(state).expand(), Padding::Zero));
847 try_likely_ok!(output.write(":"));
848 try_likely_ok!(output.format_two_digits(value.second(state).expand(), Padding::Zero));
849
850 let nanos = value.nanosecond(state);
851 if nanos.get() != 0 {
852 try_likely_ok!(output.write("."));
853 try_likely_ok!(output.write(&num_fmt::truncated_subsecond_from_nanos(nanos)));
854 }
855
856 if value.offset_is_utc(state) {
857 try_likely_ok!(output.write("Z"));
858 return Ok(());
859 }
860
861 try_likely_ok!(output.write_if_else(value.offset_is_negative(state), "-", "+"));
862 try_likely_ok!(output.format_two_digits(
863 unsafe { ru8::new_unchecked(offset_hour.get().unsigned_abs()) },
866 Padding::Zero,
867 ));
868 try_likely_ok!(output.write(":"));
869 try_likely_ok!(output.format_two_digits(
870 unsafe { ru8::new_unchecked(value.offset_minute(state).get().unsigned_abs()) },
873 Padding::Zero,
874 ));
875
876 Ok(())
877 }
878}
879
880impl<const CONFIG: EncodedConfig> sealed::Sealed for Iso8601<CONFIG> {
881 #[expect(
882 private_bounds,
883 private_interfaces,
884 reason = "irrelevant due to being a sealed trait"
885 )]
886 #[inline]
887 fn format_into<V>(
888 &self,
889 output: &mut Output<impl io::Write + ?Sized>,
890 value: &V,
891 state: &mut V::State,
892 _: PrivateMethod,
893 ) -> Result<(), error::Format>
894 where
895 V: ComponentProvider,
896 {
897 const {
898 assert!(
899 !Self::FORMAT_DATE || V::SUPPLIES_DATE,
900 "this Iso8601 configuration formats date components, but this type cannot provide \
901 them"
902 );
903 assert!(
904 !Self::FORMAT_TIME || V::SUPPLIES_TIME,
905 "this Iso8601 configuration formats time components, but this type cannot provide \
906 them"
907 );
908 assert!(
909 !Self::FORMAT_OFFSET || V::SUPPLIES_OFFSET,
910 "this Iso8601 configuration formats offset components, but this type cannot \
911 provide them"
912 );
913 assert!(
914 Self::FORMAT_DATE || Self::FORMAT_TIME || Self::FORMAT_OFFSET,
915 "this Iso8601 configuration does not format any components"
916 );
917 }
918
919 if Self::FORMAT_DATE {
920 output.format_iso8601_date::<_, CONFIG>(value, state)?;
921 }
922 if Self::FORMAT_TIME {
923 output.format_iso8601_time::<_, CONFIG>(value, state)?;
924 }
925 if Self::FORMAT_OFFSET {
926 output.format_iso8601_offset::<_, CONFIG>(value, state)?;
927 }
928
929 Ok(())
930 }
931}