#[cfg(feature="serde")]
use serde::{Deserialize, Serialize};
pub mod coordinate;
pub mod dimensions;
pub mod rectangle;
pub use self::coordinate::Coordinate;
pub use self::dimensions::Dimensions;
pub use self::rectangle::Rectangle;
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Mat <T> {
elements : Vec <T>,
dimensions : Dimensions
}
pub struct RectIter <'a, T : 'a> {
mat : &'a Mat <T>,
rectangle : Rectangle,
current : Coordinate
}
pub struct RectIterMut <'a, T : 'a> {
mat : &'a mut Mat <T>,
rectangle : Rectangle,
current : Coordinate
}
impl <T> Mat <T> {
#[inline]
pub fn fill_with (dimensions : Dimensions, element : &T) -> Self where
T : Clone
{
Mat {
elements: vec![element.clone(); dimensions.area()],
dimensions
}
}
#[inline]
pub fn with_dimensions (dimensions : Dimensions) -> Self where
T : Clone + Default
{
Self::fill_with (dimensions, &T::default())
}
#[inline]
pub fn from_vec (dimensions : Dimensions, elements : Vec <T>)
-> Option <Self>
{
if dimensions.area() == elements.len() {
Some (Mat { elements, dimensions })
} else {
None
}
}
#[inline]
pub fn dimensions (&self) -> Dimensions {
self.dimensions
}
#[inline]
pub fn get (&self, Coordinate { row, column } : Coordinate) -> Option <&T> {
self.get_rc (row, column)
}
#[inline]
pub fn get_rc (&self, row : usize, column : usize) -> Option <&T> {
if self.dimensions.contains_rc (row, column) {
let i = row * self.width() + column;
Some (&self.elements[i])
} else {
None
}
}
#[inline]
pub fn get_mut (&mut self, Coordinate { row, column } : Coordinate)
-> Option <&mut T>
{
self.get_mut_rc (row, column)
}
#[inline]
pub fn get_mut_rc (&mut self, row : usize, column : usize)
-> Option <&mut T>
{
if self.dimensions.contains_rc (row, column) {
let i = row * self.dimensions.columns + column;
Some (&mut self.elements[i])
} else {
None
}
}
#[inline]
pub const fn width (&self) -> usize {
self.dimensions.columns
}
#[inline]
pub const fn height (&self) -> usize {
self.dimensions.rows
}
#[inline]
pub fn rectangle (&self) -> Rectangle {
self.dimensions.into()
}
#[inline]
pub fn row (&self, row : usize) -> Option <Rectangle> {
self.dimensions.row (row)
}
#[inline]
pub fn column (&self, column : usize) -> Option <Rectangle> {
self.dimensions.column (column)
}
#[inline]
pub fn top (&self) -> Option <Rectangle> {
self.dimensions.top()
}
#[inline]
pub fn bottom (&self) -> Option <Rectangle> {
self.dimensions.bottom()
}
#[inline]
pub fn left (&self) -> Option <Rectangle> {
self.dimensions.left()
}
#[inline]
pub fn right (&self) -> Option <Rectangle> {
self.dimensions.right()
}
#[inline]
pub fn resize (&mut self, dimensions : Dimensions, element : T) where
T : Clone
{
self.elements.resize (dimensions.area(), element);
self.dimensions = dimensions;
}
pub fn flip_horizontal (&mut self) -> &mut Self {
let cols = self.dimensions.columns;
let rows = self.dimensions.rows;
for row in 0..rows {
let min = row * cols;
let max = row * cols + cols;
self.elements[min..max].reverse();
}
self
}
pub fn flip_vertical (&mut self) -> &mut Self {
self.elements.reverse();
self.flip_horizontal()
}
#[inline]
pub fn to_vec (self) -> Vec <T> {
self.elements
}
#[inline]
#[allow(mismatched_lifetime_syntaxes)]
pub fn elements (&self) -> std::slice::Iter <T> {
self.elements.iter()
}
#[inline]
#[allow(mismatched_lifetime_syntaxes)]
pub fn elements_mut (&mut self) -> std::slice::IterMut <T> {
self.elements.iter_mut()
}
#[inline]
#[allow(mismatched_lifetime_syntaxes)]
pub fn rows (&self) -> std::slice::Chunks <T> {
self.elements.chunks (self.width())
}
#[inline]
#[allow(mismatched_lifetime_syntaxes)]
pub fn rows_mut (&mut self) -> std::slice::ChunksMut <T> {
let width = self.width();
self.elements.chunks_mut (width)
}
pub fn rect_iter <'a> (&'a self, rectangle : Rectangle)
-> Option <RectIter <'a, T>>
{
if self.dimensions.contains (rectangle.min()) &&
self.dimensions.contains (rectangle.max())
{
let current = rectangle.min();
Some (RectIter { mat: self, rectangle, current })
} else {
None
}
}
pub fn rect_iter_mut <'a> (&'a mut self, rectangle : Rectangle)
-> Option <RectIterMut <'a, T>>
{
println!("DIMENSIONS: {:?}", self.dimensions);
println!("RECT: {:?}", rectangle);
if self.dimensions.contains (rectangle.max()) &&
self.dimensions.contains (rectangle.min())
{
let current = rectangle.min();
Some (RectIterMut { mat: self, rectangle, current })
} else {
None
}
}
}
impl <T : Clone> Mat <T> {
pub fn rotate_cw (&mut self) -> &mut Self {
let len = self.elements.len();
let mut v = Vec::with_capacity (len);
for col in 0..self.dimensions.columns {
for row in 0..self.dimensions.rows {
let row = self.dimensions.rows - row - 1;
v.push (self.get_rc (row, col).unwrap().clone());
}
}
debug_assert_eq!(v.len(), len);
self.elements = v;
self
}
pub fn rotate_ccw (&mut self) -> &mut Self {
let len = self.elements.len();
let mut v = Vec::with_capacity (len);
for col in 0..self.dimensions.columns {
let col = self.dimensions.columns - col - 1;
for row in 0..self.dimensions.rows {
v.push (self.get_rc (row, col).unwrap().clone());
}
}
debug_assert_eq!(v.len(), len);
self.elements = v;
self
}
#[inline]
pub fn tranpose (&mut self) -> &mut Self {
self.rotate_cw().flip_horizontal()
}
}
impl <T> std::ops::Deref for Mat <T> {
type Target = Vec <T>;
fn deref (&self) -> &Vec <T> {
&self.elements
}
}
impl <T : std::fmt::Debug> Mat <T> {
pub fn write_formatted <W : std::io::Write>
(&self, w : &mut W) -> std::io::Result <()>
{
let mut columns = Vec::new();
for column in 0..self.width() {
let v = self.rect_iter (self.column (column).unwrap()).unwrap()
.map (|(_, element)| format!("{:?}", element))
.collect::<Vec <String>>();
let longest = v.iter().map (String::len).max().unwrap();
columns.push ((longest, v));
}
for row in 0..self.height() {
for column in 0..self.width() {
use std::iter::FromIterator;
let (longest, col) = &columns[column];
let s = &col[row];
let space = longest - s.len() + 1;
write!(w, "{}{}", s,
String::from_iter (std::iter::repeat (' ').take (space)))?;
}
writeln!(w)?;
}
Ok (())
}
}
impl <T : std::fmt::Display> std::fmt::Display for Mat <T> {
fn fmt (&self, f : &mut std::fmt::Formatter <'_>) -> std::fmt::Result {
let mut columns = Vec::new();
for column in 0..self.width() {
let v = self.rect_iter (self.column (column).unwrap()).unwrap()
.map (|(_, element)| format!("{}", element))
.collect::<Vec <String>>();
let longest = v.iter().map (String::len).max().unwrap();
columns.push ((longest, v));
}
for row in 0..self.height() {
for column in 0..self.width() {
use std::iter::FromIterator;
let (longest, col) = &columns[column];
let s = &col[row];
let space = longest - s.len() + 1;
write!(f, "{}{}", s,
String::from_iter (std::iter::repeat (' ').take (space)))?;
}
writeln!(f)?;
}
Ok (())
}
}
impl <'a, T> Iterator for RectIter <'a, T> {
type Item = (Coordinate, &'a T);
fn next (&mut self) -> Option <Self::Item> {
if self.current.row <= self.rectangle.max().row {
let next = (self.current, self.mat.get (self.current).unwrap());
self.current.column += 1;
if self.current.column > self.rectangle.max().column {
self.current.column = self.rectangle.min().column;
self.current.row += 1;
}
Some (next)
} else {
None
}
}
}
impl <'a, T> Iterator for RectIterMut <'a, T> {
type Item = (Coordinate, &'a mut T);
fn next (&mut self) -> Option <Self::Item> {
if self.current.row <= self.rectangle.max().row {
let coordinate = self.current;
let element = unsafe {
&mut *(self.mat.get_mut (coordinate).unwrap() as *mut T)
};
self.current.column += 1;
if self.current.column > self.rectangle.max().column {
self.current.column = self.rectangle.min().column;
self.current.row += 1;
}
Some ((coordinate, element))
} else {
None
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_rect_iter_mut() {
let elements = vec![1, 2, 3, 4];
let mut mat = Mat::from_vec ((2, 2).into(), elements).unwrap();
let rectangle = Rectangle::from (((0, 0).into(), (2, 2).into()));
let mut actual_coords = Vec::new();
for (coord, elem) in mat.rect_iter_mut (rectangle).unwrap() {
*elem = -(*elem);
actual_coords.push ((coord.row, coord.column));
}
assert_eq!(actual_coords, [(0, 0), (0, 1), (1, 0), (1, 1)]);
assert_eq!(mat.elements, [-1, -2, -3, -4]);
}
#[test]
fn test_two_iterators() {
let dimensions = (2, 3).into();
let m = Mat::from_vec (dimensions, vec![0, 1, 2, 3, 4, 5]).unwrap();
let iter1 = m.rect_iter (dimensions.into()).unwrap();
let iter2 = m.rect_iter (dimensions.into()).unwrap();
for ((coord1, elem1), (coord2, elem2)) in iter1.zip (iter2) {
assert_eq!(coord1, coord2);
assert_eq!(elem1, elem2);
}
}
#[test]
fn test_rect_iter() {
let dimensions = (3, 3).into();
let m = Mat::from_vec (dimensions, vec![0, 1, 2, 3, 4, 5, 6, 7, 8])
.unwrap();
let dimensions = Dimensions::from ((2, 2));
let mut iter = m.rect_iter (dimensions.into()).unwrap();
let (coord, elem) = iter.next().unwrap();
assert_eq!((coord, *elem), (Coordinate {row: 0, column: 0}, 0));
let (coord, elem) = iter.next().unwrap();
assert_eq!((coord, *elem), (Coordinate {row: 0, column: 1}, 1));
let (coord, elem) = iter.next().unwrap();
assert_eq!((coord, *elem), (Coordinate {row: 1, column: 0}, 3));
let (coord, elem) = iter.next().unwrap();
assert_eq!((coord, *elem), (Coordinate {row: 1, column: 1}, 4));
assert!(iter.next().is_none());
}
}