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}