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 #[inline]
212 const fn to(self, end: Self) -> Span {
213 Span { start: self, end }
214 }
215
216 #[inline]
218 const fn to_self(self) -> Span {
219 Span {
220 start: self,
221 end: self,
222 }
223 }
224
225 #[must_use = "this does not modify the original value"]
229 #[inline]
230 const fn offset(&self, offset: u32) -> Self {
231 Self {
232 byte: self.byte + offset,
233 }
234 }
235
236 #[inline]
238 const fn error(self, message: &'static str) -> ErrorInner {
239 ErrorInner {
240 _message: message,
241 _span: Span {
242 start: self,
243 end: self,
244 },
245 }
246 }
247}
248
249#[derive(Clone, Copy)]
251struct Span {
252 start: Location,
253 end: Location,
254}
255
256impl Span {
257 const DUMMY: Self = Self {
258 start: Location { byte: u32::MAX },
259 end: Location { byte: u32::MAX },
260 };
261
262 #[must_use = "this does not modify the original value"]
264 #[inline]
265 const fn shrink_to_start(&self) -> Self {
266 Self {
267 start: self.start,
268 end: self.start,
269 }
270 }
271
272 #[must_use = "this does not modify the original value"]
274 const fn shrink_to_end(&self) -> Self {
275 Self {
276 start: self.end,
277 end: self.end,
278 }
279 }
280
281 #[inline]
283 const fn error(self, message: &'static str) -> ErrorInner {
284 ErrorInner {
285 _message: message,
286 _span: self,
287 }
288 }
289}
290
291#[derive(Clone, Copy)]
293struct Spanned<T> {
294 value: T,
296 span: Span,
298}
299
300impl<T> core::ops::Deref for Spanned<T> {
301 type Target = T;
302
303 #[inline]
304 fn deref(&self) -> &Self::Target {
305 &self.value
306 }
307}
308
309impl<T> Spanned<T> {
310 #[inline]
311 fn map<F, U>(self, f: F) -> Spanned<U>
312 where
313 F: FnOnce(T) -> U,
314 {
315 Spanned {
316 value: f(self.value),
317 span: self.span,
318 }
319 }
320}
321
322trait OptionExt<T> {
323 fn transpose(self) -> Spanned<Option<T>>;
324}
325
326impl<T> OptionExt<T> for Option<Spanned<T>> {
327 #[inline]
328 fn transpose(self) -> Spanned<Option<T>> {
329 match self {
330 Some(spanned) => Spanned {
331 value: Some(spanned.value),
332 span: spanned.span,
333 },
334 None => Spanned {
335 value: None,
336 span: Span::DUMMY,
337 },
338 }
339 }
340}
341
342trait SpannedValue: Sized {
344 fn spanned(self, span: Span) -> Spanned<Self>;
346}
347
348impl<T> SpannedValue for T {
349 #[inline]
350 fn spanned(self, span: Span) -> Spanned<Self> {
351 Spanned { value: self, span }
352 }
353}
354
355struct ErrorInner {
357 _message: &'static str,
359 _span: Span,
361}
362
363struct Error {
365 _inner: Unused<ErrorInner>,
367 public: error::InvalidFormatDescription,
369}
370
371impl From<Error> for error::InvalidFormatDescription {
372 #[inline]
373 fn from(error: Error) -> Self {
374 error.public
375 }
376}
377
378struct Unused<T>(core::marker::PhantomData<T>);
384
385#[inline]
387fn unused<T>(_: T) -> Unused<T> {
388 Unused(core::marker::PhantomData)
389}