1#[cfg(feature = "alloc")]
7use alloc::boxed::Box;
8use core::fmt;
9
10use crate::format_description::modifier;
11
12#[derive(Clone)]
19pub struct FormatDescriptionV3<'a> {
20 pub(crate) inner: FormatDescriptionV3Inner<'a>,
22 #[cfg(feature = "formatting")]
25 pub(crate) max_bytes_needed: usize,
26}
27
28impl fmt::Debug for FormatDescriptionV3<'_> {
29 #[inline]
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 self.inner.fmt(f)
32 }
33}
34
35impl FormatDescriptionV3<'_> {
36 #[cfg(feature = "alloc")]
39 #[inline]
40 pub fn to_owned(self) -> FormatDescriptionV3<'static> {
41 FormatDescriptionV3 {
42 inner: self.inner.to_owned(),
43 #[cfg(feature = "formatting")]
44 max_bytes_needed: self.max_bytes_needed,
45 }
46 }
47}
48
49#[non_exhaustive]
52#[derive(Clone)]
53pub enum FormatDescriptionV3Inner<'a> {
54 Component(Component),
56 BorrowedLiteral(&'a str),
58 BorrowedCompound(&'a [Self]),
60 BorrowedOptional {
63 format: bool,
65 item: &'a Self,
67 },
68 BorrowedFirst(&'a [Self]),
71 #[cfg(feature = "alloc")]
73 OwnedLiteral(Box<str>),
74 #[cfg(feature = "alloc")]
76 OwnedCompound(Box<[Self]>),
77 #[cfg(feature = "alloc")]
80 OwnedOptional {
81 format: bool,
83 item: Box<Self>,
85 },
86 #[cfg(feature = "alloc")]
89 OwnedFirst(Box<[Self]>),
90}
91
92impl fmt::Debug for FormatDescriptionV3Inner<'_> {
93 #[inline]
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 match self {
96 Self::Component(component) => f.debug_tuple("Component").field(component).finish(),
97 Self::BorrowedLiteral(literal) => f.debug_tuple("Literal").field(literal).finish(),
98 Self::BorrowedCompound(compound) => f.debug_tuple("Compound").field(compound).finish(),
99 Self::BorrowedOptional {
100 format: should_format,
101 item,
102 } => f
103 .debug_struct("Optional")
104 .field("should_format", should_format)
105 .field("item", item)
106 .finish(),
107 Self::BorrowedFirst(items) => f.debug_tuple("First").field(items).finish(),
108 #[cfg(feature = "alloc")]
109 Self::OwnedLiteral(literal) => f.debug_tuple("Literal").field(literal).finish(),
110 #[cfg(feature = "alloc")]
111 Self::OwnedCompound(compound) => f.debug_tuple("Compound").field(compound).finish(),
112 #[cfg(feature = "alloc")]
113 Self::OwnedOptional {
114 format: should_format,
115 item,
116 } => f
117 .debug_struct("Optional")
118 .field("should_format", should_format)
119 .field("item", item)
120 .finish(),
121 #[cfg(feature = "alloc")]
122 Self::OwnedFirst(items) => f.debug_tuple("First").field(items).finish(),
123 }
124 }
125}
126
127impl<'a> FormatDescriptionV3Inner<'a> {
128 #[cfg(feature = "alloc")]
131 fn to_owned(&self) -> FormatDescriptionV3Inner<'static> {
132 use alloc::borrow::ToOwned as _;
133 use alloc::boxed::Box;
134 use alloc::vec::Vec;
135
136 match self {
137 Self::Component(component) => FormatDescriptionV3Inner::Component(*component),
138 Self::BorrowedLiteral(literal) => {
139 FormatDescriptionV3Inner::OwnedLiteral((*literal).to_owned().into_boxed_str())
140 }
141 Self::BorrowedCompound(compound) => FormatDescriptionV3Inner::OwnedCompound(
142 compound
143 .iter()
144 .map(|v| v.to_owned())
145 .collect::<Vec<_>>()
146 .into_boxed_slice(),
147 ),
148 Self::BorrowedOptional { format, item } => FormatDescriptionV3Inner::OwnedOptional {
149 format: *format,
150 item: Box::new((*item).to_owned()),
151 },
152 Self::BorrowedFirst(items) => FormatDescriptionV3Inner::OwnedFirst(
153 items
154 .iter()
155 .map(|v| v.to_owned())
156 .collect::<Vec<_>>()
157 .into_boxed_slice(),
158 ),
159 Self::OwnedLiteral(literal) => FormatDescriptionV3Inner::OwnedLiteral(literal.clone()),
160 Self::OwnedCompound(compound) => FormatDescriptionV3Inner::OwnedCompound(
161 compound
162 .into_iter()
163 .map(|v| v.to_owned())
164 .collect::<Vec<_>>()
165 .into_boxed_slice(),
166 ),
167 Self::OwnedOptional { format, item } => FormatDescriptionV3Inner::OwnedOptional {
168 format: *format,
169 item: Box::new((**item).to_owned()),
170 },
171 Self::OwnedFirst(items) => FormatDescriptionV3Inner::OwnedFirst(
172 items
173 .into_iter()
174 .map(|v| v.to_owned())
175 .collect::<Vec<_>>()
176 .into_boxed_slice(),
177 ),
178 }
179 }
180
181 #[inline]
183 pub const fn into_opaque(self) -> FormatDescriptionV3<'a> {
184 FormatDescriptionV3 {
185 #[cfg(feature = "formatting")]
186 max_bytes_needed: self.max_bytes_needed(),
187 inner: self,
188 }
189 }
190
191 #[cfg(feature = "formatting")]
194 const fn max_bytes_needed(&self) -> usize {
195 match self {
196 FormatDescriptionV3Inner::Component(component) => component.max_bytes_needed(),
197 FormatDescriptionV3Inner::BorrowedLiteral(s) => s.len(),
198 FormatDescriptionV3Inner::BorrowedCompound(items) => {
199 let mut max_bytes_needed = 0;
200 let mut idx = 0;
201 while idx < items.len() {
202 max_bytes_needed += items[idx].max_bytes_needed();
203 idx += 1;
204 }
205 max_bytes_needed
206 }
207 FormatDescriptionV3Inner::BorrowedOptional { format, item } => {
208 if *format {
209 item.max_bytes_needed()
210 } else {
211 0
212 }
213 }
214 FormatDescriptionV3Inner::BorrowedFirst(items) => {
215 if items.is_empty() {
216 0
217 } else {
218 items[0].max_bytes_needed()
219 }
220 }
221 FormatDescriptionV3Inner::OwnedLiteral(s) => s.len(),
222 FormatDescriptionV3Inner::OwnedCompound(items) => {
223 let mut max_bytes_needed = 0;
224 let mut idx = 0;
225 while idx < items.len() {
226 max_bytes_needed += items[idx].max_bytes_needed();
227 idx += 1;
228 }
229 max_bytes_needed
230 }
231 FormatDescriptionV3Inner::OwnedOptional { format, item } => {
232 if *format {
233 item.max_bytes_needed()
234 } else {
235 0
236 }
237 }
238 FormatDescriptionV3Inner::OwnedFirst(items) => {
239 if items.is_empty() {
240 0
241 } else {
242 items[0].max_bytes_needed()
243 }
244 }
245 }
246 }
247}
248
249#[non_exhaustive]
252#[derive(Debug, Clone, Copy)]
253pub enum Component {
254 Day(modifier::Day),
256 MonthShort(modifier::MonthShort),
258 MonthLong(modifier::MonthLong),
260 MonthNumerical(modifier::MonthNumerical),
262 Ordinal(modifier::Ordinal),
264 WeekdayShort(modifier::WeekdayShort),
266 WeekdayLong(modifier::WeekdayLong),
268 WeekdaySunday(modifier::WeekdaySunday),
270 WeekdayMonday(modifier::WeekdayMonday),
272 WeekNumberIso(modifier::WeekNumberIso),
275 WeekNumberSunday(modifier::WeekNumberSunday),
277 WeekNumberMonday(modifier::WeekNumberMonday),
279 CalendarYearFullExtendedRange(modifier::CalendarYearFullExtendedRange),
281 CalendarYearFullStandardRange(modifier::CalendarYearFullStandardRange),
283 IsoYearFullExtendedRange(modifier::IsoYearFullExtendedRange),
285 IsoYearFullStandardRange(modifier::IsoYearFullStandardRange),
287 CalendarYearCenturyExtendedRange(modifier::CalendarYearCenturyExtendedRange),
289 CalendarYearCenturyStandardRange(modifier::CalendarYearCenturyStandardRange),
291 IsoYearCenturyExtendedRange(modifier::IsoYearCenturyExtendedRange),
293 IsoYearCenturyStandardRange(modifier::IsoYearCenturyStandardRange),
295 CalendarYearLastTwo(modifier::CalendarYearLastTwo),
297 IsoYearLastTwo(modifier::IsoYearLastTwo),
299 Hour12(modifier::Hour12),
301 Hour24(modifier::Hour24),
303 Minute(modifier::Minute),
305 Period(modifier::Period),
307 Second(modifier::Second),
309 Subsecond(modifier::Subsecond),
311 OffsetHour(modifier::OffsetHour),
313 OffsetMinute(modifier::OffsetMinute),
315 OffsetSecond(modifier::OffsetSecond),
317 Ignore(modifier::Ignore),
319 UnixTimestampSecond(modifier::UnixTimestampSecond),
321 UnixTimestampMillisecond(modifier::UnixTimestampMillisecond),
323 UnixTimestampMicrosecond(modifier::UnixTimestampMicrosecond),
325 UnixTimestampNanosecond(modifier::UnixTimestampNanosecond),
327 End(modifier::End),
330}
331
332impl Component {
333 #[cfg(feature = "formatting")]
334 const fn max_bytes_needed(&self) -> usize {
335 match self {
336 Self::Day(_) => 2,
337 Self::MonthShort(_) => 3,
338 Self::MonthLong(_) => 9,
339 Self::MonthNumerical(_) => 2,
340 Self::Ordinal(_) => 3,
341 Self::WeekdayShort(_) => 3,
342 Self::WeekdayLong(_) => 9,
343 Self::WeekdaySunday(_) | Self::WeekdayMonday(_) => 1,
344 Self::WeekNumberIso(_) | Self::WeekNumberSunday(_) | Self::WeekNumberMonday(_) => 2,
345 Self::CalendarYearFullExtendedRange(_) => 7,
346 Self::CalendarYearFullStandardRange(_) => 5,
347 Self::IsoYearFullExtendedRange(_) => 7,
348 Self::IsoYearFullStandardRange(_) => 5,
349 Self::CalendarYearCenturyExtendedRange(_) => 5,
350 Self::CalendarYearCenturyStandardRange(_) => 3,
351 Self::IsoYearCenturyExtendedRange(_) => 5,
352 Self::IsoYearCenturyStandardRange(_) => 3,
353 Self::CalendarYearLastTwo(_) => 2,
354 Self::IsoYearLastTwo(_) => 2,
355 Self::Hour12(_) | Self::Hour24(_) => 2,
356 Self::Minute(_) | Self::Period(_) | Self::Second(_) => 2,
357 Self::Subsecond(modifier) => match modifier.digits {
358 modifier::SubsecondDigits::One => 1,
359 modifier::SubsecondDigits::Two => 2,
360 modifier::SubsecondDigits::Three => 3,
361 modifier::SubsecondDigits::Four => 4,
362 modifier::SubsecondDigits::Five => 5,
363 modifier::SubsecondDigits::Six => 6,
364 modifier::SubsecondDigits::Seven => 7,
365 modifier::SubsecondDigits::Eight => 8,
366 modifier::SubsecondDigits::Nine => 9,
367 modifier::SubsecondDigits::OneOrMore => 9,
368 },
369 Self::OffsetHour(_) => 3,
370 Self::OffsetMinute(_) | Self::OffsetSecond(_) => 2,
371 #[cfg(feature = "large-dates")]
372 Self::UnixTimestampSecond(_) => 15,
373 #[cfg(not(feature = "large-dates"))]
374 Self::UnixTimestampSecond(_) => 13,
375 #[cfg(feature = "large-dates")]
376 Self::UnixTimestampMillisecond(_) => 18,
377 #[cfg(not(feature = "large-dates"))]
378 Self::UnixTimestampMillisecond(_) => 16,
379 #[cfg(feature = "large-dates")]
380 Self::UnixTimestampMicrosecond(_) => 21,
381 #[cfg(not(feature = "large-dates"))]
382 Self::UnixTimestampMicrosecond(_) => 19,
383 #[cfg(feature = "large-dates")]
384 Self::UnixTimestampNanosecond(_) => 24,
385 #[cfg(not(feature = "large-dates"))]
386 Self::UnixTimestampNanosecond(_) => 22,
387 Self::Ignore(_) | Self::End(_) => 0,
388 }
389 }
390}