1mod minutiae;
13use minutiae::{Note, Direction, Style, DSPair};
14
15
16
17#[derive(PartialEq)]
25pub struct Row<const WIDTH: usize>([Note ; WIDTH], usize);
26
27impl <const WIDTH: usize> Row<WIDTH> {
28
29 const EMPTY_ARR: [ Note ; WIDTH ] = [ Note::Empty ; WIDTH ];
30
31 const MIN_MARGIN: usize = WIDTH/8;
45
46 fn new(loc: usize) -> Row<WIDTH> { Row(Row::<WIDTH>::EMPTY_ARR, loc) }
47
48 fn set_note(&mut self, note: Note) { self.0[self.1] = note; }
49 fn is_note_empty(&self) -> bool { self.0[self.1] == Note::Empty }
50
51 fn get_loc(&self) -> &usize { &self.1 }
53
54 fn is_empty(&self) -> bool { self.0 == Row::<WIDTH>::EMPTY_ARR }
55
56 fn is_rightmost(&self) -> bool { self.1 + 1 >= WIDTH }
57 fn is_leftmost(&self) -> bool { self.1 <= 0 }
58
59 fn go_rightmost(&mut self) { self.1 = WIDTH.saturating_sub(1) }
60 fn go_leftmost(&mut self) { self.1 = 0 }
61
62 fn go_right_unchecked(&mut self) { self.1 += 1 }
63 fn go_left_unchecked(&mut self) { self.1 -= 1 }
64
65 fn go_right_wrapping(&mut self) {
66 if self.is_rightmost() { self.go_leftmost() } else { self.go_right_unchecked() }
67 }
68 fn go_left_wrapping(&mut self) {
69 if self.is_leftmost() { self.go_rightmost() } else { self.go_left_unchecked() }
70 }
71
72 fn journey_right(&mut self) -> bool {
77 for _ in 0..Row::<WIDTH>::MIN_MARGIN {
80 if self.is_note_empty() { return false }
81 else { self.go_right_wrapping() }
82 }
83 loop {
87 if self.is_note_empty() { return false }
88 else if self.is_rightmost() { return true } else { self.go_right_unchecked(); }
90 }
91 }
92
93 fn journey_left(&mut self) -> bool {
95 for _ in 0..Row::<WIDTH>::MIN_MARGIN {
96 if self.is_note_empty() { return false }
97 else { self.go_left_wrapping() }
98 }
99 loop {
100 if self.is_note_empty() { return false }
101 else if self.is_leftmost() { return true } else { self.go_left_unchecked(); }
103 }
104 }
105}
106
107
108impl <const WIDTH: usize> std::fmt::Display for Row<WIDTH> {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 for note in self.0.iter() { write!(f, "{}", note)? }
111 Ok(())
112 }
113}
114
115
116pub struct Dive<T, const WIDTH: usize> {
118 iter: T,
119 row: Row<WIDTH>,
120 buffered: Option<(Direction, Style)>,
121}
122
123impl <T: Iterator<Item=u8>, const WIDTH: usize> From<T> for Dive<T, WIDTH> {
124 fn from(it: T) -> Dive<T, WIDTH> {
125 Dive {
126 iter: it,
127 row: Row::new(WIDTH/2),
128 buffered: None,
129 }
130 }
131}
132
133impl <T: Iterator<Item=u8>, const WIDTH: usize> Dive<T, WIDTH> {
134
135 fn settle(&mut self, d: Direction, home: usize) -> Option<Row<WIDTH>> {
140 let go_down = match d {
141 Direction::Right => { self.row.journey_right() },
142 Direction::Left => { self.row.journey_left() }
143 };
144
145 if go_down {
146 return Some(std::mem::replace(&mut self.row, Row::new(home)))
147 }
148 else { None }
149 }
150
151 fn go(&mut self, d: Direction, s: Style) -> Option<Row<WIDTH>> {
170 self.row.set_note(Note::Full(d, s));
171 self.settle(d, *self.row.get_loc())
172 }
173}
174
175impl <T: Iterator<Item=u8>, const WIDTH: usize> Iterator for Dive<T, WIDTH> {
176 type Item = Row<WIDTH>;
177
178 fn next(&mut self) -> Option<Self::Item> {
190 macro_rules! go_and_return_on_descent {
191 ($direction:ident, $style:ident $(, $b:block)?) => {
192 if let Some(row) = self.go($direction, $style) {
193 $($b)?
194 return Some(row)
195 }
196 }
197 }
198
199 if let Some((d, s)) = self.buffered.take() {
200 go_and_return_on_descent!(d, s)
201 }
202
203 while let Some(byte) = self.iter.next() {
204 let DSPair([(d1, s1), (d2, s2)]) = DSPair::from(byte);
205 go_and_return_on_descent!(d1, s1, { self.buffered = Some((d2, s2)); });
206 go_and_return_on_descent!(d2, s2)
207 }
208 if self.row.is_empty() { return None }
209 else {
210 let orig = *self.row.get_loc();
211 return Some(std::mem::replace(&mut self.row, Row::new(orig)))
212 }
213 }
214}
215
216
217pub struct Route<const WIDTH: usize> {
221 route: Vec<Row<WIDTH>>,
222 end: usize,
223}
224
225
226impl <T: Iterator<Item=u8>, const WIDTH: usize> From<Dive<T, WIDTH>> for Route<WIDTH> {
227 fn from(it: Dive<T, WIDTH>) -> Route<WIDTH> {
228 let vec: Vec<_> = it.collect();
229 Route{ end: vec.last().map(|Row(_, v)| *v).unwrap_or(WIDTH/2), route: vec }
230 }
231
232}
233
234impl <const WIDTH: usize> std::fmt::Display for Route<WIDTH> {
235 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
236 write!(f, "+{}v{}+\n", "-".repeat((WIDTH/2).saturating_sub(1)), "-".repeat(WIDTH - (WIDTH/2)))?;
237 for row in &self.route {
238 write!(f, "|{}|\n", row)?
239 }
240 write!(f, "+{}v{}+\n", "-".repeat(self.end), "-".repeat((WIDTH - self.end).saturating_sub(1)))
241 }
242}
243
244