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// }