rust_advent_matrix/
iter.rs

1// Copyright 2025 Jeffrey B. Stewart <jeff@stewart.net>.  All Rights Reserved.
2
3use crate::{Coordinate, Matrix};
4use crate::column::Column;
5use crate::matrix_address::MatrixAddress;
6use crate::row::Row;
7
8/// MatrixForwardIterator returns the available addresses in a matrix in
9/// row-major format starting at the origin, or upper left (0, 0) address.
10pub struct MatrixForwardIterator<I>
11    where I: Coordinate
12{
13    end_exclusive: MatrixAddress<I>,
14    cursor: Option<MatrixAddress<I>>
15}
16
17impl <I> MatrixForwardIterator<I>
18    where I: Coordinate {
19    pub(crate) fn new(end_exclusive: MatrixAddress<I>) -> Self {
20        if end_exclusive == MatrixAddress::default() {
21            MatrixForwardIterator{
22                end_exclusive,
23                cursor: None,
24            }
25        } else {
26            MatrixForwardIterator{
27                end_exclusive,
28                cursor: Some(MatrixAddress::default()),
29            }
30            }
31    }
32}
33
34impl <I> Iterator for MatrixForwardIterator<I>
35    where I: Coordinate {
36    type Item = MatrixAddress<I>;
37
38    fn next(&mut self) -> Option<Self::Item> {
39        let result = self.cursor;
40        let next = self.cursor;
41        match next {
42            None => {},
43            Some(mut v) => {
44                v.column = v.column + I::unit();
45                if v.column == self.end_exclusive.column {
46                    v.row = v.row + I::unit();
47                    if v.row == self.end_exclusive.row {
48                        self.cursor = None;
49                    } else {
50                        v.column = I::default();
51                        self.cursor = Some(v)
52                    }
53                } else {
54                    self.cursor = Some(v);
55                }
56            }
57        }
58        result
59    }
60}
61
62/// MatrixValueIterator returns the values in a matrix
63/// in row-major order, starting at the upper left origin (0, 0).
64pub struct MatrixValueIterator<'a, T, I>
65where
66    T: 'a,
67    I: Coordinate,
68{
69    matrix: &'a dyn Matrix<'a, T, I>,
70    addrs: MatrixForwardIterator<I>,
71}
72
73impl <'a, T, I> MatrixValueIterator<'a, T, I>
74where
75    T: 'static,
76    I: Coordinate,
77{
78    pub(crate) fn new(matrix: &'a dyn Matrix<'a, T, I>) -> Self {
79        MatrixValueIterator{
80            matrix,
81            addrs: matrix.addresses(),
82        }
83    }
84}
85
86impl <'a, T, I> Iterator for MatrixValueIterator<'a, T, I>
87where
88    T: 'a,
89    I: Coordinate {
90    type Item = &'a T;
91
92    fn next(&mut self) -> Option<Self::Item> {
93        match self.addrs.next() {
94            None => None,
95            Some(addr) => Some(self.matrix.get(addr).unwrap()),
96        }
97    }
98}
99
100/// MatrixForwardIndexedIterator returns (address, value) tuples for
101/// a matrix in row-major order, starting at the upper left origin (0,0).
102pub struct MatrixForwardIndexedIterator<'a, T, I>
103where
104    T: 'a,
105    I: Coordinate,
106{
107    matrix: &'a dyn Matrix<'a, T, I>,
108    addrs: MatrixForwardIterator<I>,
109}
110
111impl <'a, T, I> MatrixForwardIndexedIterator<'a, T, I>
112where
113    T: 'static,
114    I: Coordinate,
115{
116    pub(crate) fn new(matrix: &'a dyn Matrix<'a, T, I>) -> Self {
117        MatrixForwardIndexedIterator{
118            matrix,
119            addrs: MatrixForwardIterator::new(MatrixAddress{
120                row: matrix.row_count(),
121                column: matrix.column_count(),
122            }),
123        }
124    }
125}
126
127impl <'a, T, I> Iterator for MatrixForwardIndexedIterator<'a, T, I>
128where
129    T: 'static,
130    I: Coordinate,
131{
132    type Item = (MatrixAddress<I>, &'a T);
133
134    fn next(&mut self) -> Option<Self::Item> {
135        match self.addrs.next() {
136            None => None,
137            Some(a) => Some((a, &self.matrix[a]))
138        }
139    }
140}
141
142pub struct MatrixRowIterator<'a, T, I>
143where
144    T: 'static,
145    I: Coordinate {
146    matrix: &'a dyn Matrix<'a, T, I>,
147    row: I,
148    column_cursor_forward: I,
149    column_cursor_back: I,
150    terminated: bool,
151}
152
153impl <'a, T, I> MatrixRowIterator<'a, T, I>
154where
155    T: 'a,
156    I: Coordinate
157{
158    pub(crate) fn new(matrix: &'a dyn Matrix<'a, T, I>, row: I) -> Self {
159        MatrixRowIterator{
160            matrix,
161            row,
162            column_cursor_forward: I::unit() - I::unit(),
163            column_cursor_back: matrix.column_count() - I::unit(),
164            terminated: matrix.column_count() == I::unit() - I::unit(),
165        }
166    }
167}
168
169impl <'a, T, I> Iterator for MatrixRowIterator<'a, T, I>
170where
171    T: 'a,
172    I: Coordinate,
173{
174    type Item = &'a T;
175
176    fn next(&mut self) -> Option<Self::Item> {
177        // because some of the coordinate types can be unsigned,
178        // and because we can cause termination in reverse iteration,
179        // we can't just look for cursor_forward > cursor_back.
180        if self.terminated {
181            None
182        } else {
183            let addr = MatrixAddress{
184                row: self.row,
185                column: self.column_cursor_forward,
186            };
187            let result = Some(&self.matrix[addr]);
188            if self.column_cursor_forward == self.column_cursor_back {
189                self.terminated = true;
190            }
191            self.column_cursor_forward = self.column_cursor_forward + I::unit();
192            result
193        }
194    }
195}
196
197impl <'a, T, I> DoubleEndedIterator for MatrixRowIterator<'a, T, I>
198where
199    T: 'a,
200    I: Coordinate,
201{
202    fn next_back(&mut self) -> Option<Self::Item> {
203        if self.terminated {
204            None
205        } else {
206            let addr = MatrixAddress{
207                row: self.row,
208                column: self.column_cursor_back,
209            };
210            let result = Some(&self.matrix[addr]);
211            if self.column_cursor_back == self.column_cursor_forward {
212                self.terminated = true;
213            } else {
214                self.column_cursor_back = self.column_cursor_back - I::unit();
215            }
216            result
217        }
218    }
219}
220
221pub struct MatrixRowsIterator<'a, T, I>
222where
223    T: 'static,
224    I: Coordinate {
225    matrix: &'a dyn Matrix<'a, T, I>,
226    row_cursor_forward: I,
227    row_cursor_back: I,
228    terminated: bool,
229}
230
231impl <'a, T, I> MatrixRowsIterator<'a, T, I>
232where
233    T: 'a,
234    I: Coordinate
235{
236    pub(crate) fn new(matrix: &'a dyn Matrix<'a, T, I>) -> Self {
237        MatrixRowsIterator{
238            matrix,
239            row_cursor_forward: I::unit() - I::unit(),
240            row_cursor_back: matrix.row_count() - I::unit(),
241            terminated: matrix.row_count() == I::unit() - I::unit(),
242        }
243    }
244}
245
246impl <'a, T, I> Iterator for MatrixRowsIterator<'a, T, I>
247where
248    T: 'a,
249    I: Coordinate,
250{
251    type Item = Row<'a, T, I>;
252
253    fn next(&mut self) -> Option<Self::Item> {
254        // because some of the coordinate types can be unsigned,
255        // and because we can cause termination in reverse iteration,
256        // we can't just look for cursor_forward > cursor_back.
257        if self.terminated {
258            None
259        } else {
260            let row : Row<T, I> = Row::new(self.matrix, self.row_cursor_forward);
261            if self.row_cursor_forward == self.row_cursor_back {
262                self.terminated = true;
263            }
264            self.row_cursor_forward = self.row_cursor_forward + I::unit();
265            Some(row)
266        }
267    }
268}
269
270impl <'a, T, I> DoubleEndedIterator for MatrixRowsIterator<'a, T, I>
271where
272    T: 'a,
273    I: Coordinate,
274{
275    fn next_back(&mut self) -> Option<Self::Item> {
276        if self.terminated {
277            None
278        } else {
279            let row : Row<T, I> = Row::new(self.matrix, self.row_cursor_back);
280            if self.row_cursor_forward == self.row_cursor_back {
281                self.terminated = true;
282            } else {
283                self.row_cursor_back = self.row_cursor_back - I::unit();
284            }
285            Some(row)
286        }
287    }
288}
289
290
291pub struct MatrixColumnIterator<'a, T, I>
292where
293    T: 'static,
294    I: Coordinate {
295    matrix: &'a dyn Matrix<'a, T, I>,
296    column: I,
297    row_cursor_forward: I,
298    row_cursor_back: I,
299    terminated: bool,
300}
301
302impl <'a, T, I> MatrixColumnIterator<'a, T, I>
303where
304    T: 'a,
305    I: Coordinate
306{
307    pub(crate) fn new(matrix: &'a dyn Matrix<'a, T, I>, column: I) -> Self {
308        MatrixColumnIterator{
309            matrix,
310            column,
311            row_cursor_forward: I::unit() - I::unit(),
312            row_cursor_back: matrix.row_count() - I::unit(),
313            terminated: matrix.row_count() == I::unit() - I::unit(),
314        }
315    }
316}
317
318impl <'a, T, I> Iterator for MatrixColumnIterator<'a, T, I>
319where
320    T: 'a,
321    I: Coordinate,
322{
323    type Item = &'a T;
324
325    fn next(&mut self) -> Option<Self::Item> {
326        // because some of the coordinate types can be unsigned,
327        // and because we can cause termination in reverse iteration,
328        // we can't just look for cursor_forward > cursor_back.
329        if self.terminated {
330            None
331        } else {
332            let addr = MatrixAddress{
333                row: self.row_cursor_forward,
334                column: self.column,
335            };
336            let result = Some(&self.matrix[addr]);
337            if self.row_cursor_forward == self.row_cursor_back {
338                self.terminated = true;
339            }
340            self.row_cursor_forward = self.row_cursor_forward + I::unit();
341            result
342        }
343    }
344}
345
346impl <'a, T, I> DoubleEndedIterator for MatrixColumnIterator<'a, T, I>
347where
348    T: 'a,
349    I: Coordinate,
350{
351    fn next_back(&mut self) -> Option<Self::Item> {
352        if self.terminated {
353            None
354        } else {
355            let addr = MatrixAddress{
356                row: self.row_cursor_back,
357                column: self.column,
358            };
359            let result = Some(&self.matrix[addr]);
360            if self.row_cursor_back == self.row_cursor_forward {
361                self.terminated = true;
362            } else {
363                self.row_cursor_back = self.row_cursor_back - I::unit();
364            }
365            result
366        }
367    }
368}
369
370pub struct MatrixColumnsIterator<'a, T, I>
371where
372    T: 'a,
373    I: Coordinate,
374{
375    matrix: &'a dyn Matrix<'a, T, I>,
376    column_cursor_forward: I,
377    column_cursor_back: I,
378    terminated: bool,
379}
380
381impl <'a, T, I> MatrixColumnsIterator<'a, T, I>
382where
383    T: 'static,
384    I: Coordinate
385{
386    pub(crate) fn new(matrix: &'a dyn Matrix<'a, T, I>) -> Self {
387        MatrixColumnsIterator{
388            matrix,
389            column_cursor_forward: I::unit() - I::unit(),
390            column_cursor_back: matrix.column_count() - I::unit(),
391            terminated: matrix.row_count() == I::unit() - I::unit(),
392        }
393    }
394}
395
396impl <'a, T, I> Iterator for MatrixColumnsIterator<'a, T, I>
397where
398    T: 'a,
399    I: Coordinate,
400{
401    type Item = Column<'a, T, I>;
402
403    fn next(&mut self) -> Option<Self::Item> {
404        // because some of the coordinate types can be unsigned,
405        // and because we can cause termination in reverse iteration,
406        // we can't just look for cursor_forward > cursor_back.
407        if self.terminated {
408            None
409        } else {
410            let column : Column<T, I> = Column::new(self.matrix, self.column_cursor_forward);
411            if self.column_cursor_forward == self.column_cursor_back {
412                self.terminated = true;
413            }
414            self.column_cursor_forward = self.column_cursor_forward + I::unit();
415            Some(column)
416        }
417    }
418}
419
420impl <'a, T, I> DoubleEndedIterator for MatrixColumnsIterator<'a, T, I>
421where
422    T: 'a,
423    I: Coordinate,
424{
425    fn next_back(&mut self) -> Option<Self::Item> {
426        if self.terminated {
427            None
428        } else {
429            let column : Column<T, I> = Column::new(self.matrix, self.column_cursor_back);
430            if self.column_cursor_forward == self.column_cursor_back {
431                self.terminated = true;
432            } else {
433                self.column_cursor_back = self.column_cursor_back - I::unit();
434            }
435            Some(column)
436        }
437    }
438}
439
440#[cfg(test)]
441mod tests {
442    use crate::factories::new_default_matrix;
443    use crate::format::FormatOptions;
444    use super::*;
445
446    fn u8addr(row: u8, column: u8) -> MatrixAddress<u8> {
447        MatrixAddress{row, column}
448    }
449
450    #[test]
451    fn iterator_as_expected() {
452        let end_exclusive = u8addr(3, 2);
453        let iter = MatrixForwardIterator::new(end_exclusive);
454        let values: Vec<MatrixAddress<u8>> = iter.collect();
455        assert_eq!(values, vec![
456            u8addr(0, 0), u8addr(0, 1),
457            u8addr(1, 0), u8addr(1, 1),
458            u8addr(2, 0), u8addr(2, 1),
459        ]);
460    }
461
462    #[test]
463    fn empty_matrix_iterator_is_empty() {
464        let end_exclusive = u8addr(0, 0);
465        let iter = MatrixForwardIterator::new(end_exclusive);
466        let values: Vec<MatrixAddress<u8>> = iter.collect();
467        assert!(values.is_empty());
468    }
469
470    #[test]
471    fn indexed_iterator_as_expected() {
472        let opts = FormatOptions{
473            row_delimiter: "|".to_string(),
474            column_delimiter: ",".to_string(),
475        };
476        let matrix = opts.parse_matrix(
477            "a,bc,d|d,ef,g",
478            |x| x.to_string()).unwrap();
479        let mut iter = matrix.indexed_iter();
480        let (a1, v1) = (&mut iter).next().unwrap();
481        assert_eq!(a1, u8addr(0, 0));
482        assert_eq!(v1, "a");
483        let (a2, v2) = (&mut iter).next().unwrap();
484        assert_eq!(a2, u8addr(0, 1));
485        assert_eq!(v2, "bc");
486        let (a3, v3) = (&mut iter).next().unwrap();
487        assert_eq!(a3, u8addr(0, 2));
488        assert_eq!(v3, "d");
489        let (a4, v4) = (&mut iter).next().unwrap();
490        assert_eq!(a4, u8addr(1, 0));
491        assert_eq!(v4, "d");
492        let (a5, v5) = (&mut iter).next().unwrap();
493        assert_eq!(a5, u8addr(1, 1));
494        assert_eq!(v5, "ef");
495        let (a6, v6) = (&mut iter).next().unwrap();
496        assert_eq!(a6, u8addr(1, 2));
497        assert_eq!(v6, "g");
498        assert!(iter.next().is_none());
499    }
500
501    #[test]
502    fn empty_indexed_iterator_as_expected() {
503        let matrix = new_default_matrix::<u8, u8>(0, 0).unwrap();
504        let mut iter = matrix.indexed_iter();
505        assert!((&mut iter).next().is_none());
506    }
507
508    fn ascii_parse_opts<'a>() -> FormatOptions {
509        FormatOptions{
510            row_delimiter: "\n".to_string(),
511            column_delimiter: "".to_string(),
512        }
513    }
514
515    #[test]
516    fn row_iterator_forward_only() {
517        let opts = ascii_parse_opts();
518        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
519        let row0 = matrix.row(0).unwrap().iter();
520        let values: Vec<&String> = row0.collect();
521        assert_eq!(values, vec!["A", "B", "C"]);
522    }
523
524    #[test]
525    fn row_iterator_reverse_only() {
526        let opts = ascii_parse_opts();
527        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
528        let row0 = matrix.row(0).unwrap().iter().rev();
529        let values: Vec<&String> = row0.collect();
530        assert_eq!(values, vec!["C", "B", "A"]);
531    }
532
533    #[test]
534    fn row_iterator_forward_passes_reverse() {
535        let opts = ascii_parse_opts();
536        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
537        let mut row0 = matrix.row(0).unwrap().iter();
538        assert_eq!(row0.next(), Some(&"A".to_string()));
539        assert_eq!(row0.next_back(), Some(&"C".to_string()));
540        assert_eq!(row0.next(), Some(&"B".to_string()));
541        assert_eq!(row0.next(), None);
542        assert_eq!(row0.next_back(), None);
543    }
544
545    #[test]
546    fn row_iterator_reverse_passes_forward() {
547        let opts = ascii_parse_opts();
548        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
549        let mut row1 = matrix.row(1).unwrap().iter();
550        assert_eq!(row1.next(), Some(&"D".to_string()));
551        assert_eq!(row1.next_back(), Some(&"F".to_string()));
552        assert_eq!(row1.next_back(), Some(&"E".to_string()));
553        assert_eq!(row1.next_back(), None);
554        assert_eq!(row1.next(), None);
555    }
556
557    #[test]
558    fn rows_iterator_forward() {
559        let opts = ascii_parse_opts();
560        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
561        let mut rows = matrix.rows();
562        let row1 = rows.next().unwrap();
563        let values1: Vec<&String> = row1.iter().collect();
564        assert_eq!(values1, vec!["A", "B", "C"]);
565        let row2 = rows.next().unwrap();
566        let values2: Vec<&String> = row2.iter().collect();
567        assert_eq!(values2, vec!["D", "E", "F"]);
568        assert!(rows.next().is_none());
569    }
570
571    #[test]
572    fn rows_iterator_backward() {
573        let opts = ascii_parse_opts();
574        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
575        let mut rows = matrix.rows().rev();
576        let row1 = rows.next().unwrap();
577        let values1: Vec<&String> = row1.iter().collect();
578        assert_eq!(values1, vec!["D", "E", "F"]);
579        let row2 = rows.next().unwrap();
580        let values2: Vec<&String> = row2.iter().collect();
581        assert_eq!(values2, vec!["A", "B", "C"]);
582        assert!(rows.next().is_none());
583    }
584
585
586    #[test]
587    fn column_iterator_forward_only() {
588        let opts = ascii_parse_opts();
589        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
590        let column0 = matrix.column(0).unwrap().iter();
591        let values: Vec<&String> = column0.collect();
592        assert_eq!(values, vec!["A", "D"]);
593    }
594
595    #[test]
596    fn column_iterator_reverse_only() {
597        let opts = ascii_parse_opts();
598        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
599        let column0 = matrix.column(0).unwrap().iter().rev();
600        let values: Vec<&String> = column0.collect();
601        assert_eq!(values, vec!["D", "A"]);
602    }
603
604    #[test]
605    fn column_iterator_forward_passes_reverse() {
606        let opts = ascii_parse_opts();
607        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
608        let mut column0 = matrix.column(0).unwrap().iter();
609        assert_eq!(column0.next(), Some(&"A".to_string()));
610        assert_eq!(column0.next_back(), Some(&"D".to_string()));
611        assert_eq!(column0.next(), None);
612        assert_eq!(column0.next_back(), None);
613    }
614
615    #[test]
616    fn column_iterator_reverse_passes_forward() {
617        let opts = ascii_parse_opts();
618        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
619        let mut column1 = matrix.column(1).unwrap().iter();
620        assert_eq!(column1.next(), Some(&"B".to_string()));
621        assert_eq!(column1.next_back(), Some(&"E".to_string()));
622        assert_eq!(column1.next_back(), None);
623        assert_eq!(column1.next(), None);
624    }
625
626    #[test]
627    fn columns_iterator_forward() {
628        let opts = ascii_parse_opts();
629        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
630        let mut columns = matrix.columns();
631        let column1 = columns.next().unwrap();
632        let values1: Vec<&String> = column1.iter().collect();
633        assert_eq!(values1, vec!["A", "D"]);
634        let column2 = columns.next().unwrap();
635        let values2: Vec<&String> = column2.iter().collect();
636        assert_eq!(values2, vec!["B", "E"]);
637        let column3 = columns.next().unwrap();
638        let values3: Vec<&String> = column3.iter().collect();
639        assert_eq!(values3, vec!["C", "F"]);
640        assert!(columns.next().is_none());
641    }
642
643    #[test]
644    fn columns_iterator_backward() {
645        let opts = ascii_parse_opts();
646        let matrix = opts.parse_matrix::<String, u8>("ABC\nDEF", |x| x.to_string()).unwrap();
647        let mut columns = matrix.columns().rev();
648        let column1 = columns.next().unwrap();
649        let values1: Vec<&String> = column1.iter().collect();
650        assert_eq!(values1, vec!["C", "F"]);
651        let column2 = columns.next().unwrap();
652        let values2: Vec<&String> = column2.iter().collect();
653        assert_eq!(values2, vec!["B", "E"]);
654        let column3 = columns.next().unwrap();
655        let values3: Vec<&String> = column3.iter().collect();
656        assert_eq!(values3, vec!["A", "D"]);
657        assert!(columns.next().is_none());
658    }
659}
660