1use crate::Asn1Matrix;
2
3#[cfg(feature = "derive")]
4use crate::Errorizable;
5
6pub type MatrixResult<T> = core::result::Result<T, MatrixError>;
7
8#[cfg_attr(feature = "derive", derive(Errorizable))]
9#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
10pub enum MatrixError {
11 #[cfg_attr(feature = "derive", error("Asn1Matrix: n MUST be in 1..=255 (got {0})"))]
12 InvalidN(u8),
13 #[cfg_attr(
14 feature = "derive",
15 error("Asn1Matrix: data length MUST equal n*n (n={n}, len={len})")
16 )]
17 LengthMismatch { n: u8, len: usize },
18}
19
20crate::impl_error_display!(MatrixError {
21 InvalidN(n) => "Asn1Matrix: n MUST be in 1..=255 (got {n})",
22 LengthMismatch { n, len } => "Asn1Matrix: data length MUST equal n*n (n={n}, len={len})",
23});
24
25pub trait MatrixLike {
27 fn n(&self) -> u8;
29
30 fn get(&self, r: u8, c: u8) -> u8;
32
33 fn set(&mut self, r: u8, c: u8, value: u8);
35
36 fn fill(&mut self, value: u8);
38
39 fn clear(&mut self) {
41 self.fill(0);
42 }
43}
44
45pub trait IntoMatrixDyn {
48 fn into_matrix_dyn(self) -> Result<MatrixDyn, MatrixError>;
49}
50
51impl IntoMatrixDyn for MatrixDyn {
53 fn into_matrix_dyn(self) -> Result<MatrixDyn, MatrixError> {
54 Ok(self)
55 }
56}
57
58impl<M> IntoMatrixDyn for M
60where
61 M: MatrixLike,
62 MatrixDyn: TryFrom<M, Error = MatrixError>,
63{
64 fn into_matrix_dyn(self) -> Result<MatrixDyn, MatrixError> {
65 MatrixDyn::try_from(self)
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq)]
71pub struct MatrixDyn {
72 n: u8,
73 data: Vec<u8>,
74}
75
76impl Default for MatrixDyn {
77 fn default() -> Self {
78 Self { n: 1, data: Vec::new() }
79 }
80}
81
82impl MatrixDyn {
83 pub fn from_row_major(n: u8, bytes: Vec<u8>) -> Option<Self> {
85 if n == 0 {
86 return None;
87 }
88
89 let n_usize = n as usize;
90 if bytes.len() == n_usize * n_usize {
91 Some(Self { n, data: bytes })
92 } else {
93 None
94 }
95 }
96
97 #[inline]
98 fn idx(&self, r: u8, c: u8) -> Option<usize> {
99 let n = self.n as usize;
100 let (ru, cu) = (r as usize, c as usize);
101 if ru < n && cu < n {
102 Some(ru * n + cu)
103 } else {
104 None
105 }
106 }
107
108 pub fn as_bytes(&self) -> &[u8] {
110 &self.data
111 }
112
113 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
115 &mut self.data
116 }
117
118 pub fn row(&self, r: u8) -> Option<&[u8]> {
120 let n = self.n;
121 if r >= n {
122 return None;
123 }
124 let start = r as usize * n as usize;
125 Some(&self.data[start..start + n as usize])
126 }
127}
128
129impl MatrixLike for MatrixDyn {
130 fn n(&self) -> u8 {
131 self.n
132 }
133
134 fn get(&self, r: u8, c: u8) -> u8 {
135 self.idx(r, c).map(|i| self.data[i]).unwrap_or(0)
136 }
137
138 fn set(&mut self, r: u8, c: u8, value: u8) {
139 if let Some(i) = self.idx(r, c) {
140 self.data[i] = value;
141 }
142 }
143
144 fn fill(&mut self, value: u8) {
145 for b in &mut self.data {
146 *b = value;
147 }
148 }
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq)]
153pub struct Matrix<const N: usize> {
154 data: [[u8; N]; N],
155}
156
157impl<const N: usize> Default for Matrix<N> {
158 fn default() -> Self {
159 Self { data: [[0u8; N]; N] }
160 }
161}
162
163impl<const N: usize> Matrix<N> {
164 pub fn new() -> Self {
166 Self::default()
167 }
168
169 pub fn from_row_major(bytes: &[u8]) -> Self {
172 let mut m = Self::default();
173 let mut i = 0usize;
174 for r in 0..N {
175 for c in 0..N {
176 if i < bytes.len() {
177 m.data[r][c] = bytes[i];
178 }
179 i += 1;
180 }
181 }
182 m
183 }
184
185 pub fn row(&self, r: u8) -> Option<&[u8; N]> {
187 if (r as usize) < N {
188 Some(&self.data[r as usize])
189 } else {
190 None
191 }
192 }
193}
194
195impl<const N: usize> MatrixLike for Matrix<N> {
196 fn n(&self) -> u8 {
197 N as u8
198 }
199
200 fn get(&self, r: u8, c: u8) -> u8 {
201 if (r as usize) < N && (c as usize) < N {
202 self.data[r as usize][c as usize]
203 } else {
204 0
205 }
206 }
207
208 fn set(&mut self, r: u8, c: u8, value: u8) {
209 if (r as usize) < N && (c as usize) < N {
210 self.data[r as usize][c as usize] = value;
211 }
212 }
213
214 fn fill(&mut self, value: u8) {
215 for r in 0..N {
216 for c in 0..N {
217 self.data[r][c] = value;
218 }
219 }
220 }
221}
222
223macro_rules! validate_n {
224 ($n:expr) => {
225 if $n == 0 {
226 return Err(MatrixError::InvalidN($n));
227 }
228 };
229}
230
231impl TryFrom<u8> for MatrixDyn {
232 type Error = MatrixError;
233 fn try_from(n: u8) -> Result<Self, Self::Error> {
234 validate_n!(n);
235
236 let n_usize = n as usize;
237 let data = vec![0u8; n_usize * n_usize];
238 Ok(Self { n, data })
239 }
240}
241
242impl TryFrom<MatrixDyn> for Asn1Matrix {
243 type Error = crate::matrix::MatrixError;
244
245 fn try_from(mut matrix: MatrixDyn) -> Result<Self, Self::Error> {
246 let n = matrix.n();
247 validate_n!(n);
248
249 let expected_len = (n as usize) * (n as usize);
251 if matrix.data.len() != expected_len {
252 return Err(crate::matrix::MatrixError::LengthMismatch { n, len: matrix.data.len() });
253 }
254
255 let data = std::mem::take(&mut matrix.data);
256 Ok(Self { n, data })
257 }
258}
259
260macro_rules! asn1_to_matrix_dyn_impl {
261 ($matrix:expr) => {{
262 let n = $matrix.n;
263 validate_n!(n);
264
265 let n_u8 = n as u8;
266 let n2 = n_u8 as usize * n_u8 as usize;
267 if $matrix.data.len() != n2 {
268 return Err(MatrixError::LengthMismatch { n, len: $matrix.data.len() });
269 }
270 }};
271}
272
273impl TryFrom<Asn1Matrix> for MatrixDyn {
274 type Error = MatrixError;
275 fn try_from(m: Asn1Matrix) -> Result<Self, Self::Error> {
276 asn1_to_matrix_dyn_impl!(m);
277
278 let mut m = m;
279 let data = core::mem::take(&mut m.data);
280 let len = data.len();
281
282 MatrixDyn::from_row_major(m.n, data).ok_or(MatrixError::LengthMismatch { n: m.n, len })
283 }
284}
285
286impl TryFrom<&Asn1Matrix> for MatrixDyn {
287 type Error = MatrixError;
288 fn try_from(m: &Asn1Matrix) -> Result<Self, Self::Error> {
289 asn1_to_matrix_dyn_impl!(m);
290 let n_u8 = m.n;
291
292 let mut md = MatrixDyn::try_from(n_u8)?;
293 let mut i = 0usize;
294 for r in 0..n_u8 {
295 for c in 0..n_u8 {
296 md.set(r, c, m.data[i]);
297 i += 1;
298 }
299 }
300
301 Ok(md)
302 }
303}
304
305impl TryFrom<Option<Asn1Matrix>> for MatrixDyn {
306 type Error = MatrixError;
307 fn try_from(m: Option<Asn1Matrix>) -> Result<Self, Self::Error> {
308 match m {
309 Some(m) => Self::try_from(m),
310 None => Ok(Default::default()),
311 }
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318
319 #[test]
320 #[cfg(feature = "std")]
321 fn test_matrix_like_reality_end_to_end() -> crate::error::Result<()> {
322 let bytes: Vec<u8> = (0u8..9u8).collect();
324 let mut dyn_m = MatrixDyn::from_row_major(3, bytes.clone()).expect("n*n bytes");
325 let mut stat_m: Matrix<3> = Matrix::<3>::from_row_major(&bytes);
326
327 fn paint_diag<M: MatrixLike>(m: &mut M) {
329 let n = m.n();
330 m.clear();
332 for i in 0..n {
333 m.set(i, i, 1);
334 }
335 }
336
337 assert_eq!(dyn_m.n(), 3);
339 assert_eq!(stat_m.n(), 3);
340
341 assert_eq!(dyn_m.row(1).unwrap(), &[3, 4, 5]);
343 assert_eq!(stat_m.row(1).unwrap().as_slice(), &[3, 4, 5]);
344
345 assert_eq!(dyn_m.get(2, 2), 8);
347 assert_eq!(stat_m.get(0, 2), 2);
348
349 paint_diag(&mut dyn_m);
351 paint_diag(&mut stat_m);
352
353 for r in 0..3 {
355 for c in 0..3 {
356 let dv = dyn_m.get(r, c);
357 let sv = stat_m.get(r, c);
358 if r == c {
359 assert_eq!(dv, 1);
360 assert_eq!(sv, 1);
361 } else {
362 assert_eq!(dv, 0);
363 assert_eq!(sv, 0);
364 }
365 }
366 }
367
368 dyn_m.fill(7);
370 for r in 0..3 {
371 for c in 0..3 {
372 assert_eq!(dyn_m.get(r, c), 7);
373 }
374 }
375 dyn_m.clear();
376 for r in 0..3 {
377 for c in 0..3 {
378 assert_eq!(dyn_m.get(r, c), 0);
379 }
380 }
381
382 assert_eq!(dyn_m.as_bytes().len(), 9);
384 let stat_bytes = Matrix::<3>::from_row_major(&bytes);
385 assert_eq!(stat_bytes.row(0).unwrap(), &[0, 1, 2]);
386
387 assert!(MatrixDyn::from_row_major(3, vec![0u8; 8]).is_none());
389
390 Ok(())
391 }
392
393 #[test]
394 #[cfg(feature = "std")]
395 fn test_matrix_specification_compliance() -> crate::error::Result<()> {
396 let test_matrices = vec![
398 (1u8, vec![42u8]),
399 (2u8, vec![1, 2, 3, 4]),
400 (3u8, (0u8..9u8).collect()),
401 (255u8, vec![0u8; 255 * 255]),
402 ];
403
404 for (n, data) in &test_matrices {
406 let asn1_matrix = Asn1Matrix { n: *n, data: data.clone() };
408
409 assert!(*n >= 1);
411
412 let expected_len = (*n as usize) * (*n as usize);
414 assert_eq!(data.len(), expected_len);
415
416 let matrix_dyn = MatrixDyn::try_from(&asn1_matrix)?;
418 assert_eq!(matrix_dyn.n(), *n);
419 assert_eq!(matrix_dyn.as_bytes(), data.as_slice());
420 }
421
422 let invalid_n = MatrixDyn::try_from(0u8);
424 assert!(invalid_n.is_err());
425
426 let invalid_asn1 = Asn1Matrix { n: 2, data: vec![1, 2, 3] }; let invalid_conversion = MatrixDyn::try_from(invalid_asn1);
429 assert!(invalid_conversion.is_err());
430
431 let matrix_3x3 = MatrixDyn::try_from(3u8)?;
434 let mut test_matrix = matrix_3x3;
435 for r in 0..3 {
436 for c in 0..3 {
437 let value = (r + 1) * 10 + c;
438 test_matrix.set(r, c, value);
439 }
440 }
441
442 let expected_bytes = vec![10, 11, 12, 20, 21, 22, 30, 31, 32];
444 assert_eq!(test_matrix.as_bytes(), expected_bytes.as_slice());
445
446 let mut matrix = MatrixDyn::try_from(2u8)?;
448
449 matrix.set(0, 1, 99);
451 assert_eq!(matrix.get(0, 1), 99);
452
453 assert_eq!(matrix.get(5, 5), 0);
455 matrix.set(5, 5, 123); matrix.fill(77);
459 for r in 0..2 {
460 for c in 0..2 {
461 assert_eq!(matrix.get(r, c), 77);
462 }
463 }
464
465 matrix.clear();
467 for r in 0..2 {
468 for c in 0..2 {
469 assert_eq!(matrix.get(r, c), 0);
470 }
471 }
472
473 let static_matrix: Matrix<3> = Matrix::from_row_major(&[1, 2, 3, 4, 5, 6, 7, 8, 9]);
475 let dynamic_matrix = MatrixDyn::from_row_major(3, vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap();
476 for r in 0..3 {
477 for c in 0..3 {
478 assert_eq!(static_matrix.get(r, c), dynamic_matrix.get(r, c));
479 }
480 }
481
482 Ok(())
483 }
484}