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<isize>;
47
48 fn col_range(&self) -> Range<isize>;
50
51 fn range(&self) -> MatrixRange {
53 MatrixRange::from((self.row_range(), self.col_range()))
54 }
55
56 fn start(&self) -> MatrixCoordinates {
58 MatrixCoordinates::new(self.row_range().start, self.col_range().start)
59 }
60
61 fn end(&self) -> MatrixCoordinates {
63 MatrixCoordinates::new(self.row_range().end, self.col_range().end)
64 }
65
66 fn middle(&self) -> (f64, f64) {
68 let start = self.start();
69 let end = self.end();
70 let rows = start.row as f64 + 0.5 * (end.row - start.row) as f64;
71 let cols = start.col as f64 + 0.5 * (end.col - start.col) as f64;
72 (rows, cols)
73 }
74}
75impl Domain2D for ((usize, usize), (usize, usize)) {
76 fn row_range(&self) -> Range<isize> {
77 self.0.0 as isize..self.1.0 as isize
78 }
79 fn col_range(&self) -> Range<isize> {
80 self.0.1 as isize..self.1.1 as isize
81 }
82}
83impl Domain2D for (Range<usize>, Range<usize>) {
84 fn row_range(&self) -> Range<isize> {
85 self.0.start as isize..self.0.end as isize
86 }
87 fn col_range(&self) -> Range<isize> {
88 self.1.start as isize..self.1.end as isize
89 }
90}
91impl Domain2D for ((isize, isize), (isize, isize)) {
92 fn row_range(&self) -> Range<isize> {
93 self.0.0..self.1.0
94 }
95 fn col_range(&self) -> Range<isize> {
96 self.0.1..self.1.1
97 }
98}
99impl Domain2D for (Range<isize>, Range<isize>) {
100 fn row_range(&self) -> Range<isize> {
101 self.0.clone()
102 }
103 fn col_range(&self) -> Range<isize> {
104 self.1.clone()
105 }
106}
107impl<D: Domain2D, T: Domain2D> Contains2D<D> for T {
108 fn contains(&self, other: &D) -> bool {
109 let plus_one = MatrixRange {
110 start: self.start(),
111 end: self.end() + MatrixCoordinates { row: 1, col: 1 },
112 };
113
114 self.contains(&other.start()) && plus_one.contains(&other.end())
115 }
116
117 fn overlaps(&self, other: &D) -> bool {
118 self.contains(&other.start())
119 || self.contains(&(other.end() - MatrixCoordinates::new(1, 1)))
120 || other.contains(self)
121 }
122}
123impl<T: Domain2D> Contains2D<MatrixCoordinates> for T {
124 fn contains(&self, other: &MatrixCoordinates) -> bool {
125 self.row_range().contains(&other.row) && self.col_range().contains(&other.col)
126 }
127}
128
129pub trait Dimensions2D {
131 fn n_rows(&self) -> usize;
133
134 fn n_cols(&self) -> usize;
136
137 fn dimensions(&self) -> MatrixDimensions {
139 MatrixDimensions::new(self.n_rows(), self.n_cols())
140 }
141
142 fn len(&self) -> usize {
144 self.n_rows() * self.n_cols()
145 }
146
147 fn is_empty(&self) -> bool {
149 self.n_rows() == 0 && self.n_cols() == 0
150 }
151}
152impl<D: Domain2D> Dimensions2D for D {
153 fn n_rows(&self) -> usize {
154 self.row_range().len()
155 }
156 fn n_cols(&self) -> usize {
157 self.col_range().len()
158 }
159}
160impl Dimensions2D for (usize, usize) {
161 fn n_rows(&self) -> usize {
162 self.0
163 }
164 fn n_cols(&self) -> usize {
165 self.1
166 }
167}
168impl Dimensions2D for (isize, isize) {
169 fn n_rows(&self) -> usize {
170 self.0 as usize
171 }
172 fn n_cols(&self) -> usize {
173 self.1 as usize
174 }
175}
176
177pub trait Contains2D<T> {
179 fn contains(&self, other: &T) -> bool;
181
182 fn overlaps(&self, other: &T) -> bool {
184 self.contains(other)
185 }
186}