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