image_texel/layout/
matrix.rs1use crate::image::{ImageMut, ImageRef};
3use crate::layout::{
4 Coord, Decay, Layout, MismatchedPixelError, Raster, RasterMut, SliceLayout, Take, TexelLayout,
5 TryMend,
6};
7
8use crate::{AsTexel, Texel};
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub struct MatrixBytes {
15 pub(crate) element: TexelLayout,
16 pub(crate) first_dim: usize,
17 pub(crate) second_dim: usize,
18}
19
20pub trait MatrixLayout: Layout {
22 fn matrix(&self) -> MatrixBytes;
27}
28
29impl<L> MatrixLayout for &'_ L
30where
31 L: MatrixLayout,
32{
33 fn matrix(&self) -> MatrixBytes {
34 L::matrix(*self)
35 }
36}
37
38impl<L> MatrixLayout for &'_ mut L
39where
40 L: MatrixLayout,
41{
42 fn matrix(&self) -> MatrixBytes {
43 L::matrix(*self)
44 }
45}
46
47impl MatrixBytes {
48 pub fn empty(element: TexelLayout) -> Self {
49 MatrixBytes {
50 element,
51 first_dim: 0,
52 second_dim: 0,
53 }
54 }
55
56 pub fn from_width_height(
57 element: TexelLayout,
58 first_dim: usize,
59 second_dim: usize,
60 ) -> Option<Self> {
61 let max_index = first_dim.checked_mul(second_dim)?;
62 let _ = max_index.checked_mul(element.size)?;
63
64 Some(MatrixBytes {
65 element,
66 first_dim,
67 second_dim,
68 })
69 }
70
71 pub const fn element(&self) -> TexelLayout {
73 self.element
74 }
75
76 pub const fn width(&self) -> usize {
78 self.first_dim
79 }
80
81 pub const fn height(&self) -> usize {
83 self.second_dim
84 }
85
86 pub const fn byte_len(self) -> usize {
88 self.element.size * self.len()
90 }
91
92 pub const fn len(self) -> usize {
94 self.first_dim * self.second_dim
95 }
96}
97
98impl Layout for MatrixBytes {
99 fn byte_len(&self) -> usize {
100 MatrixBytes::byte_len(*self)
101 }
102}
103
104impl Take for MatrixBytes {
105 fn take(&mut self) -> Self {
106 core::mem::replace(self, MatrixBytes::empty(self.element))
107 }
108}
109
110pub struct Matrix<P> {
116 pub(crate) width: usize,
117 pub(crate) height: usize,
118 pub(crate) pixel: Texel<P>,
119}
120
121impl<P> Matrix<P> {
122 pub fn from_width_height(pixel: Texel<P>, width: usize, height: usize) -> Option<Self> {
123 let max_index = Self::max_index(width, height)?;
124 let _ = max_index.checked_mul(pixel.size())?;
125
126 Some(Matrix {
127 width,
128 height,
129 pixel,
130 })
131 }
132
133 pub fn width_and_height(width: usize, height: usize) -> Option<Self>
134 where
135 P: AsTexel,
136 {
137 Self::from_width_height(P::texel(), width, height)
138 }
139
140 pub const fn empty(pixel: Texel<P>) -> Self {
141 Matrix {
142 pixel,
143 width: 0,
144 height: 0,
145 }
146 }
147
148 pub fn into_matrix_bytes(self) -> MatrixBytes {
149 MatrixBytes {
150 element: self.pixel.into(),
151 first_dim: self.width,
152 second_dim: self.height,
153 }
154 }
155
156 pub fn byte_len(self) -> usize {
158 self.pixel.size() * self.width * self.height
160 }
161
162 pub fn len(self) -> usize {
164 self.width * self.height
165 }
166
167 pub fn width(self) -> usize {
168 self.width
169 }
170
171 pub fn height(self) -> usize {
172 self.height
173 }
174
175 pub fn pixel(self) -> Texel<P> {
176 self.pixel
177 }
178
179 pub fn transmute<Q: AsTexel>(self) -> Matrix<Q> {
183 self.transmute_to(Q::texel())
184 }
185
186 pub fn transmute_to<Q>(self, pixel: Texel<Q>) -> Matrix<Q> {
192 assert!(
193 self.pixel.size() == pixel.size(),
194 "{} vs {}",
195 self.pixel.size(),
196 pixel.size()
197 );
198
199 Matrix {
200 width: self.width,
201 height: self.height,
202 pixel,
203 }
204 }
205
206 pub fn map<Q: AsTexel>(self) -> Option<Matrix<Q>> {
208 self.map_to(Q::texel())
209 }
210
211 pub fn map_to<Q>(self, pixel: Texel<Q>) -> Option<Matrix<Q>> {
213 Matrix::from_width_height(pixel, self.width, self.height)
214 }
215}
216
217impl<P> MatrixLayout for Matrix<P> {
218 fn matrix(&self) -> MatrixBytes {
219 self.into_matrix_bytes()
220 }
221}
222
223impl<L: MatrixLayout> Decay<L> for MatrixBytes {
225 fn decay(from: L) -> MatrixBytes {
226 from.matrix()
227 }
228}
229
230impl<P> TryMend<MatrixBytes> for Texel<P> {
232 type Into = Matrix<P>;
233 type Err = MismatchedPixelError;
234
235 fn try_mend(self, matrix: &MatrixBytes) -> Result<Matrix<P>, Self::Err> {
236 Matrix::with_matrix(self, *matrix).ok_or_else(MismatchedPixelError::default)
237 }
238}
239
240impl<P> From<Matrix<P>> for MatrixBytes {
241 fn from(mat: Matrix<P>) -> Self {
242 MatrixBytes {
243 element: mat.pixel().into(),
244 first_dim: mat.width(),
245 second_dim: mat.height(),
246 }
247 }
248}
249
250impl<P> Raster<P> for Matrix<P> {
252 fn dimensions(&self) -> Coord {
253 use core::convert::TryFrom;
254 let width = u32::try_from(self.width()).unwrap_or(u32::MAX);
255 let height = u32::try_from(self.height()).unwrap_or(u32::MAX);
256 Coord(width, height)
257 }
258
259 fn get(from: ImageRef<&Self>, Coord(x, y): Coord) -> Option<P> {
260 if from.layout().in_bounds(x as usize, y as usize) {
261 let index = from.layout().index_of(x as usize, y as usize);
262 let texel = from.layout().sample();
263 from.as_slice().get(index).map(|v| texel.copy_val(v))
264 } else {
265 None
266 }
267 }
268}
269
270impl<P> RasterMut<P> for Matrix<P> {
271 fn put(into: ImageMut<&mut Self>, Coord(x, y): Coord, val: P) {
272 if into.layout().in_bounds(x as usize, y as usize) {
273 let index = into.layout().index_of(x as usize, y as usize);
274 if let Some(dst) = into.into_mut_slice().get_mut(index) {
275 *dst = val;
276 }
277 }
278 }
279}