time/format_description/parse/
mod.rs1use alloc::boxed::Box;
4use alloc::vec::Vec;
5
6use crate::{error, format_description};
7
8macro_rules! version {
10 ($range:expr) => {
11 $range.contains(&VERSION)
12 };
13}
14
15macro_rules! validate_version {
17 ($version:ident) => {
18 #[allow(clippy::let_unit_value)]
19 let _ = $crate::format_description::parse::Version::<$version>::IS_VALID;
20 };
21}
22
23mod ast;
24mod format_item;
25mod lexer;
26
27struct Version<const N: usize>;
29impl<const N: usize> Version<N> {
30 const IS_VALID: () = assert!(N >= 1 && N <= 2);
33}
34
35pub fn parse(
44 s: &str,
45) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
46 parse_borrowed::<1>(s)
47}
48
49pub fn parse_borrowed<const VERSION: usize>(
55 s: &str,
56) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
57 validate_version!(VERSION);
58 let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
59 let ast = ast::parse::<_, VERSION>(&mut lexed);
60 let format_items = format_item::parse(ast);
61 Ok(format_items
62 .map(|res| res.and_then(TryInto::try_into))
63 .collect::<Result<_, _>>()?)
64}
65
66pub fn parse_owned<const VERSION: usize>(
77 s: &str,
78) -> Result<format_description::OwnedFormatItem, error::InvalidFormatDescription> {
79 validate_version!(VERSION);
80 let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
81 let ast = ast::parse::<_, VERSION>(&mut lexed);
82 let format_items = format_item::parse(ast);
83 let items = format_items.collect::<Result<Box<_>, _>>()?;
84 Ok(items.into())
85}
86
87#[derive(Clone, Copy)]
89struct Location {
90 byte: u32,
92}
93
94impl Location {
95 const fn to(self, end: Self) -> Span {
97 Span { start: self, end }
98 }
99
100 #[must_use = "this does not modify the original value"]
104 const fn offset(&self, offset: u32) -> Self {
105 Self {
106 byte: self.byte + offset,
107 }
108 }
109
110 const fn error(self, message: &'static str) -> ErrorInner {
112 ErrorInner {
113 _message: message,
114 _span: Span {
115 start: self,
116 end: self,
117 },
118 }
119 }
120}
121
122#[derive(Clone, Copy)]
124struct Span {
125 #[allow(clippy::missing_docs_in_private_items)]
126 start: Location,
127 #[allow(clippy::missing_docs_in_private_items)]
128 end: Location,
129}
130
131impl Span {
132 #[must_use = "this does not modify the original value"]
134 const fn shrink_to_start(&self) -> Self {
135 Self {
136 start: self.start,
137 end: self.start,
138 }
139 }
140
141 #[must_use = "this does not modify the original value"]
143 const fn shrink_to_end(&self) -> Self {
144 Self {
145 start: self.end,
146 end: self.end,
147 }
148 }
149
150 #[must_use = "this does not modify the original value"]
152 const fn shrink_to_before(&self, pos: u32) -> Self {
153 Self {
154 start: self.start,
155 end: Location {
156 byte: self.start.byte + pos - 1,
157 },
158 }
159 }
160
161 #[must_use = "this does not modify the original value"]
163 const fn shrink_to_after(&self, pos: u32) -> Self {
164 Self {
165 start: Location {
166 byte: self.start.byte + pos + 1,
167 },
168 end: self.end,
169 }
170 }
171
172 const fn error(self, message: &'static str) -> ErrorInner {
174 ErrorInner {
175 _message: message,
176 _span: self,
177 }
178 }
179}
180
181#[derive(Clone, Copy)]
183struct Spanned<T> {
184 value: T,
186 span: Span,
188}
189
190impl<T> core::ops::Deref for Spanned<T> {
191 type Target = T;
192
193 fn deref(&self) -> &Self::Target {
194 &self.value
195 }
196}
197
198trait SpannedValue: Sized {
200 fn spanned(self, span: Span) -> Spanned<Self>;
202}
203
204impl<T> SpannedValue for T {
205 fn spanned(self, span: Span) -> Spanned<Self> {
206 Spanned { value: self, span }
207 }
208}
209
210struct ErrorInner {
212 _message: &'static str,
214 _span: Span,
216}
217
218struct Error {
220 _inner: Unused<ErrorInner>,
222 public: error::InvalidFormatDescription,
224}
225
226impl From<Error> for error::InvalidFormatDescription {
227 fn from(error: Error) -> Self {
228 error.public
229 }
230}
231
232struct Unused<T>(core::marker::PhantomData<T>);
238
239fn unused<T>(_: T) -> Unused<T> {
241 Unused(core::marker::PhantomData)
242}