grid_iter/
lib.rs

1#![no_std]
2//! Grids for Iterators
3//!
4//! Provides a two dimensional abstraction over Iterators.
5//! Intended to be simple, flexible and ideomatic.
6//! ```rust
7//! use grid_iter::IntoGridIter;
8//!
9//! let file:&str = "1,2,3,4,5\n6,7,8,9,10\n11,12,13,14,15";
10//! let columns = file.find('\n').unwrap();
11//! let mut store = file.lines()
12//!     .flat_map(|line|line.split(',').map(|s|s.parse().unwrap()))
13//!     .collect::<Vec<_>>();
14//! store.iter_mut().into_grid_iter(columns).iter_col(3).for_each(|i| *i= 0);
15//! store.iter_mut().into_grid_iter(columns).iter_row(1).for_each(|i| *i+= 1);
16//! let borrowing_grid = store.iter().into_grid_iter(5);
17//! drop(borrowing_grid);
18//! let capturing_grid = store.iter().into_grid_iter(5);
19//! println!("{:?}", capturing_grid);
20//! ```
21use core::iter::{Skip, StepBy, Take, repeat};
22
23///The Grid struct wraps an Iterator and provies two dimensional access over its contents.
24#[derive(Copy, Debug)]
25pub struct GridIter<I: Iterator<Item = T>, T> {
26    inner: I,
27    columns: usize,
28    rows: Option<usize>,
29}
30//M anually implement because T does not need to be Clone
31impl<I: Iterator<Item = T> + Clone, T> Clone for GridIter<I, T> {
32    fn clone(&self) -> Self {
33        Self {
34            inner: self.inner.clone(),
35            columns: self.columns.clone(),
36            rows: self.rows.clone(),
37        }
38    }
39}
40impl<I: Iterator<Item = T> + Clone, T: core::fmt::Display> core::fmt::Display for GridIter<I, T> {
41    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
42        self.clone().iter_rows().for_each(|col| {
43            col.for_each(|ch| write!(f, "{}\t", ch).unwrap());
44            write!(f, "\n").unwrap();
45        });
46        Ok(())
47    }
48}
49
50/// IntoGridIter ist implemented for all iterators.
51/// Provides the grid function to wrap iterators with the Grid struct which contains the main functionality.
52pub trait IntoGridIter<I: Iterator<Item = T>, T> {
53    fn into_grid_iter(self, columns: usize) -> GridIter<I, T>;
54}
55
56impl<I: Iterator<Item = T>, T> IntoGridIter<I, T> for I {
57    fn into_grid_iter(self, columns: usize) -> GridIter<I, T> {
58        GridIter {
59            inner: self,
60            columns,
61            rows: None,
62        }
63    }
64}
65
66pub type Get<T> = Take<Skip<T>>;
67pub type RowIter<T> = Take<Skip<T>>;
68pub type ColIter<T> = StepBy<Skip<T>>;
69pub type DiagBwdIter<T> = Take<StepBy<Skip<T>>>;
70pub type DiagFwdIter<T> = Take<StepBy<Skip<T>>>;
71
72impl<I: Iterator<Item = T>, T> GridIter<I, T> {
73    ///```rust
74    ///
75    /// // . x .
76    /// // . x .
77    /// // . x .
78    ///
79    /// use grid_iter::IntoGridIter;
80    /// (0..25).into_grid_iter(5)
81    ///     .iter_col(3)
82    ///     .zip([3,8,13,18,23])
83    ///     .for_each(|(l, r)| assert!(l == r));
84    ///```   
85    pub fn iter_col(self, col: usize) -> ColIter<I> {
86        assert!(col < self.columns);
87        self.inner.into_iter().skip(col).step_by(self.columns)
88    }
89    ///```rust
90    ///
91    /// // . . .
92    /// // x x x
93    /// // . . .
94    ///
95    /// use grid_iter::IntoGridIter;
96    /// (0..25).into_grid_iter(5)
97    ///     .iter_row(3)
98    ///     .zip(15..20)
99    ///     .for_each(|(l, r)| assert!(l == r));
100    ///```
101    pub fn iter_row(self, row: usize) -> RowIter<I> {
102        self.inner.skip(row * self.columns).take(self.columns)
103    }
104
105    ///```rust
106    ///
107    /// // . . .
108    /// // . x .
109    /// // . . .
110    ///
111    /// use grid_iter::IntoGridIter;
112    /// assert!((0..25).into_grid_iter(5)
113    ///     .get(2,2)==Some(12))
114    ///```
115    pub fn get(self, col: usize, row: usize) -> Option<<I as IntoIterator>::Item> {
116        self.inner
117            .skip(index_to_flat(self.columns, col, row))
118            .take(1)
119            .next()
120    }
121    pub fn get_kernel(self, col: usize, row: usize) -> Option<[<I as IntoIterator>::Item; 9]> {
122        if col == 0 || col == self.columns - 1 || row == 0 {
123            None
124        } else {
125            let mut iter = self
126                .inner
127                .skip(index_to_flat(self.columns, col - 1, row - 1));
128            Some([
129                iter.next()?,
130                iter.next()?,
131                iter.next()?,
132                {
133                    (0..self.columns - 3).for_each(|_| {
134                        iter.next();
135                    });
136                    iter.next()?
137                },
138                iter.next()?,
139                iter.next()?,
140                {
141                    (0..self.columns - 3).for_each(|_| {
142                        iter.next();
143                    });
144                    iter.next()?
145                },
146                iter.next()?,
147                iter.next()?,
148            ])
149        }
150    }
151    pub fn position<P: FnMut(I::Item) -> bool>(mut self, pred: P) -> Option<(usize, usize)> {
152        self.inner
153            .position(pred)
154            .map(|flat| index_from_flat(self.columns, flat))
155    }
156
157    ///```rust
158    ///
159    /// // . . 1
160    /// // . 2 .
161    /// // 3 . .
162    ///
163    /// use grid_iter::IntoGridIter;
164    /// (0..25).into_grid_iter(5)
165    ///     .iter_diag_fwd(0,1)
166    ///     .zip([1,5])
167    ///     .for_each(|(l, r)| assert!(l == r));
168    /// (0..25).into_grid_iter(5)
169    ///     .iter_diag_fwd(3,2)
170    ///     .zip([9,13,17,21])
171    ///     .for_each(|(l, r)| assert!(l == r));
172    /// (0..25).into_grid_iter(5)
173    ///     .iter_diag_fwd(1,0)
174    ///     .zip([1,5])
175    ///     .for_each(|(l, r)| assert!(l == r));
176    ///```
177    pub fn iter_diag_fwd(self, col: usize, row: usize) -> DiagFwdIter<I> {
178        let col_max = self.columns - 1;
179        let (skip, take) = if col + row > self.columns - 1 {
180            // lower right part
181            (
182                index_to_flat(self.columns, col_max, row - (col_max - col)),
183                self.columns,
184            )
185        } else {
186            // upper left part
187            (index_to_flat(self.columns, row + col, 0), row + col + 1)
188        };
189        self.inner.skip(skip).step_by(col_max).take(take)
190    }
191    ///```rust
192    ///
193    /// // x . .
194    /// // . x .
195    /// // . . x
196    ///
197    /// use grid_iter::IntoGridIter;
198    /// (0..25).into_grid_iter(5)
199    ///     .iter_diag_bwd(1,2)
200    ///     .zip([5,11,17,23])
201    ///     .for_each(|(l, r)| assert!(l == r));
202    /// (0..25).into_grid_iter(5)
203    ///     .iter_diag_bwd(4,2)
204    ///     .zip([2,8,14])
205    ///     .for_each(|(l, r)| assert!(l == r));
206    /// (0..25).into_grid_iter(5)
207    ///     .iter_diag_bwd(4,0)
208    ///     .zip([4])
209    ///     .for_each(|(l, r)| assert!(l == r));
210    ///```
211    pub fn iter_diag_bwd(self, col: usize, row: usize) -> DiagBwdIter<I> {
212        let diff = col.abs_diff(row);
213        let (skip, take) = if col > row {
214            //topright
215            (index_to_flat(self.columns, diff, 0), self.columns - diff)
216        } else {
217            // botleft
218            (index_to_flat(self.columns, 0, diff), self.columns)
219        };
220        self.inner.skip(skip).step_by(self.columns + 1).take(take)
221    }
222}
223impl<I: Iterator<Item = T> + Clone, T> GridIter<I, T> {
224    /// calculates the rows and tries to cache them
225    /// for performance reasons you should use this function before using any other that needs the row count
226    fn calc_rows(&mut self) -> usize {
227        if let Some(rows) = self.rows {
228            rows
229        } else {
230            assert!(self.columns != 0);
231            let rows = self.clone().inner.count().div_ceil(self.columns);
232            self.rows = Some(rows);
233            rows
234        }
235    }
236    ///```rust
237    ///
238    /// use grid_iter::IntoGridIter;
239    /// assert!((0..25).into_grid_iter(5)
240    ///     .iter_rows()
241    ///     .flatten()
242    ///     .sum::<usize>()
243    ///     .eq(&(0..25).sum::<usize>()))
244    ///```
245    pub fn iter_rows(mut self) -> impl Iterator<Item = RowIter<I>> {
246        let rows = self.calc_rows();
247        repeat(self)
248            .enumerate()
249            .take(rows)
250            .map(|(r, s)| s.iter_row(r))
251    }
252    ///```rust
253    ///
254    /// use grid_iter::IntoGridIter;
255    /// assert!((0..25).into_grid_iter(5)
256    ///     .iter_cols()
257    ///     .flatten()
258    ///     .sum::<usize>()
259    ///     .eq(&(0..25).sum::<usize>()))
260    ///```
261    pub fn iter_cols(self) -> impl Iterator<Item = ColIter<I>> {
262        let columns = self.columns;
263        repeat(self)
264            .enumerate()
265            .take(columns)
266            .map(|(c, s)| s.iter_col(c))
267    }
268    ///```rust
269    ///
270    /// use grid_iter::IntoGridIter;
271    /// assert!((0..25).into_grid_iter(5)
272    ///     .iter_diags_bwd()
273    ///     .flatten()
274    ///     .sum::<usize>()
275    ///     .eq(&(0..25).sum::<usize>()))
276    ///```
277    pub fn iter_diags_bwd(mut self) -> impl Iterator<Item = DiagBwdIter<I>> {
278        let rows = self.calc_rows();
279        (0..self.columns)
280            .rev()
281            .zip(repeat(self.clone()))
282            .map(|(c, s)| s.iter_diag_bwd(c, 0))
283            .chain(
284                (1..rows)
285                    .zip(repeat(self))
286                    .map(|(r, s)| s.iter_diag_bwd(0, r)),
287            )
288    }
289    ///```rust
290    ///
291    /// use grid_iter::IntoGridIter;
292    /// assert!((0..25).into_grid_iter(5)
293    ///     .iter_diags_fwd()
294    ///     .flatten()
295    ///     .sum::<usize>()
296    ///     .eq(&(0..25).sum::<usize>()))
297    ///```
298    pub fn iter_diags_fwd(mut self) -> impl Iterator<Item = DiagFwdIter<I>> {
299        let rows = self.calc_rows();
300        let col_max = self.columns - 1;
301        (0..self.columns)
302            .zip(repeat(self.clone()))
303            .map(|(c, s)| s.iter_diag_fwd(c, 0))
304            .chain(
305                (1..rows)
306                    .zip(repeat(self))
307                    .map(move |(r, s)| s.iter_diag_fwd(col_max, r)),
308            )
309    }
310    pub fn iter_kernels(mut self) -> impl Iterator<Item = [T; 9]> {
311        let row_max = self.calc_rows() - 1;
312        let col_max = self.columns - 1;
313        repeat(self).zip(1..row_max).flat_map(move |(iter, r)| {
314            (1..col_max).filter_map(move |c| iter.clone().get_kernel(c, r))
315        })
316    }
317}
318fn index_from_flat(gridcolumns: usize, flat: usize) -> (usize, usize) {
319    assert!(gridcolumns != 0, "Columns set to 0! Cant calculate index");
320    (flat % gridcolumns, flat / gridcolumns)
321}
322fn index_to_flat(gridcolumns: usize, col: usize, row: usize) -> usize {
323    gridcolumns * row + col
324}
325
326// #[cfg(test)]
327// mod tests {
328//     use super::IntoGridIter;
329//     #[test]
330//     fn test_get() {
331//         println!("{}", (0..25).into_grid_iter(5));
332//         let t = (0..25)
333//             .into_grid_iter(5)
334//             .iter_kernels()
335//             .for_each(|f| println!("{:?}", f));
336//         println!("{t:?}");
337//     }
338// }