1use std::{borrow::Cow, fmt, iter::Peekable};
6
7use serde_derive::Serialize;
8
9#[derive(Clone)]
34pub enum Span<'a> {
35 Content { text: Cow<'a, str>, token: FmtToken },
36 Child(&'a dyn TokenFmt<'a>),
37}
38
39impl<'a> Span<'a> {
40 pub fn new(text: impl Into<Cow<'a, str>>, token: FmtToken) -> Span<'a> {
43 Span::Content {
44 text: text.into(),
45 token,
46 }
47 }
48
49 pub fn plain(text: impl Into<Cow<'a, str>>) -> Span<'a> {
51 Span::new(text, FmtToken::Plain)
52 }
53
54 pub fn error(text: impl Into<Cow<'a, str>>) -> Span<'a> {
56 Span::new(text, FmtToken::Error)
57 }
58
59 pub fn unit(text: impl Into<Cow<'a, str>>) -> Span<'a> {
61 Span::new(text, FmtToken::Unit)
62 }
63
64 pub fn quantity(text: impl Into<Cow<'a, str>>) -> Span<'a> {
66 Span::new(text, FmtToken::Quantity)
67 }
68
69 pub fn number(text: impl Into<Cow<'a, str>>) -> Span<'a> {
71 Span::new(text, FmtToken::Number)
72 }
73
74 pub fn prop_name(text: impl Into<Cow<'a, str>>) -> Span<'a> {
76 Span::new(text, FmtToken::PropName)
77 }
78
79 pub fn user_input(text: impl Into<Cow<'a, str>>) -> Span<'a> {
81 Span::new(text, FmtToken::UserInput)
82 }
83
84 pub fn list_begin(text: impl Into<Cow<'a, str>>) -> Span<'a> {
86 Span::new(text, FmtToken::ListBegin)
87 }
88
89 pub fn list_sep(text: impl Into<Cow<'a, str>>) -> Span<'a> {
91 Span::new(text, FmtToken::ListSep)
92 }
93
94 pub fn doc_string(text: impl Into<Cow<'a, str>>) -> Span<'a> {
96 Span::new(text, FmtToken::DocString)
97 }
98
99 pub fn pow(text: impl Into<Cow<'a, str>>) -> Span<'a> {
101 Span::new(text, FmtToken::Pow)
102 }
103
104 pub fn date_time(text: impl Into<Cow<'a, str>>) -> Span<'a> {
106 Span::new(text, FmtToken::DateTime)
107 }
108
109 pub fn child(obj: &'a dyn TokenFmt<'a>) -> Span<'a> {
112 Span::Child(obj)
113 }
114
115 pub fn link(text: impl Into<Cow<'a, str>>) -> Span<'a> {
117 Span::new(text, FmtToken::Link)
118 }
119
120 pub fn keyword(text: impl Into<Cow<'a, str>>) -> Span<'a> {
122 Span::new(text, FmtToken::Keyword)
123 }
124
125 pub fn timezone(text: impl Into<Cow<'a, str>>) -> Span<'a> {
127 Span::new(text, FmtToken::TimeZone)
128 }
129
130 pub fn is_ws(&self) -> bool {
131 if let Span::Content { text, .. } = self {
132 text.ends_with(" ")
133 } else {
134 false
135 }
136 }
137}
138
139impl<'a> fmt::Debug for Span<'a> {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 match self {
142 Span::Content { text, token } => write!(f, "({:?}, {:?})", text, token),
143 Span::Child(obj) => {
144 let spans = obj.to_spans();
145 spans.fmt(f)
146 }
147 }
148 }
149}
150
151#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Serialize)]
154#[serde(rename_all = "snake_case")]
155#[non_exhaustive]
156pub enum FmtToken {
157 Plain,
160 Error,
163 Unit,
165 Quantity,
167 Number,
169 UserInput,
173 ListBegin,
176 ListSep,
180 DocString,
182 Pow,
185 PropName,
187 DateTime,
194 Link,
198 Keyword,
200 TimeZone,
202}
203
204impl FmtToken {
205 pub fn as_str(self) -> &'static str {
206 match self {
207 FmtToken::Plain => "plain",
208 FmtToken::Error => "error",
209 FmtToken::Unit => "unit",
210 FmtToken::Quantity => "quantity",
211 FmtToken::Number => "number",
212 FmtToken::UserInput => "user_input",
213 FmtToken::ListBegin => "list_begin",
214 FmtToken::ListSep => "list_sep",
215 FmtToken::DocString => "doc_string",
216 FmtToken::Pow => "pow",
217 FmtToken::PropName => "prop_name",
218 FmtToken::DateTime => "date_time",
219 FmtToken::Link => "link",
220 FmtToken::Keyword => "keyword",
221 FmtToken::TimeZone => "time_zone",
222 }
223 }
224}
225
226pub(crate) fn write_spans_string(out: &mut String, spans: &[Span]) {
227 for span in spans {
228 match span {
229 Span::Content { text, .. } => out.push_str(text),
230 Span::Child(child) => write_spans_string(out, &child.to_spans()),
231 }
232 }
233}
234
235pub trait TokenFmt<'a> {
237 fn to_spans(&'a self) -> Vec<Span<'a>>;
238
239 fn spans_to_string(&'a self) -> String {
240 let mut string = String::new();
241 write_spans_string(&mut string, &self.to_spans());
242 string
243 }
244
245 fn display(&'a self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
246 for span in self.to_spans() {
247 match span {
248 Span::Content { text, .. } => write!(fmt, "{}", text)?,
249 Span::Child(child) => child.display(fmt)?,
250 }
251 }
252 Ok(())
253 }
254}
255
256pub(crate) struct JoinIter<'a, I>
257where
258 I: Iterator,
259{
260 iter: Peekable<I>,
261 sep: Span<'a>,
262 last_was_sep: bool,
263}
264
265pub(crate) fn join<'a, I>(iter: I, sep: Span<'a>) -> impl Iterator<Item = Span<'a>>
266where
267 I: Iterator<Item = Span<'a>>,
268{
269 JoinIter {
270 iter: iter.peekable(),
271 sep,
272 last_was_sep: true,
273 }
274}
275
276impl<'a, I> Iterator for JoinIter<'a, I>
277where
278 I: Iterator<Item = Span<'a>>,
279{
280 type Item = Span<'a>;
281
282 fn next(&mut self) -> Option<Self::Item> {
283 if self.iter.peek().is_some() {
284 if self.last_was_sep {
285 self.last_was_sep = false;
286 self.iter.next()
287 } else {
288 self.last_was_sep = true;
289 Some(self.sep.clone())
290 }
291 } else {
292 None
293 }
294 }
295}
296
297pub(crate) struct FlatJoinIter<'a, I, I2>
298where
299 I: Iterator<Item = I2>,
300 I2: IntoIterator<Item = Span<'a>>,
301{
302 iter: Peekable<I>,
303 sep: Span<'a>,
304 last_was_sep: bool,
305 current: Option<I2::IntoIter>,
306}
307
308pub(crate) fn flat_join<'a, I, I2>(iter: I, sep: Span<'a>) -> impl Iterator<Item = Span<'a>>
309where
310 I: Iterator<Item = I2>,
311 I2: IntoIterator<Item = Span<'a>>,
312{
313 FlatJoinIter {
314 iter: iter.peekable(),
315 sep,
316 last_was_sep: true,
317 current: None,
318 }
319}
320
321impl<'a, I, I2> Iterator for FlatJoinIter<'a, I, I2>
322where
323 I: Iterator<Item = I2>,
324 I2: IntoIterator<Item = Span<'a>>,
325{
326 type Item = Span<'a>;
327
328 fn next(&mut self) -> Option<Self::Item> {
329 if let Some(ref mut current) = self.current {
330 if let Some(next) = current.next() {
331 return Some(next);
332 }
333 }
334 if self.iter.peek().is_some() {
335 if self.last_was_sep {
336 self.last_was_sep = false;
337 let mut new_current = self.iter.next().unwrap().into_iter();
338 let next = new_current.next();
339 self.current = Some(new_current);
340 next
341 } else {
342 self.last_was_sep = true;
343 Some(self.sep.clone())
344 }
345 } else {
346 None
347 }
348 }
349}