time/format_description/parse/
mod.rs1use alloc::vec::Vec;
4
5use self::lexer_ast::Lexer;
6use self::sealed::{Version, VersionedParser};
7pub use self::strftime::{parse_strftime_borrowed, parse_strftime_owned};
8use crate::error;
9use crate::format_description::__private::FormatDescriptionV3Inner;
10use crate::format_description::{BorrowedFormatItem, FormatDescriptionV3, OwnedFormatItem};
11
12macro_rules! version {
13 ($pat:pat) => {
14 const { matches!(VERSION, $pat) }
15 };
16}
17
18macro_rules! assert_version {
19 () => {
20 const {
21 assert!(matches!(VERSION, 1..=3), "invalid version provided");
22 }
23 };
24}
25
26mod format_item;
27mod lexer_ast;
28mod strftime;
29
30mod sealed {
31 use super::*;
32
33 #[expect(
35 missing_debug_implementations,
36 reason = "only used at the type level; not public API"
37 )]
38 pub struct Version<const N: usize>;
39
40 pub trait VersionedParser {
43 type BorrowedOutput<'input>;
45
46 type OwnedOutput;
48
49 fn parse_borrowed(
51 s: &str,
52 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription>;
53
54 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription>;
57 }
58}
59
60impl VersionedParser for Version<1> {
61 type BorrowedOutput<'input> = Vec<BorrowedFormatItem<'input>>;
62 type OwnedOutput = OwnedFormatItem;
63
64 #[inline]
65 fn parse_borrowed(
66 s: &str,
67 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
68 Ok(Lexer::<1>::new(s)
69 .map(|res| res.and_then(TryInto::try_into))
70 .collect::<Result<_, _>>()?)
71 }
72
73 #[inline]
74 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
75 Ok(Lexer::<1>::new(s)
76 .collect::<Result<Vec<_>, _>>()?
77 .try_into()?)
78 }
79}
80
81impl VersionedParser for Version<2> {
82 type BorrowedOutput<'input> = Vec<BorrowedFormatItem<'input>>;
83 type OwnedOutput = OwnedFormatItem;
84
85 #[inline]
86 fn parse_borrowed(
87 s: &str,
88 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
89 Ok(Lexer::<2>::new(s)
90 .map(|res| res.and_then(TryInto::try_into))
91 .collect::<Result<_, _>>()?)
92 }
93
94 #[inline]
95 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
96 Ok(Lexer::<2>::new(s)
97 .collect::<Result<Vec<_>, _>>()?
98 .try_into()?)
99 }
100}
101
102impl VersionedParser for Version<3> {
103 type BorrowedOutput<'input> = FormatDescriptionV3<'input>;
104 type OwnedOutput = FormatDescriptionV3<'static>;
105
106 #[inline]
107 fn parse_borrowed(
108 s: &str,
109 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
110 Ok(FormatDescriptionV3Inner::OwnedCompound(
111 Lexer::<3>::new(s)
112 .map(|res| res.and_then(TryInto::try_into))
113 .collect::<Result<_, _>>()?,
114 )
115 .into_opaque())
116 }
117
118 #[inline]
119 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
120 Ok(FormatDescriptionV3Inner::OwnedCompound(
121 Lexer::<3>::new(s)
122 .map(|res| res.and_then(TryInto::try_into))
123 .collect::<Result<_, _>>()?,
124 )
125 .into_opaque()
126 .to_owned())
127 }
128}
129
130#[deprecated(
138 since = "0.3.48",
139 note = "use `parse_borrowed` with the appropriate version for clarity"
140)]
141#[inline]
142pub fn parse(s: &str) -> Result<Vec<BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
143 parse_borrowed::<1>(s)
144}
145
146#[inline]
161pub fn parse_borrowed<const VERSION: usize>(
162 s: &str,
163) -> Result<
164 <Version<VERSION> as VersionedParser>::BorrowedOutput<'_>,
165 error::InvalidFormatDescription,
166>
167where
168 Version<VERSION>: VersionedParser,
169{
170 Version::<VERSION>::parse_borrowed(s)
171}
172
173#[inline]
193pub fn parse_owned<const VERSION: usize>(
194 s: &str,
195) -> Result<<Version<VERSION> as VersionedParser>::OwnedOutput, error::InvalidFormatDescription>
196where
197 Version<VERSION>: VersionedParser,
198{
199 Version::<VERSION>::parse_owned(s)
200}
201
202#[derive(Clone, Copy)]
204struct Location {
205 byte: u32,
207}
208
209impl Location {
210 const DUMMY: Self = Self { byte: u32::MAX };
211
212 #[inline]
214 const fn to(self, end: Self) -> Span {
215 Span { start: self, end }
216 }
217
218 #[inline]
220 const fn to_self(self) -> Span {
221 Span {
222 start: self,
223 end: self,
224 }
225 }
226
227 #[inline]
228 const fn with_length(self, length: usize) -> Span {
229 Span {
230 start: self,
231 end: Self {
232 byte: self.byte + length as u32 - 1,
233 },
234 }
235 }
236
237 #[must_use = "this does not modify the original value"]
241 #[inline]
242 const fn offset(&self, offset: u32) -> Self {
243 Self {
244 byte: self.byte + offset,
245 }
246 }
247
248 #[inline]
250 const fn error(self, message: &'static str) -> ErrorInner {
251 ErrorInner {
252 _message: message,
253 _span: Span {
254 start: self,
255 end: self,
256 },
257 }
258 }
259}
260
261#[derive(Clone, Copy)]
263struct WithLocation<T> {
264 value: T,
266 location: Location,
268}
269
270impl<T> core::ops::Deref for WithLocation<T> {
271 type Target = T;
272
273 #[inline]
274 fn deref(&self) -> &Self::Target {
275 &self.value
276 }
277}
278
279trait WithLocationValue: Sized {
281 fn with_location(self, location: Location) -> WithLocation<Self>;
283}
284
285impl<T> WithLocationValue for T {
286 #[inline]
287 fn with_location(self, location: Location) -> WithLocation<Self> {
288 WithLocation {
289 value: self,
290 location,
291 }
292 }
293}
294
295#[derive(Clone, Copy)]
297struct Span {
298 start: Location,
299 end: Location,
300}
301
302impl Span {
303 const DUMMY: Self = Self {
304 start: Location { byte: u32::MAX },
305 end: Location { byte: u32::MAX },
306 };
307
308 #[must_use = "this does not modify the original value"]
310 #[inline]
311 const fn shrink_to_start(&self) -> Self {
312 Self {
313 start: self.start,
314 end: self.start,
315 }
316 }
317
318 #[must_use = "this does not modify the original value"]
320 const fn shrink_to_end(&self) -> Self {
321 Self {
322 start: self.end,
323 end: self.end,
324 }
325 }
326
327 #[inline]
329 const fn error(self, message: &'static str) -> ErrorInner {
330 ErrorInner {
331 _message: message,
332 _span: self,
333 }
334 }
335}
336
337#[derive(Clone, Copy)]
339struct Spanned<T> {
340 value: T,
342 span: Span,
344}
345
346impl<T> core::ops::Deref for Spanned<T> {
347 type Target = T;
348
349 #[inline]
350 fn deref(&self) -> &Self::Target {
351 &self.value
352 }
353}
354
355impl<T> Spanned<T> {
356 #[inline]
357 fn map<F, U>(self, f: F) -> Spanned<U>
358 where
359 F: FnOnce(T) -> U,
360 {
361 Spanned {
362 value: f(self.value),
363 span: self.span,
364 }
365 }
366}
367
368trait OptionExt<T> {
369 fn transpose(self) -> Spanned<Option<T>>;
370}
371
372impl<T> OptionExt<T> for Option<Spanned<T>> {
373 #[inline]
374 fn transpose(self) -> Spanned<Option<T>> {
375 match self {
376 Some(spanned) => Spanned {
377 value: Some(spanned.value),
378 span: spanned.span,
379 },
380 None => Spanned {
381 value: None,
382 span: Span::DUMMY,
383 },
384 }
385 }
386}
387
388trait SpannedValue: Sized {
390 fn spanned(self, span: Span) -> Spanned<Self>;
392}
393
394impl<T> SpannedValue for T {
395 #[inline]
396 fn spanned(self, span: Span) -> Spanned<Self> {
397 Spanned { value: self, span }
398 }
399}
400
401struct ErrorInner {
403 _message: &'static str,
405 _span: Span,
407}
408
409struct Error {
411 _inner: Unused<ErrorInner>,
413 public: error::InvalidFormatDescription,
415}
416
417impl From<Error> for error::InvalidFormatDescription {
418 #[inline]
419 fn from(error: Error) -> Self {
420 error.public
421 }
422}
423
424struct Unused<T>(core::marker::PhantomData<T>);
430
431#[inline]
433fn unused<T>(_: T) -> Unused<T> {
434 Unused(core::marker::PhantomData)
435}