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>>(
29 &self,
30 coordinates: T,
31 ) -> Result<&C, CoordinatesOutOfBoundsError>;
32}
33
34pub trait MatrixMut<C> {
36 fn set<T: Into<MatrixCoordinates>>(
39 &mut self,
40 coordinates: T,
41 value: C,
42 ) -> Result<C, CoordinatesOutOfBoundsError>;
43}
44
45pub trait Domain2D {
47 fn row_range(&self) -> Range<usize>;
49
50 fn col_range(&self) -> Range<usize>;
52
53 fn range(&self) -> MatrixRange {
55 MatrixRange::from((self.row_range(), self.col_range()))
56 }
57
58 fn start(&self) -> MatrixCoordinates {
60 MatrixCoordinates::new(self.row_range().start, self.col_range().start)
61 }
62
63 fn end(&self) -> MatrixCoordinates {
65 MatrixCoordinates::new(self.row_range().end, self.col_range().end)
66 }
67
68 fn middle(&self) -> (f64, f64) {
70 let start = self.start();
71 let end = self.end();
72 let rows = start.row as f64 + 0.5 * (end.row - start.row) as f64;
73 let cols = start.col as f64 + 0.5 * (end.col - start.col) as f64;
74 (rows, cols)
75 }
76}
77impl Domain2D for ((usize, usize), (usize, usize)) {
78 fn row_range(&self) -> Range<usize> {
79 self.0.0..self.1.0
80 }
81 fn col_range(&self) -> Range<usize> {
82 self.0.1..self.1.1
83 }
84}
85impl Domain2D for (Range<usize>, Range<usize>) {
86 fn row_range(&self) -> Range<usize> {
87 self.0.clone()
88 }
89 fn col_range(&self) -> Range<usize> {
90 self.1.clone()
91 }
92}
93impl<D: Domain2D, T: Domain2D> Contains2D<D> for T {
94 fn contains(&self, other: &D) -> bool {
95 let plus_one = MatrixRange {
96 start: self.start(),
97 end: self.end() + MatrixCoordinates::new(1, 1),
98 };
99
100 self.contains(&other.start()) && plus_one.contains(&other.end())
101 }
102
103 fn overlaps(&self, other: &D) -> bool {
104 let plus_one = MatrixRange {
105 start: self.start(),
106 end: self.end() + MatrixCoordinates::new(1, 1),
107 };
108
109 self.contains(&other.start()) || plus_one.contains(&other.end()) || other.contains(self)
110 }
111}
112impl<T: Domain2D> Contains2D<MatrixCoordinates> for T {
113 fn contains(&self, other: &MatrixCoordinates) -> bool {
114 self.row_range().contains(&other.row) && self.col_range().contains(&other.col)
115 }
116}
117
118pub trait Dimensions2D {
120 fn n_rows(&self) -> usize;
122
123 fn n_cols(&self) -> usize;
125
126 fn dimensions(&self) -> MatrixDimensions {
128 MatrixDimensions::new(self.n_rows(), self.n_cols())
129 }
130
131 fn len(&self) -> usize {
133 self.n_rows() * self.n_cols()
134 }
135
136 fn is_empty(&self) -> bool {
138 self.n_rows() == 0 && self.n_cols() == 0
139 }
140}
141impl<D: Domain2D> Dimensions2D for D {
142 fn n_rows(&self) -> usize {
143 self.row_range().len()
144 }
145 fn n_cols(&self) -> usize {
146 self.col_range().len()
147 }
148}
149impl Dimensions2D for (usize, usize) {
150 fn n_rows(&self) -> usize {
151 self.0
152 }
153 fn n_cols(&self) -> usize {
154 self.1
155 }
156}
157impl Dimensions2D for (isize, isize) {
158 fn n_rows(&self) -> usize {
159 self.0 as usize
160 }
161 fn n_cols(&self) -> usize {
162 self.1 as usize
163 }
164}
165
166pub trait Contains2D<T> {
168 fn contains(&self, other: &T) -> bool;
170
171 fn overlaps(&self, other: &T) -> bool {
173 self.contains(other)
174 }
175}