1use std::ops::Range;
4
5use crate::{
6 CoordinatesOutOfBoundsError, MatrixCoordinates, MatrixDimensionError, MatrixDimensions,
7 MatrixRange,
8};
9
10pub trait Matrix2D<C>: Dimensions2D + Domain2D + MatrixRef<C> + MatrixMut<C> + Sized {
12 fn new(values: Vec<C>, n_cols: usize) -> Result<Self, MatrixDimensionError>;
14}
15
16pub trait MatrixRef<C> {
18 fn get<T: Into<MatrixCoordinates>>(
20 &self,
21 coordinates: T,
22 ) -> Result<&C, CoordinatesOutOfBoundsError>;
23}
24
25pub trait MatrixMut<C> {
27 fn set<T: Into<MatrixCoordinates>>(
29 &mut self,
30 coordinates: T,
31 value: C,
32 ) -> Result<C, CoordinatesOutOfBoundsError>;
33}
34
35pub trait Domain2D {
37 fn row_range(&self) -> Range<usize>;
39 fn col_range(&self) -> Range<usize>;
41 fn range(&self) -> MatrixRange {
43 MatrixRange::from((self.row_range(), self.col_range()))
44 }
45 fn start(&self) -> MatrixCoordinates {
47 MatrixCoordinates::new(self.row_range().start, self.col_range().start)
48 }
49 fn end(&self) -> MatrixCoordinates {
51 MatrixCoordinates::new(self.row_range().end, self.col_range().end)
52 }
53 fn middle(&self) -> (f64, f64) {
55 let start = self.start();
56 let end = self.end();
57 let rows = start.row as f64 + 0.5 * (end.row - start.row) as f64;
58 let cols = start.col as f64 + 0.5 * (end.col - start.col) as f64;
59 (rows, cols)
60 }
61}
62impl Domain2D for ((usize, usize), (usize, usize)) {
63 fn row_range(&self) -> Range<usize> {
64 self.0 .0..self.1 .0
65 }
66 fn col_range(&self) -> Range<usize> {
67 self.0 .1..self.1 .1
68 }
69}
70impl Domain2D for (Range<usize>, Range<usize>) {
71 fn row_range(&self) -> Range<usize> {
72 self.0.clone()
73 }
74 fn col_range(&self) -> Range<usize> {
75 self.1.clone()
76 }
77}
78impl<D: Domain2D, T: Domain2D> Contains2D<D> for T {
79 fn contains(&self, other: &D) -> bool {
80 let plus_one = MatrixRange {
81 start: self.start(),
82 end: self.end() + MatrixCoordinates { row: 1, col: 1 },
83 };
84
85 self.contains(&other.start()) && plus_one.contains(&other.end())
86 }
87}
88impl<T: Domain2D> Contains2D<MatrixCoordinates> for T {
89 fn contains(&self, other: &MatrixCoordinates) -> bool {
90 self.row_range().contains(&other.row) && self.col_range().contains(&other.col)
91 }
92}
93
94pub trait Dimensions2D {
96 fn n_rows(&self) -> usize;
98 fn n_cols(&self) -> usize;
100 fn dimensions(&self) -> MatrixDimensions {
102 MatrixDimensions::new(self.n_rows(), self.n_cols())
103 }
104 fn len(&self) -> usize {
106 self.n_rows() * self.n_cols()
107 }
108 fn is_empty(&self) -> bool {
110 self.n_rows() == 0 && self.n_cols() == 0
111 }
112}
113impl<D: Domain2D> Dimensions2D for D {
114 fn n_rows(&self) -> usize {
115 self.row_range().len()
116 }
117 fn n_cols(&self) -> usize {
118 self.col_range().len()
119 }
120}
121impl Dimensions2D for (usize, usize) {
122 fn n_rows(&self) -> usize {
123 self.0
124 }
125 fn n_cols(&self) -> usize {
126 self.1
127 }
128}
129
130pub trait Contains2D<T> {
132 fn contains(&self, other: &T) -> bool;
134}