mat/
lib.rs

1//! Dynamically sized 2d storage with rectangular iterators and in-place
2//! resizing
3
4#[cfg(feature="serde")]
5use serde::{Deserialize, Serialize};
6
7pub mod coordinate;
8pub mod dimensions;
9pub mod rectangle;
10pub use self::coordinate::Coordinate;
11pub use self::dimensions::Dimensions;
12pub use self::rectangle::Rectangle;
13
14/// Container for 2D data
15#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
16#[derive(Clone, Debug, Default, Eq, PartialEq)]
17pub struct Mat <T> {
18  elements   : Vec <T>,
19  dimensions : Dimensions
20}
21
22/// Iterator over a sub-rectangle within a `Mat`.
23///
24/// &#9888; Note this iterator proceeds *by row*, so the sequence for a
25/// an Nx3 rectangle would proceed as: `(0,0)`, `(0,1)`, `(0,2)`,
26/// `(1,0)`, `(1,1)`, ...
27pub struct RectIter <'a, T : 'a> {
28  mat       : &'a Mat <T>,
29  rectangle : Rectangle,
30  current   : Coordinate
31}
32
33/// Mutable iterator over a sub-rectangle within a `Mat`.
34///
35/// Note this iterator proceeds *by row*, so the sequence for a an Nx3 rectangle
36/// would proceed as: `(0,0)`, `(0,1)`, `(0,2)`, `(1,0)`, `(1,1)`, ...
37pub struct RectIterMut <'a, T : 'a> {
38  mat       : &'a mut Mat <T>,
39  rectangle : Rectangle,
40  current   : Coordinate
41}
42
43impl <T> Mat <T> {
44  /// Create a Mat with the given `dimensions`. All elements are initialized as
45  /// copies of the given element
46  #[inline]
47  pub fn fill_with (dimensions : Dimensions, element : &T) -> Self where
48    T : Clone
49  {
50    Mat {
51      elements: vec![element.clone(); dimensions.area()],
52      dimensions
53    }
54  }
55  /// Create a Mat with the given dimensions filled with default elements
56  #[inline]
57  pub fn with_dimensions (dimensions : Dimensions) -> Self where
58    T : Clone + Default
59  {
60    Self::fill_with (dimensions, &T::default())
61  }
62  /// Create a Mat with the given `dimensions` and elements.
63  ///
64  /// None is returned if the `dimensions` does not match the length of
65  /// elements.
66  #[inline]
67  pub fn from_vec (dimensions : Dimensions, elements : Vec <T>)
68    -> Option <Self>
69  {
70    if dimensions.area() == elements.len() {
71      Some (Mat { elements, dimensions })
72    } else {
73      None
74    }
75  }
76  #[inline]
77  pub fn dimensions (&self) -> Dimensions {
78    self.dimensions
79  }
80  /// Returns element at the given coord or `None` if the coord is outside the
81  /// Mat.
82  ///
83  /// # Example
84  ///
85  /// ```
86  /// # use mat::Mat;
87  /// let m = Mat::from_vec (
88  ///   (3, 3).into(), vec!['a','b','c','d','e','f','g','h','i']
89  /// ).unwrap();
90  /// assert_eq!(m.get_rc (0, 1), Some(&'b'));
91  /// assert_eq!(m.get_rc (2, 1), Some(&'h'));
92  /// assert_eq!(m.get_rc (0, 3), None);
93  /// ```
94  #[inline]
95  pub fn get (&self, Coordinate { row, column } : Coordinate) -> Option <&T> {
96    self.get_rc (row, column)
97  }
98  #[inline]
99  pub fn get_rc (&self, row : usize, column : usize) -> Option <&T> {
100    if self.dimensions.contains_rc (row, column) {
101      let i = row * self.width() + column;
102      Some (&self.elements[i])
103    } else {
104      None
105    }
106  }
107  #[inline]
108  pub fn get_mut (&mut self, Coordinate { row, column } : Coordinate)
109    -> Option <&mut T>
110  {
111    self.get_mut_rc (row, column)
112  }
113  /// Returns a mutable reference to the element at the given coord or
114  /// `None` if the coord is outside the Mat.
115  ///
116  /// # Example
117  ///
118  /// ```
119  /// # extern crate mat; use mat::*;
120  /// # fn main () {
121  /// let mut m = Mat::from_vec (
122  ///   (3, 3).into(),
123  ///   vec!['a','b','c','d','e','f','g','h','i']
124  /// ).unwrap();
125  /// assert_eq!(m.get_mut ((0, 1).into()), Some(&mut 'b'));
126  /// assert_eq!(m.get_mut ((2, 1).into()), Some(&mut 'h'));
127  /// assert_eq!(m.get_mut ((0, 3).into()), None);
128  /// # }
129  /// ```
130  #[inline]
131  pub fn get_mut_rc (&mut self, row : usize, column : usize)
132    -> Option <&mut T>
133  {
134    if self.dimensions.contains_rc (row, column) {
135      let i = row * self.dimensions.columns + column;
136      Some (&mut self.elements[i])
137    } else {
138      None
139    }
140  }
141  #[inline]
142  pub const fn width (&self) -> usize {
143    self.dimensions.columns
144  }
145  #[inline]
146  pub const fn height (&self) -> usize {
147    self.dimensions.rows
148  }
149  #[inline]
150  pub fn rectangle (&self) -> Rectangle {
151    self.dimensions.into()
152  }
153  #[inline]
154  pub fn row (&self, row : usize) -> Option <Rectangle> {
155    self.dimensions.row (row)
156  }
157  #[inline]
158  pub fn column (&self, column : usize) -> Option <Rectangle> {
159    self.dimensions.column (column)
160  }
161  #[inline]
162  pub fn top (&self) -> Option <Rectangle> {
163    self.dimensions.top()
164  }
165  #[inline]
166  pub fn bottom (&self) -> Option <Rectangle> {
167    self.dimensions.bottom()
168  }
169  #[inline]
170  pub fn left (&self) -> Option <Rectangle> {
171    self.dimensions.left()
172  }
173  #[inline]
174  pub fn right (&self) -> Option <Rectangle> {
175    self.dimensions.right()
176  }
177  /// Resize *in-place* so that `dimensions()` is equal to `new_dimensions`.
178  ///
179  /// Note that this does not reflow the contents, the new contents will just be
180  /// the first elements up to the new total length.
181  #[inline]
182  pub fn resize (&mut self, dimensions : Dimensions, element : T) where
183    T : Clone
184  {
185    self.elements.resize (dimensions.area(), element);
186    self.dimensions = dimensions;
187  }
188  pub fn flip_horizontal (&mut self) -> &mut Self {
189    let cols = self.dimensions.columns;
190    let rows = self.dimensions.rows;
191    for row in 0..rows {
192      let min = row * cols;
193      let max = row * cols + cols;
194      self.elements[min..max].reverse();
195    }
196    self
197  }
198  pub fn flip_vertical (&mut self) -> &mut Self {
199    self.elements.reverse();
200    self.flip_horizontal()
201  }
202  #[inline]
203  pub fn to_vec (self) -> Vec <T> {
204    self.elements
205  }
206  /// Iterate over the entire Mat
207  #[inline]
208  #[allow(mismatched_lifetime_syntaxes)]
209  pub fn elements (&self) -> std::slice::Iter <T> {
210    self.elements.iter()
211  }
212  /// Mutable iterater over the entire Mat
213  #[inline]
214  #[allow(mismatched_lifetime_syntaxes)]
215  pub fn elements_mut (&mut self) -> std::slice::IterMut <T> {
216    self.elements.iter_mut()
217  }
218  #[inline]
219  #[allow(mismatched_lifetime_syntaxes)]
220  pub fn rows (&self) -> std::slice::Chunks <T> {
221    self.elements.chunks (self.width())
222  }
223  #[inline]
224  #[allow(mismatched_lifetime_syntaxes)]
225  pub fn rows_mut (&mut self) -> std::slice::ChunksMut <T> {
226    let width = self.width();
227    self.elements.chunks_mut (width)
228  }
229  /// Create an iterator over a rectangular region of the Mat.
230  ///
231  /// None is returned if the given `rectangle` does not fit entirely within the
232  /// Mat.
233  pub fn rect_iter <'a> (&'a self, rectangle : Rectangle)
234    -> Option <RectIter <'a, T>>
235  {
236    if self.dimensions.contains (rectangle.min()) &&
237      self.dimensions.contains (rectangle.max())
238    {
239      let current = rectangle.min();
240      Some (RectIter { mat: self, rectangle, current })
241    } else {
242      None
243    }
244  }
245  /// Create a mutable iterator over a rectangular region of the Mat.
246  ///
247  /// None is returned if the given `rectangle` does not fit entirely within the
248  /// Mat.
249  pub fn rect_iter_mut <'a> (&'a mut self, rectangle : Rectangle)
250    -> Option <RectIterMut <'a, T>>
251  {
252    /*FIXME:debug*/ println!("DIMENSIONS: {:?}", self.dimensions);
253    /*FIXME:debug*/ println!("RECT: {:?}", rectangle);
254    if self.dimensions.contains (rectangle.max()) &&
255      self.dimensions.contains (rectangle.min())
256    {
257      let current = rectangle.min();
258      Some (RectIterMut { mat: self, rectangle, current })
259    } else {
260      None
261    }
262  }
263}
264impl <T : Clone> Mat <T> {
265  pub fn rotate_cw (&mut self) -> &mut Self {
266    let len = self.elements.len();
267    let mut v = Vec::with_capacity (len);
268    for col in 0..self.dimensions.columns {
269      for row in 0..self.dimensions.rows {
270        let row = self.dimensions.rows - row - 1;
271        v.push (self.get_rc (row, col).unwrap().clone());
272      }
273    }
274    debug_assert_eq!(v.len(), len);
275    self.elements = v;
276    self
277  }
278  pub fn rotate_ccw (&mut self) -> &mut Self {
279    let len = self.elements.len();
280    let mut v = Vec::with_capacity (len);
281    for col in 0..self.dimensions.columns {
282      let col = self.dimensions.columns - col - 1;
283      for row in 0..self.dimensions.rows {
284        v.push (self.get_rc (row, col).unwrap().clone());
285      }
286    }
287    debug_assert_eq!(v.len(), len);
288    self.elements = v;
289    self
290  }
291  #[inline]
292  pub fn tranpose (&mut self) -> &mut Self {
293    self.rotate_cw().flip_horizontal()
294  }
295}
296impl <T> std::ops::Deref for Mat <T> {
297  type Target = Vec <T>;
298  fn deref (&self) -> &Vec <T> {
299    &self.elements
300  }
301}
302impl <T : std::fmt::Debug> Mat <T> {
303  pub fn write_formatted <W : std::io::Write>
304    (&self, w : &mut W) -> std::io::Result <()>
305  {
306    let mut columns = Vec::new();
307    for column in 0..self.width() {
308      let v = self.rect_iter (self.column (column).unwrap()).unwrap()
309        .map (|(_, element)| format!("{:?}", element))
310        .collect::<Vec <String>>();
311      let longest = v.iter().map (String::len).max().unwrap();
312      columns.push ((longest, v));
313    }
314    for row in 0..self.height() {
315      for column in 0..self.width() {
316        use std::iter::FromIterator;
317        let (longest, col) = &columns[column];
318        let s     = &col[row];
319        let space = longest - s.len() + 1;
320        write!(w, "{}{}", s,
321          String::from_iter (std::iter::repeat (' ').take (space)))?;
322      }
323      writeln!(w)?;
324    }
325    Ok (())
326  }
327}
328impl <T : std::fmt::Display> std::fmt::Display for Mat <T> {
329  fn fmt (&self, f : &mut std::fmt::Formatter <'_>) -> std::fmt::Result {
330    let mut columns = Vec::new();
331    for column in 0..self.width() {
332      let v = self.rect_iter (self.column (column).unwrap()).unwrap()
333        .map (|(_, element)| format!("{}", element))
334        .collect::<Vec <String>>();
335      let longest = v.iter().map (String::len).max().unwrap();
336      columns.push ((longest, v));
337    }
338    for row in 0..self.height() {
339      for column in 0..self.width() {
340        use std::iter::FromIterator;
341        let (longest, col) = &columns[column];
342        let s     = &col[row];
343        let space = longest - s.len() + 1;
344        write!(f, "{}{}", s,
345          String::from_iter (std::iter::repeat (' ').take (space)))?;
346      }
347      writeln!(f)?;
348    }
349    Ok (())
350  }
351}
352
353impl <'a, T> Iterator for RectIter <'a, T> {
354  type Item = (Coordinate, &'a T);
355  fn next (&mut self) -> Option <Self::Item> {
356    if self.current.row <= self.rectangle.max().row {
357      let next = (self.current, self.mat.get (self.current).unwrap());
358      self.current.column += 1;
359      if self.current.column > self.rectangle.max().column {
360        self.current.column = self.rectangle.min().column;
361        self.current.row += 1;
362      }
363      Some (next)
364    } else {
365      None
366    }
367  }
368}
369
370impl <'a, T> Iterator for RectIterMut <'a, T> {
371  type Item = (Coordinate, &'a mut T);
372  fn next (&mut self) -> Option <Self::Item> {
373    if self.current.row <= self.rectangle.max().row {
374      let coordinate = self.current;
375      let element    = unsafe {
376        &mut *(self.mat.get_mut (coordinate).unwrap() as *mut T)
377      };
378      self.current.column += 1;
379      if self.current.column > self.rectangle.max().column {
380        self.current.column = self.rectangle.min().column;
381        self.current.row += 1;
382      }
383      Some ((coordinate, element))
384    } else {
385      None
386    }
387  }
388}
389
390#[cfg(test)]
391mod test {
392  use super::*;
393
394  #[test]
395  fn test_rect_iter_mut() {
396    let elements  = vec![1, 2, 3, 4];
397    let mut mat   = Mat::from_vec ((2, 2).into(), elements).unwrap();
398    let rectangle = Rectangle::from (((0, 0).into(), (2, 2).into()));
399    let mut actual_coords = Vec::new();
400    for (coord, elem) in mat.rect_iter_mut (rectangle).unwrap() {
401      *elem = -(*elem);
402      actual_coords.push ((coord.row, coord.column));
403    }
404    assert_eq!(actual_coords, [(0, 0), (0, 1), (1, 0), (1, 1)]);
405    assert_eq!(mat.elements, [-1, -2, -3, -4]);
406  }
407
408  #[test]
409  fn test_two_iterators() {
410    let dimensions = (2, 3).into();
411    let m = Mat::from_vec (dimensions, vec![0, 1, 2, 3, 4, 5]).unwrap();
412    let iter1 = m.rect_iter (dimensions.into()).unwrap();
413    let iter2 = m.rect_iter (dimensions.into()).unwrap();
414    for ((coord1, elem1), (coord2, elem2)) in iter1.zip (iter2) {
415      assert_eq!(coord1, coord2);
416      assert_eq!(elem1, elem2);
417    }
418  }
419
420  #[test]
421  fn test_rect_iter() {
422    let dimensions = (3, 3).into();
423    let m = Mat::from_vec (dimensions, vec![0, 1, 2, 3, 4, 5, 6, 7, 8])
424      .unwrap();
425    let dimensions = Dimensions::from ((2, 2));
426    let mut iter = m.rect_iter (dimensions.into()).unwrap();
427    let (coord, elem) = iter.next().unwrap();
428    assert_eq!((coord, *elem), (Coordinate {row: 0, column: 0}, 0));
429    let (coord, elem) = iter.next().unwrap();
430    assert_eq!((coord, *elem), (Coordinate {row: 0, column: 1}, 1));
431    let (coord, elem) = iter.next().unwrap();
432    assert_eq!((coord, *elem), (Coordinate {row: 1, column: 0}, 3));
433    let (coord, elem) = iter.next().unwrap();
434    assert_eq!((coord, *elem), (Coordinate {row: 1, column: 1}, 4));
435    assert!(iter.next().is_none());
436  }
437}