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