time\format_description\parse/
mod.rs1use alloc::boxed::Box;
4use alloc::vec::Vec;
5
6pub use self::strftime::{parse_strftime_borrowed, parse_strftime_owned};
7use crate::{error, format_description};
8
9macro_rules! version {
11 ($range:expr) => {
12 $range.contains(&VERSION)
13 };
14}
15
16macro_rules! validate_version {
18 ($version:ident) => {
19 #[allow(clippy::let_unit_value)]
20 let _ = $crate::format_description::parse::Version::<$version>::IS_VALID;
21 };
22}
23
24mod ast;
25mod format_item;
26mod lexer;
27mod strftime;
28
29struct Version<const N: usize>;
31impl<const N: usize> Version<N> {
32 const IS_VALID: () = assert!(N >= 1 && N <= 2);
35}
36
37pub fn parse(
46 s: &str,
47) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
48 parse_borrowed::<1>(s)
49}
50
51pub fn parse_borrowed<const VERSION: usize>(
57 s: &str,
58) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
59 validate_version!(VERSION);
60 let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
61 let ast = ast::parse::<_, VERSION>(&mut lexed);
62 let format_items = format_item::parse(ast);
63 Ok(format_items
64 .map(|res| res.and_then(TryInto::try_into))
65 .collect::<Result<_, _>>()?)
66}
67
68pub fn parse_owned<const VERSION: usize>(
79 s: &str,
80) -> Result<format_description::OwnedFormatItem, error::InvalidFormatDescription> {
81 validate_version!(VERSION);
82 let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
83 let ast = ast::parse::<_, VERSION>(&mut lexed);
84 let format_items = format_item::parse(ast);
85 let items = format_items.collect::<Result<Box<_>, _>>()?;
86 Ok(items.into())
87}
88
89fn attach_location<'item>(
91 iter: impl Iterator<Item = &'item u8>,
92) -> impl Iterator<Item = (&'item u8, Location)> {
93 let mut byte_pos = 0;
94
95 iter.map(move |byte| {
96 let location = Location { byte: byte_pos };
97 byte_pos += 1;
98 (byte, location)
99 })
100}
101
102#[derive(Clone, Copy)]
104struct Location {
105 byte: u32,
107}
108
109impl Location {
110 const fn to(self, end: Self) -> Span {
112 Span { start: self, end }
113 }
114
115 const fn to_self(self) -> Span {
117 Span {
118 start: self,
119 end: self,
120 }
121 }
122
123 #[must_use = "this does not modify the original value"]
127 const fn offset(&self, offset: u32) -> Self {
128 Self {
129 byte: self.byte + offset,
130 }
131 }
132
133 const fn error(self, message: &'static str) -> ErrorInner {
135 ErrorInner {
136 _message: message,
137 _span: Span {
138 start: self,
139 end: self,
140 },
141 }
142 }
143}
144
145#[derive(Clone, Copy)]
147struct Span {
148 #[allow(clippy::missing_docs_in_private_items)]
149 start: Location,
150 #[allow(clippy::missing_docs_in_private_items)]
151 end: Location,
152}
153
154impl Span {
155 #[must_use = "this does not modify the original value"]
157 const fn shrink_to_start(&self) -> Self {
158 Self {
159 start: self.start,
160 end: self.start,
161 }
162 }
163
164 #[must_use = "this does not modify the original value"]
166 const fn shrink_to_end(&self) -> Self {
167 Self {
168 start: self.end,
169 end: self.end,
170 }
171 }
172
173 #[must_use = "this does not modify the original value"]
175 const fn shrink_to_before(&self, pos: u32) -> Self {
176 Self {
177 start: self.start,
178 end: Location {
179 byte: self.start.byte + pos - 1,
180 },
181 }
182 }
183
184 #[must_use = "this does not modify the original value"]
186 const fn shrink_to_after(&self, pos: u32) -> Self {
187 Self {
188 start: Location {
189 byte: self.start.byte + pos + 1,
190 },
191 end: self.end,
192 }
193 }
194
195 const fn error(self, message: &'static str) -> ErrorInner {
197 ErrorInner {
198 _message: message,
199 _span: self,
200 }
201 }
202}
203
204#[derive(Clone, Copy)]
206struct Spanned<T> {
207 value: T,
209 span: Span,
211}
212
213impl<T> core::ops::Deref for Spanned<T> {
214 type Target = T;
215
216 fn deref(&self) -> &Self::Target {
217 &self.value
218 }
219}
220
221trait SpannedValue: Sized {
223 fn spanned(self, span: Span) -> Spanned<Self>;
225}
226
227impl<T> SpannedValue for T {
228 fn spanned(self, span: Span) -> Spanned<Self> {
229 Spanned { value: self, span }
230 }
231}
232
233struct ErrorInner {
235 _message: &'static str,
237 _span: Span,
239}
240
241struct Error {
243 _inner: Unused<ErrorInner>,
245 public: error::InvalidFormatDescription,
247}
248
249impl From<Error> for error::InvalidFormatDescription {
250 fn from(error: Error) -> Self {
251 error.public
252 }
253}
254
255struct Unused<T>(core::marker::PhantomData<T>);
261
262fn unused<T>(_: T) -> Unused<T> {
264 Unused(core::marker::PhantomData)
265}