1use alloc::string::String;
4use alloc::vec::Vec;
5use core::ops::Deref;
6use std::io;
7
8use num_conv::prelude::*;
9
10use crate::error;
11use crate::format_description::well_known::iso8601::EncodedConfig;
12use crate::format_description::well_known::{Iso8601, Rfc2822, Rfc3339};
13use crate::format_description::{BorrowedFormatItem, OwnedFormatItem};
14use crate::formatting::{
15 ComponentProvider, MONTH_NAMES, WEEKDAY_NAMES, format_component, format_number_pad_zero,
16 iso8601, write, write_if_else,
17};
18
19#[cfg_attr(docsrs, doc(notable_trait))]
25pub trait Formattable: sealed::Sealed {}
26impl Formattable for BorrowedFormatItem<'_> {}
27impl Formattable for [BorrowedFormatItem<'_>] {}
28impl Formattable for OwnedFormatItem {}
29impl Formattable for [OwnedFormatItem] {}
30impl Formattable for Rfc3339 {}
31impl Formattable for Rfc2822 {}
32impl<const CONFIG: EncodedConfig> Formattable for Iso8601<CONFIG> {}
33impl<T> Formattable for T where T: Deref<Target: Formattable> {}
34
35mod sealed {
37 use super::*;
38 use crate::formatting::ComponentProvider;
39
40 #[expect(
42 private_bounds,
43 private_interfaces,
44 reason = "irrelevant due to being a sealed trait"
45 )]
46 pub trait Sealed {
47 fn format_into<V>(
49 &self,
50 output: &mut (impl io::Write + ?Sized),
51 value: &V,
52 state: &mut V::State,
53 ) -> Result<usize, error::Format>
54 where
55 V: ComponentProvider;
56
57 #[inline]
59 fn format<V>(&self, value: &V, state: &mut V::State) -> Result<String, error::Format>
60 where
61 V: ComponentProvider,
62 {
63 let mut buf = Vec::new();
64 self.format_into(&mut buf, value, state)?;
65 Ok(String::from_utf8_lossy(&buf).into_owned())
66 }
67 }
68}
69
70impl sealed::Sealed for BorrowedFormatItem<'_> {
71 #[expect(
72 private_bounds,
73 private_interfaces,
74 reason = "irrelevant due to being a sealed trait"
75 )]
76 #[inline]
77 fn format_into<V>(
78 &self,
79 output: &mut (impl io::Write + ?Sized),
80 value: &V,
81 state: &mut V::State,
82 ) -> Result<usize, error::Format>
83 where
84 V: ComponentProvider,
85 {
86 Ok(match *self {
87 Self::Literal(literal) => write(output, literal)?,
88 Self::Component(component) => format_component(output, component, value, state)?,
89 Self::Compound(items) => (*items).format_into(output, value, state)?,
90 Self::Optional(item) => (*item).format_into(output, value, state)?,
91 Self::First(items) => match items {
92 [] => 0,
93 [item, ..] => (*item).format_into(output, value, state)?,
94 },
95 })
96 }
97}
98
99impl sealed::Sealed for [BorrowedFormatItem<'_>] {
100 #[expect(
101 private_bounds,
102 private_interfaces,
103 reason = "irrelevant due to being a sealed trait"
104 )]
105 #[inline]
106 fn format_into<V>(
107 &self,
108 output: &mut (impl io::Write + ?Sized),
109 value: &V,
110 state: &mut V::State,
111 ) -> Result<usize, error::Format>
112 where
113 V: ComponentProvider,
114 {
115 let mut bytes = 0;
116 for item in self.iter() {
117 bytes += (*item).format_into(output, value, state)?;
118 }
119 Ok(bytes)
120 }
121}
122
123impl sealed::Sealed for OwnedFormatItem {
124 #[expect(
125 private_bounds,
126 private_interfaces,
127 reason = "irrelevant due to being a sealed trait"
128 )]
129 #[inline]
130 fn format_into<V>(
131 &self,
132 output: &mut (impl io::Write + ?Sized),
133 value: &V,
134 state: &mut V::State,
135 ) -> Result<usize, error::Format>
136 where
137 V: ComponentProvider,
138 {
139 match self {
140 Self::Literal(literal) => Ok(write(output, literal)?),
141 Self::Component(component) => format_component(output, *component, value, state),
142 Self::Compound(items) => (**items).format_into(output, value, state),
143 Self::Optional(item) => (**item).format_into(output, value, state),
144 Self::First(items) => match &**items {
145 [] => Ok(0),
146 [item, ..] => (*item).format_into(output, value, state),
147 },
148 }
149 }
150}
151
152impl sealed::Sealed for [OwnedFormatItem] {
153 #[expect(
154 private_bounds,
155 private_interfaces,
156 reason = "irrelevant due to being a sealed trait"
157 )]
158 #[inline]
159 fn format_into<V>(
160 &self,
161 output: &mut (impl io::Write + ?Sized),
162 value: &V,
163 state: &mut V::State,
164 ) -> Result<usize, error::Format>
165 where
166 V: ComponentProvider,
167 {
168 let mut bytes = 0;
169 for item in self.iter() {
170 bytes += item.format_into(output, value, state)?;
171 }
172 Ok(bytes)
173 }
174}
175
176impl<T> sealed::Sealed for T
177where
178 T: Deref<Target: sealed::Sealed>,
179{
180 #[expect(
181 private_bounds,
182 private_interfaces,
183 reason = "irrelevant due to being a sealed trait"
184 )]
185 #[inline]
186 fn format_into<V>(
187 &self,
188 output: &mut (impl io::Write + ?Sized),
189 value: &V,
190 state: &mut V::State,
191 ) -> Result<usize, error::Format>
192 where
193 V: ComponentProvider,
194 {
195 self.deref().format_into(output, value, state)
196 }
197}
198
199impl sealed::Sealed for Rfc2822 {
200 #[expect(
201 private_bounds,
202 private_interfaces,
203 reason = "irrelevant due to being a sealed trait"
204 )]
205 fn format_into<V>(
206 &self,
207 output: &mut (impl io::Write + ?Sized),
208 value: &V,
209 state: &mut V::State,
210 ) -> Result<usize, error::Format>
211 where
212 V: ComponentProvider,
213 {
214 const {
215 assert!(
216 V::SUPPLIES_DATE && V::SUPPLIES_TIME && V::SUPPLIES_OFFSET,
217 "Rfc2822 requires date, time, and offset components, but not all can be provided \
218 by this type"
219 );
220 }
221
222 let mut bytes = 0;
223
224 if value.calendar_year(state) < 1900 {
225 return Err(error::Format::InvalidComponent("year"));
226 }
227 if value.offset_second(state) != 0 {
228 return Err(error::Format::InvalidComponent("offset_second"));
229 }
230
231 bytes += write(output, unsafe {
233 WEEKDAY_NAMES[value
234 .weekday(state)
235 .number_days_from_monday()
236 .extend::<usize>()]
237 .get_unchecked(..3)
238 })?;
239 bytes += write(output, b", ")?;
240 bytes += format_number_pad_zero::<2>(output, value.day(state))?;
241 bytes += write(output, b" ")?;
242 bytes += write(output, unsafe {
244 MONTH_NAMES[u8::from(value.month(state)).extend::<usize>() - 1].get_unchecked(..3)
245 })?;
246 bytes += write(output, b" ")?;
247 bytes += format_number_pad_zero::<4>(output, value.calendar_year(state).cast_unsigned())?;
248 bytes += write(output, b" ")?;
249 bytes += format_number_pad_zero::<2>(output, value.hour(state))?;
250 bytes += write(output, b":")?;
251 bytes += format_number_pad_zero::<2>(output, value.minute(state))?;
252 bytes += write(output, b":")?;
253 bytes += format_number_pad_zero::<2>(output, value.second(state))?;
254 bytes += write(output, b" ")?;
255 bytes += write_if_else(output, value.offset_is_negative(state), b"-", b"+")?;
256 bytes += format_number_pad_zero::<2>(output, value.offset_hour(state).unsigned_abs())?;
257 bytes += format_number_pad_zero::<2>(output, value.offset_minute(state).unsigned_abs())?;
258
259 Ok(bytes)
260 }
261}
262
263impl sealed::Sealed for Rfc3339 {
264 #[expect(
265 private_bounds,
266 private_interfaces,
267 reason = "irrelevant due to being a sealed trait"
268 )]
269 fn format_into<V>(
270 &self,
271 output: &mut (impl io::Write + ?Sized),
272 value: &V,
273 state: &mut V::State,
274 ) -> Result<usize, error::Format>
275 where
276 V: ComponentProvider,
277 {
278 const {
279 assert!(
280 V::SUPPLIES_DATE && V::SUPPLIES_TIME && V::SUPPLIES_OFFSET,
281 "Rfc3339 requires date, time, and offset components, but not all can be provided \
282 by this type"
283 );
284 }
285
286 let offset_hour = value.offset_hour(state);
287 let mut bytes = 0;
288
289 if !(0..10_000).contains(&value.calendar_year(state)) {
290 return Err(error::Format::InvalidComponent("year"));
291 }
292 if offset_hour.unsigned_abs() > 23 {
293 return Err(error::Format::InvalidComponent("offset_hour"));
294 }
295 if value.offset_second(state) != 0 {
296 return Err(error::Format::InvalidComponent("offset_second"));
297 }
298
299 bytes += format_number_pad_zero::<4>(output, value.calendar_year(state).cast_unsigned())?;
300 bytes += write(output, b"-")?;
301 bytes += format_number_pad_zero::<2>(output, u8::from(value.month(state)))?;
302 bytes += write(output, b"-")?;
303 bytes += format_number_pad_zero::<2>(output, value.day(state))?;
304 bytes += write(output, b"T")?;
305 bytes += format_number_pad_zero::<2>(output, value.hour(state))?;
306 bytes += write(output, b":")?;
307 bytes += format_number_pad_zero::<2>(output, value.minute(state))?;
308 bytes += write(output, b":")?;
309 bytes += format_number_pad_zero::<2>(output, value.second(state))?;
310
311 let nanos = value.nanosecond(state);
312 if nanos != 0 {
313 bytes += write(output, b".")?;
314 bytes += if nanos % 10 != 0 {
315 format_number_pad_zero::<9>(output, nanos)
316 } else if (nanos / 10) % 10 != 0 {
317 format_number_pad_zero::<8>(output, nanos / 10)
318 } else if (nanos / 100) % 10 != 0 {
319 format_number_pad_zero::<7>(output, nanos / 100)
320 } else if (nanos / 1_000) % 10 != 0 {
321 format_number_pad_zero::<6>(output, nanos / 1_000)
322 } else if (nanos / 10_000) % 10 != 0 {
323 format_number_pad_zero::<5>(output, nanos / 10_000)
324 } else if (nanos / 100_000) % 10 != 0 {
325 format_number_pad_zero::<4>(output, nanos / 100_000)
326 } else if (nanos / 1_000_000) % 10 != 0 {
327 format_number_pad_zero::<3>(output, nanos / 1_000_000)
328 } else if (nanos / 10_000_000) % 10 != 0 {
329 format_number_pad_zero::<2>(output, nanos / 10_000_000)
330 } else {
331 format_number_pad_zero::<1>(output, nanos / 100_000_000)
332 }?;
333 }
334
335 if value.offset_is_utc(state) {
336 bytes += write(output, b"Z")?;
337 return Ok(bytes);
338 }
339
340 bytes += write_if_else(output, value.offset_is_negative(state), b"-", b"+")?;
341 bytes += format_number_pad_zero::<2>(output, offset_hour.unsigned_abs())?;
342 bytes += write(output, b":")?;
343 bytes += format_number_pad_zero::<2>(output, value.offset_minute(state).unsigned_abs())?;
344
345 Ok(bytes)
346 }
347}
348
349impl<const CONFIG: EncodedConfig> sealed::Sealed for Iso8601<CONFIG> {
350 #[expect(
351 private_bounds,
352 private_interfaces,
353 reason = "irrelevant due to being a sealed trait"
354 )]
355 #[inline]
356 fn format_into<V>(
357 &self,
358 output: &mut (impl io::Write + ?Sized),
359 value: &V,
360 state: &mut V::State,
361 ) -> Result<usize, error::Format>
362 where
363 V: ComponentProvider,
364 {
365 let mut bytes = 0;
366
367 const {
368 assert!(
369 !Self::FORMAT_DATE || V::SUPPLIES_DATE,
370 "this Iso8601 configuration formats date components, but this type cannot provide \
371 them"
372 );
373 assert!(
374 !Self::FORMAT_TIME || V::SUPPLIES_TIME,
375 "this Iso8601 configuration formats time components, but this type cannot provide \
376 them"
377 );
378 assert!(
379 !Self::FORMAT_OFFSET || V::SUPPLIES_OFFSET,
380 "this Iso8601 configuration formats offset components, but this type cannot \
381 provide them"
382 );
383 assert!(
384 Self::FORMAT_DATE || Self::FORMAT_TIME || Self::FORMAT_OFFSET,
385 "this Iso8601 configuration does not format any components"
386 );
387 }
388
389 if Self::FORMAT_DATE {
390 bytes += iso8601::format_date::<_, CONFIG>(output, value, state)?;
391 }
392 if Self::FORMAT_TIME {
393 bytes += iso8601::format_time::<_, CONFIG>(output, value, state)?;
394 }
395 if Self::FORMAT_OFFSET {
396 bytes += iso8601::format_offset::<_, CONFIG>(output, value, state)?;
397 }
398
399 Ok(bytes)
400 }
401}