time/format_description/parse/
mod.rs1use alloc::boxed::Box;
4use alloc::vec::Vec;
5
6use self::sealed::{Version, VersionedParser};
7pub use self::strftime::{parse_strftime_borrowed, parse_strftime_owned};
8use super::FormatDescriptionVersion;
9use crate::{error, format_description};
10
11mod ast;
12mod format_item;
13mod lexer;
14mod strftime;
15
16mod sealed {
17 use super::*;
18
19 #[expect(
21 missing_debug_implementations,
22 reason = "only used at the type level; not public API"
23 )]
24 pub struct Version<const N: usize>;
25
26 pub trait VersionedParser {
29 type BorrowedOutput<'input>;
31
32 type OwnedOutput;
34
35 fn parse_borrowed(
37 s: &str,
38 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription>;
39
40 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription>;
43 }
44}
45
46impl VersionedParser for Version<1> {
47 type BorrowedOutput<'input> = Vec<format_description::BorrowedFormatItem<'input>>;
48 type OwnedOutput = format_description::OwnedFormatItem;
49
50 #[inline]
51 fn parse_borrowed(
52 s: &str,
53 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
54 let mut lexed = lexer::lex(FormatDescriptionVersion::V1, s.as_bytes());
55 let ast = ast::parse(FormatDescriptionVersion::V1, &mut lexed);
56 let format_items = format_item::parse(ast);
57 Ok(format_items
58 .map(|res| res.and_then(TryInto::try_into))
59 .collect::<Result<_, _>>()?)
60 }
61
62 #[inline]
63 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
64 let mut lexed = lexer::lex(FormatDescriptionVersion::V1, s.as_bytes());
65 let ast = ast::parse(FormatDescriptionVersion::V1, &mut lexed);
66 let format_items = format_item::parse(ast);
67 let items = format_items.collect::<Result<Box<_>, _>>()?;
68 Ok(items.try_into()?)
69 }
70}
71
72impl VersionedParser for Version<2> {
73 type BorrowedOutput<'input> = Vec<format_description::BorrowedFormatItem<'input>>;
74 type OwnedOutput = format_description::OwnedFormatItem;
75
76 #[inline]
77 fn parse_borrowed(
78 s: &str,
79 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
80 let mut lexed = lexer::lex(FormatDescriptionVersion::V2, s.as_bytes());
81 let ast = ast::parse(FormatDescriptionVersion::V2, &mut lexed);
82 let format_items = format_item::parse(ast);
83 Ok(format_items
84 .map(|res| res.and_then(TryInto::try_into))
85 .collect::<Result<_, _>>()?)
86 }
87
88 #[inline]
89 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
90 let mut lexed = lexer::lex(FormatDescriptionVersion::V2, s.as_bytes());
91 let ast = ast::parse(FormatDescriptionVersion::V2, &mut lexed);
92 let format_items = format_item::parse(ast);
93 let items = format_items.collect::<Result<Box<_>, _>>()?;
94 Ok(items.try_into()?)
95 }
96}
97
98impl VersionedParser for Version<3> {
99 type BorrowedOutput<'input> = format_description::FormatDescriptionV3<'input>;
100 type OwnedOutput = format_description::FormatDescriptionV3<'static>;
101
102 #[inline]
103 fn parse_borrowed(
104 s: &str,
105 ) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
106 let mut lexed = lexer::lex(FormatDescriptionVersion::V3, s.as_bytes());
107 let ast = ast::parse(FormatDescriptionVersion::V3, &mut lexed);
108 let format_items = format_item::parse(ast);
109 let items = format_items.collect::<Result<Box<_>, _>>()?;
110 let inner = format_description::__private::FormatDescriptionV3Inner::try_from(items)?;
111 Ok(inner.into_opaque())
112 }
113
114 #[inline]
115 fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
116 let mut lexed = lexer::lex(FormatDescriptionVersion::V3, s.as_bytes());
117 let ast = ast::parse(FormatDescriptionVersion::V3, &mut lexed);
118 let format_items = format_item::parse(ast);
119 let items = format_items.collect::<Result<Box<_>, _>>()?;
120 let inner = format_description::__private::FormatDescriptionV3Inner::try_from(items)?;
121 Ok(inner.into_opaque().to_owned())
122 }
123}
124
125#[deprecated(
133 since = "0.3.48",
134 note = "use `parse_borrowed` with the appropriate version for clarity"
135)]
136#[inline]
137pub fn parse(
138 s: &str,
139) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
140 parse_borrowed::<1>(s)
141}
142
143#[inline]
158pub fn parse_borrowed<const VERSION: usize>(
159 s: &str,
160) -> Result<
161 <Version<VERSION> as VersionedParser>::BorrowedOutput<'_>,
162 error::InvalidFormatDescription,
163>
164where
165 Version<VERSION>: VersionedParser,
166{
167 Version::<VERSION>::parse_borrowed(s)
168}
169
170#[inline]
190pub fn parse_owned<const VERSION: usize>(
191 s: &str,
192) -> Result<<Version<VERSION> as VersionedParser>::OwnedOutput, error::InvalidFormatDescription>
193where
194 Version<VERSION>: VersionedParser,
195{
196 Version::<VERSION>::parse_owned(s)
197}
198
199#[inline]
201fn attach_location<'item>(
202 iter: impl Iterator<Item = &'item u8>,
203) -> impl Iterator<Item = (&'item u8, Location)> {
204 let mut byte_pos = 0;
205
206 iter.map(move |byte| {
207 let location = Location { byte: byte_pos };
208 byte_pos += 1;
209 (byte, location)
210 })
211}
212
213#[derive(Clone, Copy)]
215struct Location {
216 byte: u32,
218}
219
220impl Location {
221 #[inline]
223 const fn to(self, end: Self) -> Span {
224 Span { start: self, end }
225 }
226
227 #[inline]
229 const fn to_self(self) -> Span {
230 Span {
231 start: self,
232 end: self,
233 }
234 }
235
236 #[must_use = "this does not modify the original value"]
240 #[inline]
241 const fn offset(&self, offset: u32) -> Self {
242 Self {
243 byte: self.byte + offset,
244 }
245 }
246
247 #[inline]
249 const fn error(self, message: &'static str) -> ErrorInner {
250 ErrorInner {
251 _message: message,
252 _span: Span {
253 start: self,
254 end: self,
255 },
256 }
257 }
258}
259
260#[derive(Clone, Copy)]
262struct Span {
263 start: Location,
264 end: Location,
265}
266
267impl Span {
268 const DUMMY: Self = Self {
269 start: Location { byte: u32::MAX },
270 end: Location { byte: u32::MAX },
271 };
272
273 #[must_use = "this does not modify the original value"]
275 #[inline]
276 const fn shrink_to_start(&self) -> Self {
277 Self {
278 start: self.start,
279 end: self.start,
280 }
281 }
282
283 #[must_use = "this does not modify the original value"]
285 const fn shrink_to_end(&self) -> Self {
286 Self {
287 start: self.end,
288 end: self.end,
289 }
290 }
291
292 #[inline]
294 const fn error(self, message: &'static str) -> ErrorInner {
295 ErrorInner {
296 _message: message,
297 _span: self,
298 }
299 }
300}
301
302#[derive(Clone, Copy)]
304struct Spanned<T> {
305 value: T,
307 span: Span,
309}
310
311impl<T> core::ops::Deref for Spanned<T> {
312 type Target = T;
313
314 #[inline]
315 fn deref(&self) -> &Self::Target {
316 &self.value
317 }
318}
319
320impl<T> Spanned<T> {
321 #[inline]
322 fn map<F, U>(self, f: F) -> Spanned<U>
323 where
324 F: FnOnce(T) -> U,
325 {
326 Spanned {
327 value: f(self.value),
328 span: self.span,
329 }
330 }
331}
332
333trait OptionExt<T> {
334 fn transpose(self) -> Spanned<Option<T>>;
335}
336
337impl<T> OptionExt<T> for Option<Spanned<T>> {
338 #[inline]
339 fn transpose(self) -> Spanned<Option<T>> {
340 match self {
341 Some(spanned) => Spanned {
342 value: Some(spanned.value),
343 span: spanned.span,
344 },
345 None => Spanned {
346 value: None,
347 span: Span::DUMMY,
348 },
349 }
350 }
351}
352
353trait SpannedValue: Sized {
355 fn spanned(self, span: Span) -> Spanned<Self>;
357}
358
359impl<T> SpannedValue for T {
360 #[inline]
361 fn spanned(self, span: Span) -> Spanned<Self> {
362 Spanned { value: self, span }
363 }
364}
365
366struct ErrorInner {
368 _message: &'static str,
370 _span: Span,
372}
373
374struct Error {
376 _inner: Unused<ErrorInner>,
378 public: error::InvalidFormatDescription,
380}
381
382impl From<Error> for error::InvalidFormatDescription {
383 #[inline]
384 fn from(error: Error) -> Self {
385 error.public
386 }
387}
388
389struct Unused<T>(core::marker::PhantomData<T>);
395
396#[inline]
398fn unused<T>(_: T) -> Unused<T> {
399 Unused(core::marker::PhantomData)
400}