time/format_description/parse/
mod.rs1use alloc::vec::Vec;
4
5use self::lexer_ast::parse_generic;
6use self::sealed::{Version, VersionedParser};
7pub use self::strftime::{parse_strftime_borrowed, parse_strftime_owned};
8use crate::error;
9use crate::format_description::{BorrowedFormatItem, FormatDescriptionV3, OwnedFormatItem};
10
11macro_rules! version {
12 ($pat:pat) => {
13 const { matches!(VERSION, $pat) }
14 };
15}
16
17macro_rules! assert_version {
18 () => {
19 const {
20 assert!(matches!(VERSION, 1..=3), "invalid version provided");
21 }
22 };
23}
24
25mod format_item;
26mod lexer_ast;
27mod strftime;
28
29mod sealed {
30 use super::*;
31
32 #[expect(
34 missing_debug_implementations,
35 reason = "only used at the type level; not public API"
36 )]
37 pub struct Version<const N: usize>;
38
39 pub trait VersionedParser {
42 type BorrowedOutput<'input>;
44
45 type OwnedOutput;
47
48 fn parse_borrowed(
50 s: &str,
51 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription>;
52
53 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription>;
56 }
57}
58
59impl VersionedParser for Version<1> {
60 type BorrowedOutput<'input> = Vec<BorrowedFormatItem<'input>>;
61 type OwnedOutput = OwnedFormatItem;
62
63 #[inline]
64 fn parse_borrowed(
65 s: &str,
66 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
67 Ok(parse_generic::<1, false>(s)?)
68 }
69
70 #[inline]
71 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
72 Ok(parse_generic::<1, true>(s)?)
73 }
74}
75
76impl VersionedParser for Version<2> {
77 type BorrowedOutput<'input> = Vec<BorrowedFormatItem<'input>>;
78 type OwnedOutput = OwnedFormatItem;
79
80 #[inline]
81 fn parse_borrowed(
82 s: &str,
83 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
84 Ok(parse_generic::<2, false>(s)?)
85 }
86
87 #[inline]
88 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
89 Ok(parse_generic::<2, true>(s)?)
90 }
91}
92
93impl VersionedParser for Version<3> {
94 type BorrowedOutput<'input> = FormatDescriptionV3<'input>;
95 type OwnedOutput = FormatDescriptionV3<'static>;
96
97 #[inline]
98 fn parse_borrowed(
99 s: &str,
100 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
101 Ok(parse_generic::<3, false>(s)?)
102 }
103
104 #[inline]
105 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
106 Ok(parse_generic::<3, true>(s)?)
107 }
108}
109
110#[deprecated(
118 since = "0.3.48",
119 note = "use `parse_borrowed` with the appropriate version for clarity"
120)]
121#[inline]
122pub fn parse(s: &str) -> Result<Vec<BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
123 parse_borrowed::<1>(s)
124}
125
126#[inline]
141pub fn parse_borrowed<const VERSION: usize>(
142 s: &str,
143) -> Result<
144 <Version<VERSION> as VersionedParser>::BorrowedOutput<'_>,
145 error::InvalidFormatDescription,
146>
147where
148 Version<VERSION>: VersionedParser,
149{
150 Version::<VERSION>::parse_borrowed(s)
151}
152
153#[inline]
173pub fn parse_owned<const VERSION: usize>(
174 s: &str,
175) -> Result<<Version<VERSION> as VersionedParser>::OwnedOutput, error::InvalidFormatDescription>
176where
177 Version<VERSION>: VersionedParser,
178{
179 Version::<VERSION>::parse_owned(s)
180}
181
182#[derive(Clone, Copy)]
184struct Location {
185 byte: u32,
187}
188
189impl Location {
190 const DUMMY: Self = Self { byte: u32::MAX };
191
192 #[inline]
194 const fn to(self, end: Self) -> Span {
195 Span { start: self, end }
196 }
197
198 #[inline]
200 const fn to_self(self) -> Span {
201 Span {
202 start: self,
203 end: self,
204 }
205 }
206
207 #[inline]
208 const fn with_length(self, length: usize) -> Span {
209 Span {
210 start: self,
211 end: Self {
212 byte: self.byte + length as u32 - 1,
213 },
214 }
215 }
216
217 #[must_use = "this does not modify the original value"]
221 #[inline]
222 const fn offset(&self, offset: u32) -> Self {
223 Self {
224 byte: self.byte + offset,
225 }
226 }
227
228 #[inline]
230 const fn error(self, message: &'static str) -> ErrorInner {
231 ErrorInner {
232 _message: message,
233 _span: Span {
234 start: self,
235 end: self,
236 },
237 }
238 }
239}
240
241#[derive(Clone, Copy)]
243struct WithLocation<T> {
244 value: T,
246 location: Location,
248}
249
250impl<T> core::ops::Deref for WithLocation<T> {
251 type Target = T;
252
253 #[inline]
254 fn deref(&self) -> &Self::Target {
255 &self.value
256 }
257}
258
259trait WithLocationValue: Sized {
261 fn with_location(self, location: Location) -> WithLocation<Self>;
263}
264
265impl<T> WithLocationValue for T {
266 #[inline]
267 fn with_location(self, location: Location) -> WithLocation<Self> {
268 WithLocation {
269 value: self,
270 location,
271 }
272 }
273}
274
275#[derive(Clone, Copy)]
277struct Span {
278 start: Location,
279 end: Location,
280}
281
282impl Span {
283 const DUMMY: Self = Self {
284 start: Location { byte: u32::MAX },
285 end: Location { byte: u32::MAX },
286 };
287
288 #[must_use = "this does not modify the original value"]
290 #[inline]
291 const fn shrink_to_start(&self) -> Self {
292 Self {
293 start: self.start,
294 end: self.start,
295 }
296 }
297
298 #[must_use = "this does not modify the original value"]
300 const fn shrink_to_end(&self) -> Self {
301 Self {
302 start: self.end,
303 end: self.end,
304 }
305 }
306
307 #[inline]
309 const fn error(self, message: &'static str) -> ErrorInner {
310 ErrorInner {
311 _message: message,
312 _span: self,
313 }
314 }
315}
316
317#[derive(Clone, Copy)]
319struct Spanned<T> {
320 value: T,
322 span: Span,
324}
325
326impl<T> core::ops::Deref for Spanned<T> {
327 type Target = T;
328
329 #[inline]
330 fn deref(&self) -> &Self::Target {
331 &self.value
332 }
333}
334
335impl<T> Spanned<T> {
336 #[inline]
337 fn map<F, U>(self, f: F) -> Spanned<U>
338 where
339 F: FnOnce(T) -> U,
340 {
341 Spanned {
342 value: f(self.value),
343 span: self.span,
344 }
345 }
346}
347
348trait OptionExt<T> {
349 fn transpose(self) -> Spanned<Option<T>>;
350}
351
352impl<T> OptionExt<T> for Option<Spanned<T>> {
353 #[inline]
354 fn transpose(self) -> Spanned<Option<T>> {
355 match self {
356 Some(spanned) => Spanned {
357 value: Some(spanned.value),
358 span: spanned.span,
359 },
360 None => Spanned {
361 value: None,
362 span: Span::DUMMY,
363 },
364 }
365 }
366}
367
368trait SpannedValue: Sized {
370 fn spanned(self, span: Span) -> Spanned<Self>;
372}
373
374impl<T> SpannedValue for T {
375 #[inline]
376 fn spanned(self, span: Span) -> Spanned<Self> {
377 Spanned { value: self, span }
378 }
379}
380
381struct ErrorInner {
383 _message: &'static str,
385 _span: Span,
387}
388
389struct Error {
391 _inner: Unused<ErrorInner>,
393 public: error::InvalidFormatDescription,
395}
396
397impl From<Error> for error::InvalidFormatDescription {
398 #[inline]
399 fn from(error: Error) -> Self {
400 error.public
401 }
402}
403
404impl From<core::convert::Infallible> for Error {
405 #[inline]
406 fn from(v: core::convert::Infallible) -> Self {
407 match v {}
408 }
409}
410
411struct Unused<T>(core::marker::PhantomData<T>);
417
418#[inline]
420fn unused<T>(_: T) -> Unused<T> {
421 Unused(core::marker::PhantomData)
422}