time_fmt/parse/
desc_parser.rs1use std::slice::SliceIndex;
2
3pub(crate) trait Collector {
8 type Output;
9 type Error;
10 fn spaces(&mut self) -> Result<(), Self::Error>;
12 fn day_of_week_name(&mut self) -> Result<(), Self::Error>;
14 fn month_name(&mut self) -> Result<(), Self::Error>;
16 #[inline]
18 fn preferred_date_time(&mut self) -> Result<(), Self::Error> {
19 self.day_of_week_name()?;
20 self.spaces()?;
21 self.month_name()?;
22 self.spaces()?;
23 self.day_of_month()?;
24 self.spaces()?;
25 self.time_of_day()?;
26 self.spaces()?;
27 self.year()
28 }
29 fn year_prefix(&mut self) -> Result<(), Self::Error>;
31 fn day_of_month(&mut self) -> Result<(), Self::Error>;
33 #[inline]
35 fn date_mmddyy_slash(&mut self) -> Result<(), Self::Error> {
36 self.month_of_year()?;
37 self.spaces()?;
38 self.static_str("/")?;
39 self.spaces()?;
40 self.day_of_month()?;
41 self.spaces()?;
42 self.static_str("/")?;
43 self.spaces()?;
44 self.year_suffix()
45 }
46 #[inline]
48 fn date_yyyymmdd_hyphen(&mut self) -> Result<(), Self::Error> {
49 self.year()?;
50 self.static_str("-")?;
51 self.month_of_year()?;
52 self.static_str("-")?;
53 self.day_of_month()
54 }
55 fn hour_of_day(&mut self) -> Result<(), Self::Error>;
57 fn hour_of_day_12(&mut self) -> Result<(), Self::Error>;
59 fn day_of_year(&mut self) -> Result<(), Self::Error>;
61 fn month_of_year(&mut self) -> Result<(), Self::Error>;
63 fn minute_of_hour(&mut self) -> Result<(), Self::Error>;
65 #[inline]
67 fn new_line(&mut self) -> Result<(), Self::Error> {
68 self.spaces()
69 }
70 fn ampm(&mut self) -> Result<(), Self::Error>;
72 #[inline]
74 fn time_ampm(&mut self) -> Result<(), Self::Error> {
75 self.hour_of_day_12()?;
76 self.spaces()?;
77 self.static_str(":")?;
78 self.spaces()?;
79 self.minute_of_hour()?;
80 self.spaces()?;
81 self.static_str(":")?;
82 self.spaces()?;
83 self.second_of_minute()?;
84 self.spaces()?;
85 self.ampm()
86 }
87 #[inline]
89 fn hour_minute_of_day(&mut self) -> Result<(), Self::Error> {
90 self.hour_of_day()?;
91 self.spaces()?;
92 self.static_str(":")?;
93 self.spaces()?;
94 self.minute_of_hour()
95 }
96 fn second_of_minute(&mut self) -> Result<(), Self::Error>;
98 fn nanosecond_of_second(&mut self) -> Result<(), Self::Error>;
100 #[inline]
102 fn tab(&mut self) -> Result<(), Self::Error> {
103 self.spaces()
104 }
105 #[inline]
107 fn time_of_day(&mut self) -> Result<(), Self::Error> {
108 self.hour_of_day()?;
109 self.spaces()?;
110 self.static_str(":")?;
111 self.spaces()?;
112 self.minute_of_hour()?;
113 self.spaces()?;
114 self.static_str(":")?;
115 self.spaces()?;
116 self.second_of_minute()
117 }
118 fn week_number_of_current_year_start_sunday(&mut self) -> Result<(), Self::Error>;
120 fn day_of_week_from_sunday_as_0(&mut self) -> Result<(), Self::Error>;
122 fn week_number_of_current_year_start_monday(&mut self) -> Result<(), Self::Error>;
124 #[inline]
126 fn preferred_date(&mut self) -> Result<(), Self::Error> {
127 self.month_of_year()?;
128 self.static_str("/")?;
129 self.day_of_month()?;
130 self.static_str("/")?;
131 self.year_suffix()
132 }
133 #[inline]
135 fn preferred_time_of_day(&mut self) -> Result<(), Self::Error> {
136 self.hour_of_day()?;
137 self.static_str(":")?;
138 self.minute_of_hour()?;
139 self.static_str(":")?;
140 self.second_of_minute()
141 }
142 fn year_suffix(&mut self) -> Result<(), Self::Error>;
144 fn year(&mut self) -> Result<(), Self::Error>;
146 fn timezone(&mut self) -> Result<(), Self::Error>;
148 fn timezone_name(&mut self) -> Result<(), Self::Error>;
150 #[inline]
152 fn percent(&mut self) -> Result<(), Self::Error> {
153 self.static_str("%")
154 }
155 fn static_str(&mut self, s: &'static str) -> Result<(), Self::Error>;
158 fn literal(
163 &mut self,
164 lit: &str,
165 fmt_span: impl SliceIndex<[u8], Output = [u8]>,
166 ) -> Result<(), Self::Error>;
167 fn unknown(&mut self, specifier: char) -> Result<(), Self::Error>;
169
170 fn unconsumed_input(&self) -> Result<(), Self::Error>;
172
173 fn output(self) -> Result<Self::Output, Self::Error>;
175}
176
177pub(crate) fn parse_format_specifications<C: Collector>(
178 mut format: &str,
179 mut collector: C,
180 strict: bool,
181) -> Result<C::Output, C::Error> {
182 let original_len = format.len();
183 while !format.is_empty() {
184 let i = format
185 .find(|c: char| c == '%' || c.is_whitespace())
186 .unwrap_or(format.len());
187 if i > 0 {
188 let start = original_len - format.len();
189 let (lit, rest) = format.split_at(i);
190 collector.literal(lit, start..(start + i))?;
191 format = rest;
192 if format.is_empty() {
193 break;
194 }
195 }
196 if format.starts_with(char::is_whitespace) {
197 collector.spaces()?;
198 format = format.trim_start();
199 continue;
200 }
201 assert_eq!(format.as_bytes()[0], b'%');
202 format = &format[1..];
203 if let Some(b) = format.bytes().next() {
204 match b {
205 b'a' | b'A' => collector.day_of_week_name()?,
206 b'b' | b'B' | b'h' => collector.month_name()?,
207 b'c' => collector.preferred_date_time()?,
208 b'C' => collector.year_prefix()?,
209 b'd' | b'e' => collector.day_of_month()?,
210 b'D' => collector.date_mmddyy_slash()?,
211 b'F' => collector.date_yyyymmdd_hyphen()?,
212 b'H' | b'k' => collector.hour_of_day()?,
213 b'I' | b'l' => collector.hour_of_day_12()?,
214 b'j' => collector.day_of_year()?,
215 b'm' => collector.month_of_year()?,
216 b'M' => collector.minute_of_hour()?,
217 b'n' => collector.new_line()?,
218 b'p' | b'P' => collector.ampm()?,
219 b'r' => collector.time_ampm()?,
220 b'R' => collector.hour_minute_of_day()?,
221 b'S' => collector.second_of_minute()?,
222 b'f' => collector.nanosecond_of_second()?,
223 b't' => collector.tab()?,
224 b'T' => collector.time_of_day()?,
225 b'U' => collector.week_number_of_current_year_start_sunday()?,
226 b'w' => collector.day_of_week_from_sunday_as_0()?,
227 b'W' => collector.week_number_of_current_year_start_monday()?,
228 b'x' => collector.preferred_date()?,
229 b'X' => collector.preferred_time_of_day()?,
230 b'y' => collector.year_suffix()?,
231 b'Y' => collector.year()?,
232 b'z' => collector.timezone()?,
233 b'Z' => collector.timezone_name()?,
234 b'%' => collector.percent()?,
235 _ => {
236 let c = format.chars().next().unwrap();
237 collector.unknown(c)?;
238 format = &format[c.len_utf8()..];
239 continue;
240 }
241 }
242 format = &format[1..];
243 } else {
244 collector.percent()?;
245 }
246 }
247
248 if strict {
249 collector.unconsumed_input()?;
250 };
251
252 collector.output()
253}