1//! Parser for format descriptions.
23use alloc::boxed::Box;
4use alloc::vec::Vec;
56pub use self::strftime::{parse_strftime_borrowed, parse_strftime_owned};
7use crate::{error, format_description};
89/// A helper macro to make version restrictions simpler to read and write.
10macro_rules! version {
11 ($range:expr) => {
12$range.contains(&VERSION)
13 };
14}
1516/// A helper macro to statically validate the version (when used as a const parameter).
17macro_rules! validate_version {
18 ($version:ident) => {
19const {
20assert!($version >= 1 && $version <= 2);
21 }
22 };
23}
2425mod ast;
26mod format_item;
27mod lexer;
28mod strftime;
2930/// Parse a sequence of items from the format description.
31///
32/// The syntax for the format description can be found in [the
33/// book](https://time-rs.github.io/book/api/format-description.html).
34///
35/// This function exists for backward compatibility reasons. It is equivalent to calling
36/// `parse_borrowed::<1>(s)`. In the future, this function will be deprecated in favor of
37/// `parse_borrowed`.
38#[inline]
39pub fn parse(
40 s: &str,
41) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
42parse_borrowed::<1>(s)
43}
4445/// Parse a sequence of items from the format description.
46///
47/// The syntax for the format description can be found in [the
48/// book](https://time-rs.github.io/book/api/format-description.html). The version of the format
49/// description is provided as the const parameter. **It is recommended to use version 2.**
50#[inline]
51pub fn parse_borrowed<const VERSION: usize>(
52 s: &str,
53) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
54const {
if !(VERSION >= 1 && VERSION <= 2) {
::core::panicking::panic("assertion failed: VERSION >= 1 && VERSION <= 2")
};
};validate_version!(VERSION);
55let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
56let ast = ast::parse::<_, VERSION>(&mut lexed);
57let format_items = format_item::parse(ast);
58Ok(format_items59 .map(|res| res.and_then(TryInto::try_into))
60 .collect::<Result<_, _>>()?)
61}
6263/// Parse a sequence of items from the format description.
64///
65/// The syntax for the format description can be found in [the
66/// book](https://time-rs.github.io/book/api/format-description.html). The version of the format
67/// description is provided as the const parameter.
68///
69/// Unlike [`parse`], this function returns [`OwnedFormatItem`], which owns its contents. This means
70/// that there is no lifetime that needs to be handled. **It is recommended to use version 2.**
71///
72/// [`OwnedFormatItem`]: crate::format_description::OwnedFormatItem
73#[inline]
74pub fn parse_owned<const VERSION: usize>(
75 s: &str,
76) -> Result<format_description::OwnedFormatItem, error::InvalidFormatDescription> {
77const {
if !(VERSION >= 1 && VERSION <= 2) {
::core::panicking::panic("assertion failed: VERSION >= 1 && VERSION <= 2")
};
};validate_version!(VERSION);
78let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
79let ast = ast::parse::<_, VERSION>(&mut lexed);
80let format_items = format_item::parse(ast);
81let items = format_items.collect::<Result<Box<_>, _>>()?;
82Ok(items.into())
83}
8485/// Attach [`Location`] information to each byte in the iterator.
86#[inline]
87fn attach_location<'item>(
88 iter: impl Iterator<Item = &'item u8>,
89) -> impl Iterator<Item = (&'item u8, Location)> {
90let mut byte_pos = 0;
9192iter.map(move |byte| {
93let location = Location { byte: byte_pos };
94byte_pos += 1;
95 (byte, location)
96 })
97}
9899/// A location within a string.
100#[derive(#[automatically_derived]
impl ::core::clone::Clone for Location {
#[inline]
fn clone(&self) -> Location {
let _: ::core::clone::AssertParamIsClone<u32>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Location { }Copy)]
101struct Location {
102/// The zero-indexed byte of the string.
103byte: u32,
104}
105106impl Location {
107/// Create a new [`Span`] from `self` to `other`.
108#[inline]
109const fn to(self, end: Self) -> Span {
110Span { start: self, end }
111 }
112113/// Create a new [`Span`] consisting entirely of `self`.
114#[inline]
115const fn to_self(self) -> Span {
116Span {
117 start: self,
118 end: self,
119 }
120 }
121122/// Offset the location by the provided amount.
123 ///
124 /// Note that this assumes the resulting location is on the same line as the original location.
125#[must_use = "this does not modify the original value"]
126 #[inline]
127const fn offset(&self, offset: u32) -> Self {
128Self {
129 byte: self.byte + offset,
130 }
131 }
132133/// Create an error with the provided message at this location.
134#[inline]
135const fn error(self, message: &'static str) -> ErrorInner {
136ErrorInner {
137 _message: message,
138 _span: Span {
139 start: self,
140 end: self,
141 },
142 }
143 }
144}
145146/// A start and end point within a string.
147#[derive(#[automatically_derived]
impl ::core::clone::Clone for Span {
#[inline]
fn clone(&self) -> Span {
let _: ::core::clone::AssertParamIsClone<Location>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for Span { }Copy)]
148struct Span {
149 start: Location,
150 end: Location,
151}
152153impl Span {
154/// Obtain a `Span` pointing at the start of the pre-existing span.
155#[must_use = "this does not modify the original value"]
156 #[inline]
157const fn shrink_to_start(&self) -> Self {
158Self {
159 start: self.start,
160 end: self.start,
161 }
162 }
163164/// Obtain a `Span` pointing at the end of the pre-existing span.
165#[must_use = "this does not modify the original value"]
166const fn shrink_to_end(&self) -> Self {
167Self {
168 start: self.end,
169 end: self.end,
170 }
171 }
172173/// Obtain a `Span` that ends before the provided position of the pre-existing span.
174#[must_use = "this does not modify the original value"]
175 #[inline]
176const fn shrink_to_before(&self, pos: u32) -> Self {
177Self {
178 start: self.start,
179 end: Location {
180 byte: self.start.byte + pos - 1,
181 },
182 }
183 }
184185/// Obtain a `Span` that starts after provided position to the end of the pre-existing span.
186#[must_use = "this does not modify the original value"]
187 #[inline]
188const fn shrink_to_after(&self, pos: u32) -> Self {
189Self {
190 start: Location {
191 byte: self.start.byte + pos + 1,
192 },
193 end: self.end,
194 }
195 }
196197/// Create an error with the provided message at this span.
198#[inline]
199const fn error(self, message: &'static str) -> ErrorInner {
200ErrorInner {
201 _message: message,
202 _span: self,
203 }
204 }
205}
206207/// A value with an associated [`Span`].
208#[derive(#[automatically_derived]
impl<T: ::core::clone::Clone> ::core::clone::Clone for Spanned<T> {
#[inline]
fn clone(&self) -> Spanned<T> {
Spanned {
value: ::core::clone::Clone::clone(&self.value),
span: ::core::clone::Clone::clone(&self.span),
}
}
}Clone, #[automatically_derived]
impl<T: ::core::marker::Copy> ::core::marker::Copy for Spanned<T> { }Copy)]
209struct Spanned<T> {
210/// The value.
211value: T,
212/// Where the value was in the format string.
213span: Span,
214}
215216impl<T> core::ops::Dereffor Spanned<T> {
217type Target = T;
218219#[inline]
220fn deref(&self) -> &Self::Target {
221&self.value
222 }
223}
224225/// Helper trait to attach a [`Span`] to a value.
226trait SpannedValue: Sized {
227/// Attach a [`Span`] to a value.
228fn spanned(self, span: Span) -> Spanned<Self>;
229}
230231impl<T> SpannedValuefor T {
232#[inline]
233fn spanned(self, span: Span) -> Spanned<Self> {
234Spanned { value: self, span }
235 }
236}
237238/// The internal error type.
239struct ErrorInner {
240/// The message displayed to the user.
241_message: &'static str,
242/// Where the error originated.
243_span: Span,
244}
245246/// A complete error description.
247struct Error {
248/// The internal error.
249_inner: Unused<ErrorInner>,
250/// The error needed for interoperability with the rest of `time`.
251public: error::InvalidFormatDescription,
252}
253254impl From<Error> for error::InvalidFormatDescription {
255#[inline]
256fn from(error: Error) -> Self {
257error.public
258 }
259}
260261/// A value that may be used in the future, but currently is not.
262///
263/// This struct exists so that data can semantically be passed around without _actually_ passing it
264/// around. This way the data still exists if it is needed in the future.
265// `PhantomData` is not used directly because we don't want to introduce any trait implementations.
266struct Unused<T>(core::marker::PhantomData<T>);
267268/// Indicate that a value is currently unused.
269#[inline]
270fn unused<T>(_: T) -> Unused<T> {
271Unused(core::marker::PhantomData)
272}