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