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,
36            rows: self.rows,
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            writeln!(f).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, column_index: usize) -> ColIter<I> {
86        assert!(column_index < self.columns);
87        self.inner.skip(column_index).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_index: usize) -> RowIter<I> {
102        self.inner.skip(row_index * 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_index: usize, row_index: usize) -> Option<<I as IntoIterator>::Item> {
116        self.inner
117            .skip(grid_index_to_flat(self.columns, col_index, row_index))
118            .take(1)
119            .next()
120    }
121    pub fn get_kernel(
122        self,
123        column_index: usize,
124        row_index: usize,
125    ) -> Option<[<I as IntoIterator>::Item; 9]> {
126        if column_index == 0 || column_index == self.columns - 1 || row_index == 0 {
127            None
128        } else {
129            let mut iter = self.inner.skip(grid_index_to_flat(
130                self.columns,
131                column_index - 1,
132                row_index - 1,
133            ));
134            Some([
135                iter.next()?,
136                iter.next()?,
137                iter.next()?,
138                {
139                    (0..self.columns - 3).for_each(|_| {
140                        iter.next();
141                    });
142                    iter.next()?
143                },
144                iter.next()?,
145                iter.next()?,
146                {
147                    (0..self.columns - 3).for_each(|_| {
148                        iter.next();
149                    });
150                    iter.next()?
151                },
152                iter.next()?,
153                iter.next()?,
154            ])
155        }
156    }
157    pub fn position<P: FnMut(I::Item) -> bool>(mut self, pred: P) -> Option<(usize, usize)> {
158        self.inner
159            .position(pred)
160            .map(|flat| flat_index_to_grid(self.columns, flat))
161    }
162
163    ///```rust
164    ///
165    /// // . . 1
166    /// // . 2 .
167    /// // 3 . .
168    ///
169    /// use grid_iter::IntoGridIter;
170    /// (0..25).into_grid_iter(5)
171    ///     .iter_diag_fwd(0,1)
172    ///     .zip([1,5])
173    ///     .for_each(|(l, r)| assert!(l == r));
174    /// (0..25).into_grid_iter(5)
175    ///     .iter_diag_fwd(3,2)
176    ///     .zip([9,13,17,21])
177    ///     .for_each(|(l, r)| assert!(l == r));
178    /// (0..25).into_grid_iter(5)
179    ///     .iter_diag_fwd(1,0)
180    ///     .zip([1,5])
181    ///     .for_each(|(l, r)| assert!(l == r));
182    ///```
183    pub fn iter_diag_fwd(self, column_index: usize, row_index: usize) -> DiagFwdIter<I> {
184        let col_max = self.columns - 1;
185        let (skip, take) = if column_index + row_index > self.columns - 1 {
186            // lower right part
187            (
188                grid_index_to_flat(self.columns, col_max, row_index - (col_max - column_index)),
189                self.columns,
190            )
191        } else {
192            // upper left part
193            (
194                grid_index_to_flat(self.columns, row_index + column_index, 0),
195                row_index + column_index + 1,
196            )
197        };
198        self.inner.skip(skip).step_by(col_max).take(take)
199    }
200    ///```rust
201    ///
202    /// // x . .
203    /// // . x .
204    /// // . . x
205    ///
206    /// use grid_iter::IntoGridIter;
207    /// (0..25).into_grid_iter(5)
208    ///     .iter_diag_bwd(1,2)
209    ///     .zip([5,11,17,23])
210    ///     .for_each(|(l, r)| assert!(l == r));
211    /// (0..25).into_grid_iter(5)
212    ///     .iter_diag_bwd(4,2)
213    ///     .zip([2,8,14])
214    ///     .for_each(|(l, r)| assert!(l == r));
215    /// (0..25).into_grid_iter(5)
216    ///     .iter_diag_bwd(4,0)
217    ///     .zip([4])
218    ///     .for_each(|(l, r)| assert!(l == r));
219    ///```
220    pub fn iter_diag_bwd(self, column_index: usize, row_index: usize) -> DiagBwdIter<I> {
221        let diff = column_index.abs_diff(row_index);
222        let (skip, take) = if column_index > row_index {
223            //topright
224            (
225                grid_index_to_flat(self.columns, diff, 0),
226                self.columns - diff,
227            )
228        } else {
229            // botleft
230            (grid_index_to_flat(self.columns, 0, diff), self.columns)
231        };
232        self.inner.skip(skip).step_by(self.columns + 1).take(take)
233    }
234}
235impl<I: Iterator<Item = T> + Clone, T> GridIter<I, T> {
236    /// calculates the rows and tries to cache them
237    /// for performance reasons you should use this function before using any other that needs the row count
238    fn calc_rows(&mut self) -> usize {
239        if let Some(rows) = self.rows {
240            rows
241        } else {
242            assert!(self.columns != 0);
243            let rows = self.clone().inner.count().div_ceil(self.columns);
244            self.rows = Some(rows);
245            rows
246        }
247    }
248    ///```rust
249    ///
250    /// use grid_iter::IntoGridIter;
251    /// assert!((0..25).into_grid_iter(5)
252    ///     .iter_rows()
253    ///     .flatten()
254    ///     .sum::<usize>()
255    ///     .eq(&(0..25).sum::<usize>()))
256    ///```
257    pub fn iter_rows(mut self) -> impl Iterator<Item = RowIter<I>> {
258        let rows = self.calc_rows();
259        repeat(self)
260            .enumerate()
261            .take(rows)
262            .map(|(r, s)| s.iter_row(r))
263    }
264    ///```rust
265    ///
266    /// use grid_iter::IntoGridIter;
267    /// assert!((0..25).into_grid_iter(5)
268    ///     .iter_cols()
269    ///     .flatten()
270    ///     .sum::<usize>()
271    ///     .eq(&(0..25).sum::<usize>()))
272    ///```
273    pub fn iter_cols(self) -> impl Iterator<Item = ColIter<I>> {
274        let columns = self.columns;
275        repeat(self)
276            .enumerate()
277            .take(columns)
278            .map(|(c, s)| s.iter_col(c))
279    }
280    ///```rust
281    ///
282    /// use grid_iter::IntoGridIter;
283    /// assert!((0..25).into_grid_iter(5)
284    ///     .iter_diags_bwd()
285    ///     .flatten()
286    ///     .sum::<usize>()
287    ///     .eq(&(0..25).sum::<usize>()))
288    ///```
289    pub fn iter_diags_bwd(mut self) -> impl Iterator<Item = DiagBwdIter<I>> {
290        let rows = self.calc_rows();
291        (0..self.columns)
292            .rev()
293            .zip(repeat(self.clone()))
294            .map(|(c, s)| s.iter_diag_bwd(c, 0))
295            .chain(
296                (1..rows)
297                    .zip(repeat(self))
298                    .map(|(r, s)| s.iter_diag_bwd(0, r)),
299            )
300    }
301    ///```rust
302    ///
303    /// use grid_iter::IntoGridIter;
304    /// assert!((0..25).into_grid_iter(5)
305    ///     .iter_diags_fwd()
306    ///     .flatten()
307    ///     .sum::<usize>()
308    ///     .eq(&(0..25).sum::<usize>()))
309    ///```
310    pub fn iter_diags_fwd(mut self) -> impl Iterator<Item = DiagFwdIter<I>> {
311        let rows = self.calc_rows();
312        let col_max = self.columns - 1;
313        (0..self.columns)
314            .zip(repeat(self.clone()))
315            .map(|(c, s)| s.iter_diag_fwd(c, 0))
316            .chain(
317                (1..rows)
318                    .zip(repeat(self))
319                    .map(move |(r, s)| s.iter_diag_fwd(col_max, r)),
320            )
321    }
322    pub fn iter_kernels(mut self) -> impl Iterator<Item = [T; 9]> {
323        let row_max = self.calc_rows() - 1;
324        let col_max = self.columns - 1;
325        repeat(self).zip(1..row_max).flat_map(move |(iter, r)| {
326            (1..col_max).filter_map(move |c| iter.clone().get_kernel(c, r))
327        })
328    }
329}
330fn flat_index_to_grid(grid_columns: usize, flat_index: usize) -> (usize, usize) {
331    assert!(grid_columns != 0, "Columns set to 0! Cant calculate index");
332    (flat_index % grid_columns, flat_index / grid_columns)
333}
334fn grid_index_to_flat(grid_columns: usize, column_index: usize, row_index: usize) -> usize {
335    grid_columns * row_index + column_index
336}
337
338#[cfg(test)]
339mod tests {
340    use crate::{flat_index_to_grid, grid_index_to_flat};
341
342    #[test]
343    fn test_index() {
344        let (grid_col, flat_index) = (5123, 55);
345        let (col, row) = flat_index_to_grid(grid_col, flat_index);
346        let flat_index2 = grid_index_to_flat(grid_col, col, row);
347        assert_eq!(flat_index, flat_index2);
348    }
349}