solar_data_structures/
fmt.rs1use std::{cell::Cell, fmt};
2
3#[cfg(feature = "nightly")]
5pub fn from_fn<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result>(
6 f: F,
7) -> impl fmt::Debug + fmt::Display {
8 fmt::from_fn(f)
9}
10
11#[cfg(not(feature = "nightly"))]
13pub fn from_fn<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result>(
14 f: F,
15) -> impl fmt::Debug + fmt::Display {
16 struct FromFn<F>(F);
17
18 impl<F> fmt::Debug for FromFn<F>
19 where
20 F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
21 {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 (self.0)(f)
24 }
25 }
26
27 impl<F> fmt::Display for FromFn<F>
28 where
29 F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result,
30 {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 (self.0)(f)
33 }
34 }
35
36 FromFn(f)
37}
38
39pub fn or_list<I>(list: I) -> impl fmt::Display
41where
42 I: IntoIterator<IntoIter: ExactSizeIterator, Item: fmt::Display>,
43{
44 let list = Cell::new(Some(list.into_iter()));
45 from_fn(move |f| {
46 let list = list.take().expect("or_list called twice");
47 let len = list.len();
48 for (i, t) in list.enumerate() {
49 if i > 0 {
50 let is_last = i == len - 1;
51 f.write_str(if len > 2 && is_last {
52 ", or "
53 } else if len == 2 && is_last {
54 " or "
55 } else {
56 ", "
57 })?;
58 }
59 write!(f, "{t}")?;
60 }
61 Ok(())
62 })
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn test_or_list() {
71 let tests: &[(&[&str], &str)] = &[
72 (&[], ""),
73 (&["`<eof>`"], "`<eof>`"),
74 (&["integer", "identifier"], "integer or identifier"),
75 (&["path", "string literal", "`&&`"], "path, string literal, or `&&`"),
76 (&["`&&`", "`||`", "`&&`", "`||`"], "`&&`, `||`, `&&`, or `||`"),
77 ];
78 for &(tokens, expected) in tests {
79 assert_eq!(or_list(tokens).to_string(), expected, "{tokens:?}");
80 }
81 }
82}