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}