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