Skip to main content

pub_just/
list.rs

1use super::*;
2
3pub struct List<T: Display, I: Iterator<Item = T> + Clone> {
4  conjunction: &'static str,
5  values: I,
6}
7
8impl<T: Display, I: Iterator<Item = T> + Clone> List<T, I> {
9  pub fn or<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> Self {
10    Self {
11      conjunction: "or",
12      values: values.into_iter(),
13    }
14  }
15
16  pub fn and<II: IntoIterator<Item = T, IntoIter = I>>(values: II) -> Self {
17    Self {
18      conjunction: "and",
19      values: values.into_iter(),
20    }
21  }
22
23  pub fn or_ticked<II: IntoIterator<Item = T, IntoIter = I>>(
24    values: II,
25  ) -> List<Enclosure<T>, impl Iterator<Item = Enclosure<T>> + Clone> {
26    List::or(values.into_iter().map(Enclosure::tick))
27  }
28
29  pub fn and_ticked<II: IntoIterator<Item = T, IntoIter = I>>(
30    values: II,
31  ) -> List<Enclosure<T>, impl Iterator<Item = Enclosure<T>> + Clone> {
32    List::and(values.into_iter().map(Enclosure::tick))
33  }
34}
35
36impl<T: Display, I: Iterator<Item = T> + Clone> Display for List<T, I> {
37  fn fmt(&self, f: &mut Formatter) -> fmt::Result {
38    let mut values = self.values.clone().fuse();
39
40    if let Some(first) = values.next() {
41      write!(f, "{first}")?;
42    } else {
43      return Ok(());
44    }
45
46    let second = values.next();
47
48    if second.is_none() {
49      return Ok(());
50    }
51
52    let third = values.next();
53
54    if let (Some(second), None) = (second.as_ref(), third.as_ref()) {
55      write!(f, " {} {second}", self.conjunction)?;
56      return Ok(());
57    }
58
59    let mut current = second;
60    let mut next = third;
61
62    loop {
63      match (current, next) {
64        (Some(c), Some(n)) => {
65          write!(f, ", {c}")?;
66          current = Some(n);
67          next = values.next();
68        }
69        (Some(c), None) => {
70          write!(f, ", {} {c}", self.conjunction)?;
71          return Ok(());
72        }
73        _ => unreachable!("Iterator was fused, but returned Some after None"),
74      }
75    }
76  }
77}
78
79#[cfg(test)]
80mod tests {
81  use super::*;
82
83  #[test]
84  fn or() {
85    assert_eq!("1", List::or(&[1]).to_string());
86    assert_eq!("1 or 2", List::or(&[1, 2]).to_string());
87    assert_eq!("1, 2, or 3", List::or(&[1, 2, 3]).to_string());
88    assert_eq!("1, 2, 3, or 4", List::or(&[1, 2, 3, 4]).to_string());
89  }
90
91  #[test]
92  fn and() {
93    assert_eq!("1", List::and(&[1]).to_string());
94    assert_eq!("1 and 2", List::and(&[1, 2]).to_string());
95    assert_eq!("1, 2, and 3", List::and(&[1, 2, 3]).to_string());
96    assert_eq!("1, 2, 3, and 4", List::and(&[1, 2, 3, 4]).to_string());
97  }
98
99  #[test]
100  fn or_ticked() {
101    assert_eq!("`1`", List::or_ticked(&[1]).to_string());
102    assert_eq!("`1` or `2`", List::or_ticked(&[1, 2]).to_string());
103    assert_eq!("`1`, `2`, or `3`", List::or_ticked(&[1, 2, 3]).to_string());
104    assert_eq!(
105      "`1`, `2`, `3`, or `4`",
106      List::or_ticked(&[1, 2, 3, 4]).to_string()
107    );
108  }
109
110  #[test]
111  fn and_ticked() {
112    assert_eq!("`1`", List::and_ticked(&[1]).to_string());
113    assert_eq!("`1` and `2`", List::and_ticked(&[1, 2]).to_string());
114    assert_eq!(
115      "`1`, `2`, and `3`",
116      List::and_ticked(&[1, 2, 3]).to_string()
117    );
118    assert_eq!(
119      "`1`, `2`, `3`, and `4`",
120      List::and_ticked(&[1, 2, 3, 4]).to_string()
121    );
122  }
123}