1#[cfg(not(feature = "std"))]
2use alloc::vec::Vec;
3
4use crate::Asn1Matrix;
5
6#[cfg(feature = "derive")]
7use crate::Errorizable;
8
9pub type MatrixResult<T> = core::result::Result<T, MatrixError>;
10
11#[cfg_attr(feature = "derive", derive(Errorizable))]
12#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
13pub enum MatrixError {
14 #[cfg_attr(feature = "derive", error("Asn1Matrix: n MUST be in 1..=255 (got {0})"))]
15 InvalidN(u8),
16 #[cfg_attr(
17 feature = "derive",
18 error("Asn1Matrix: data length MUST equal n*n (n={n}, len={len})")
19 )]
20 LengthMismatch { n: u8, len: usize },
21}
22
23crate::impl_error_display!(MatrixError {
24 InvalidN(n) => "Asn1Matrix: n MUST be in 1..=255 (got {n})",
25 LengthMismatch { n, len } => "Asn1Matrix: data length MUST equal n*n (n={n}, len={len})",
26});
27
28pub trait MatrixLike {
30 fn n(&self) -> u8;
32
33 fn get(&self, r: u8, c: u8) -> u8;
35
36 fn set(&mut self, r: u8, c: u8, value: u8);
38
39 fn fill(&mut self, value: u8);
41
42 fn clear(&mut self) {
44 self.fill(0);
45 }
46}
47
48pub trait IntoMatrixDyn {
51 fn into_matrix_dyn(self) -> Result<MatrixDyn, MatrixError>;
52}
53
54impl IntoMatrixDyn for MatrixDyn {
56 fn into_matrix_dyn(self) -> Result<MatrixDyn, MatrixError> {
57 Ok(self)
58 }
59}
60
61impl<M> IntoMatrixDyn for M
63where
64 M: MatrixLike,
65 MatrixDyn: TryFrom<M, Error = MatrixError>,
66{
67 fn into_matrix_dyn(self) -> Result<MatrixDyn, MatrixError> {
68 MatrixDyn::try_from(self)
69 }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq)]
74pub struct MatrixDyn {
75 n: u8,
76 data: Vec<u8>,
77}
78
79impl Default for MatrixDyn {
80 fn default() -> Self {
83 Self { n: 1, data: vec![0u8; 1] }
84 }
85}
86
87impl MatrixDyn {
88 pub fn from_row_major(n: u8, bytes: Vec<u8>) -> Option<Self> {
90 if n == 0 {
91 return None;
92 }
93
94 let n_usize = n as usize;
95 if bytes.len() == n_usize * n_usize {
96 Some(Self { n, data: bytes })
97 } else {
98 None
99 }
100 }
101
102 #[inline]
106 fn idx(&self, r: u8, c: u8) -> Option<usize> {
107 let n = self.n as usize;
108 let (ru, cu) = (r as usize, c as usize);
109 (ru < n && cu < n).then(|| ru * n + cu).filter(|i| *i < self.data.len())
110 }
111
112 pub fn as_bytes(&self) -> &[u8] {
114 &self.data
115 }
116
117 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
119 &mut self.data
120 }
121
122 pub fn row(&self, r: u8) -> Option<&[u8]> {
124 if r >= self.n {
125 return None;
126 }
127
128 let n = self.n as usize;
129 let start = r as usize * n;
130 self.data.get(start..start + n)
131 }
132}
133
134impl MatrixLike for MatrixDyn {
135 fn n(&self) -> u8 {
136 self.n
137 }
138
139 fn get(&self, r: u8, c: u8) -> u8 {
140 self.idx(r, c).map(|i| self.data[i]).unwrap_or(0)
141 }
142
143 fn set(&mut self, r: u8, c: u8, value: u8) {
144 if let Some(i) = self.idx(r, c) {
145 self.data[i] = value;
146 }
147 }
148
149 fn fill(&mut self, value: u8) {
150 for b in &mut self.data {
151 *b = value;
152 }
153 }
154}
155
156#[derive(Debug, Clone, Copy, PartialEq, Eq)]
167pub struct Matrix<const N: usize> {
168 data: [[u8; N]; N],
169}
170
171impl<const N: usize> Default for Matrix<N> {
172 fn default() -> Self {
173 const { Self::VALID_N };
174 Self { data: [[0u8; N]; N] }
175 }
176}
177
178impl<const N: usize> Matrix<N> {
179 const VALID_N: () = assert!(N >= 1 && N <= 255, "Matrix dimension must be 1..=255");
183
184 pub fn new() -> Self {
186 Self::default()
187 }
188
189 pub fn from_row_major(bytes: &[u8]) -> Self {
192 let mut m = Self::default();
193 let mut i = 0usize;
194 for r in 0..N {
195 for c in 0..N {
196 if i < bytes.len() {
197 m.data[r][c] = bytes[i];
198 }
199 i += 1;
200 }
201 }
202 m
203 }
204
205 pub fn row(&self, r: u8) -> Option<&[u8; N]> {
207 if (r as usize) < N {
208 Some(&self.data[r as usize])
209 } else {
210 None
211 }
212 }
213}
214
215impl<const N: usize> MatrixLike for Matrix<N> {
216 fn n(&self) -> u8 {
217 N as u8
218 }
219
220 fn get(&self, r: u8, c: u8) -> u8 {
221 if (r as usize) < N && (c as usize) < N {
222 self.data[r as usize][c as usize]
223 } else {
224 0
225 }
226 }
227
228 fn set(&mut self, r: u8, c: u8, value: u8) {
229 if (r as usize) < N && (c as usize) < N {
230 self.data[r as usize][c as usize] = value;
231 }
232 }
233
234 fn fill(&mut self, value: u8) {
235 for r in 0..N {
236 for c in 0..N {
237 self.data[r][c] = value;
238 }
239 }
240 }
241}
242
243macro_rules! validate_n {
244 ($n:expr) => {
245 if $n == 0 {
246 return Err(MatrixError::InvalidN($n));
247 }
248 };
249}
250
251impl TryFrom<u8> for MatrixDyn {
252 type Error = MatrixError;
253 fn try_from(n: u8) -> Result<Self, Self::Error> {
254 validate_n!(n);
255
256 let n_usize = n as usize;
257 let data = vec![0u8; n_usize * n_usize];
258 Ok(Self { n, data })
259 }
260}
261
262impl TryFrom<MatrixDyn> for Asn1Matrix {
263 type Error = crate::matrix::MatrixError;
264
265 fn try_from(mut matrix: MatrixDyn) -> Result<Self, Self::Error> {
266 let n = matrix.n();
267 validate_n!(n);
268
269 let expected_len = (n as usize) * (n as usize);
271 if matrix.data.len() != expected_len {
272 return Err(crate::matrix::MatrixError::LengthMismatch { n, len: matrix.data.len() });
273 }
274
275 let data = core::mem::take(&mut matrix.data);
276 Ok(Self { n, data })
277 }
278}
279
280macro_rules! asn1_to_matrix_dyn_impl {
281 ($matrix:expr) => {{
282 let n = $matrix.n;
283 validate_n!(n);
284
285 let n_u8 = n as u8;
286 let n2 = n_u8 as usize * n_u8 as usize;
287 if $matrix.data.len() != n2 {
288 return Err(MatrixError::LengthMismatch { n, len: $matrix.data.len() });
289 }
290 }};
291}
292
293impl TryFrom<Asn1Matrix> for MatrixDyn {
294 type Error = MatrixError;
295 fn try_from(m: Asn1Matrix) -> Result<Self, Self::Error> {
296 asn1_to_matrix_dyn_impl!(m);
297
298 let mut m = m;
299 let data = core::mem::take(&mut m.data);
300 let len = data.len();
301
302 MatrixDyn::from_row_major(m.n, data).ok_or(MatrixError::LengthMismatch { n: m.n, len })
303 }
304}
305
306impl TryFrom<&Asn1Matrix> for MatrixDyn {
307 type Error = MatrixError;
308 fn try_from(m: &Asn1Matrix) -> Result<Self, Self::Error> {
309 asn1_to_matrix_dyn_impl!(m);
310
311 MatrixDyn::from_row_major(m.n, m.data.clone()).ok_or(MatrixError::LengthMismatch { n: m.n, len: m.data.len() })
312 }
313}
314
315impl TryFrom<Option<Asn1Matrix>> for MatrixDyn {
316 type Error = MatrixError;
317 fn try_from(m: Option<Asn1Matrix>) -> Result<Self, Self::Error> {
318 match m {
319 Some(m) => Self::try_from(m),
320 None => Ok(Default::default()),
321 }
322 }
323}
324
325#[cfg(test)]
326mod tests {
327 use super::*;
328
329 #[test]
330 #[cfg(feature = "std")]
331 fn default_matrix_dyn_upholds_invariant() {
332 let matrix = MatrixDyn::default();
333 assert_eq!(matrix.n(), 1);
334 assert_eq!(matrix.as_bytes(), &[0u8]);
335 assert_eq!(matrix.get(0, 0), 0);
336 assert!(matrix.row(0).is_some());
337 }
338
339 #[test]
340 #[cfg(feature = "std")]
341 fn absent_asn1_matrix_converts_to_valid_default() -> crate::error::Result<()> {
342 let matrix = MatrixDyn::try_from(None::<Asn1Matrix>)?;
343 assert_eq!(matrix.n(), 1);
344 assert_eq!(matrix.get(0, 0), 0);
345 assert!(matrix.row(0).is_some());
346
347 Ok(())
348 }
349
350 #[test]
351 #[cfg(feature = "std")]
352 fn test_matrix_like_reality_end_to_end() -> crate::error::Result<()> {
353 let bytes: Vec<u8> = (0u8..9u8).collect();
355 let mut dyn_m = MatrixDyn::from_row_major(3, bytes.clone()).expect("n*n bytes");
356 let mut stat_m: Matrix<3> = Matrix::<3>::from_row_major(&bytes);
357
358 fn paint_diag<M: MatrixLike>(m: &mut M) {
360 let n = m.n();
361 m.clear();
363 for i in 0..n {
364 m.set(i, i, 1);
365 }
366 }
367
368 assert_eq!(dyn_m.n(), 3);
370 assert_eq!(stat_m.n(), 3);
371
372 assert_eq!(
374 dyn_m.row(1).ok_or(crate::testing::error::TestingError::InvariantViolated)?,
375 &[3, 4, 5]
376 );
377 assert_eq!(
378 stat_m
379 .row(1)
380 .ok_or(crate::testing::error::TestingError::InvariantViolated)?
381 .as_slice(),
382 &[3, 4, 5]
383 );
384
385 assert_eq!(dyn_m.get(2, 2), 8);
387 assert_eq!(stat_m.get(0, 2), 2);
388
389 paint_diag(&mut dyn_m);
391 paint_diag(&mut stat_m);
392
393 for r in 0..3 {
395 for c in 0..3 {
396 let dv = dyn_m.get(r, c);
397 let sv = stat_m.get(r, c);
398 if r == c {
399 assert_eq!(dv, 1);
400 assert_eq!(sv, 1);
401 } else {
402 assert_eq!(dv, 0);
403 assert_eq!(sv, 0);
404 }
405 }
406 }
407
408 dyn_m.fill(7);
410 for r in 0..3 {
411 for c in 0..3 {
412 assert_eq!(dyn_m.get(r, c), 7);
413 }
414 }
415 dyn_m.clear();
416 for r in 0..3 {
417 for c in 0..3 {
418 assert_eq!(dyn_m.get(r, c), 0);
419 }
420 }
421
422 assert_eq!(dyn_m.as_bytes().len(), 9);
424
425 let stat_bytes = Matrix::<3>::from_row_major(&bytes);
426 assert_eq!(
427 stat_bytes
428 .row(0)
429 .ok_or(crate::testing::error::TestingError::InvariantViolated)?,
430 &[0, 1, 2]
431 );
432
433 assert!(MatrixDyn::from_row_major(3, vec![0u8; 8]).is_none());
435
436 Ok(())
437 }
438
439 #[test]
440 #[cfg(feature = "std")]
441 fn test_matrix_specification_compliance() -> crate::error::Result<()> {
442 let test_matrices = vec![
444 (1u8, vec![42u8]),
445 (2u8, vec![1, 2, 3, 4]),
446 (3u8, (0u8..9u8).collect()),
447 (255u8, vec![0u8; 255 * 255]),
448 ];
449
450 for (n, data) in &test_matrices {
452 let asn1_matrix = Asn1Matrix { n: *n, data: data.clone() };
454 assert!(*n >= 1);
456
457 let expected_len = (*n as usize) * (*n as usize);
459 assert_eq!(data.len(), expected_len);
460
461 let matrix_dyn = MatrixDyn::try_from(&asn1_matrix)?;
463 assert_eq!(matrix_dyn.n(), *n);
464 assert_eq!(matrix_dyn.as_bytes(), data.as_slice());
465 }
466
467 let invalid_n = MatrixDyn::try_from(0u8);
469 assert!(invalid_n.is_err());
470
471 let invalid_asn1 = Asn1Matrix { n: 2, data: vec![1, 2, 3] }; let invalid_conversion = MatrixDyn::try_from(invalid_asn1);
474 assert!(invalid_conversion.is_err());
475
476 let matrix_3x3 = MatrixDyn::try_from(3u8)?;
479 let mut test_matrix = matrix_3x3;
480 for r in 0..3 {
481 for c in 0..3 {
482 let value = (r + 1) * 10 + c;
483 test_matrix.set(r, c, value);
484 }
485 }
486
487 let expected_bytes = vec![10, 11, 12, 20, 21, 22, 30, 31, 32];
489 assert_eq!(test_matrix.as_bytes(), expected_bytes.as_slice());
490
491 let mut matrix = MatrixDyn::try_from(2u8)?;
493
494 matrix.set(0, 1, 99);
496 assert_eq!(matrix.get(0, 1), 99);
497
498 assert_eq!(matrix.get(5, 5), 0);
500 matrix.set(5, 5, 123); matrix.fill(77);
504 for r in 0..2 {
505 for c in 0..2 {
506 assert_eq!(matrix.get(r, c), 77);
507 }
508 }
509
510 matrix.clear();
512 for r in 0..2 {
513 for c in 0..2 {
514 assert_eq!(matrix.get(r, c), 0);
515 }
516 }
517
518 let static_matrix: Matrix<3> = Matrix::from_row_major(&[1, 2, 3, 4, 5, 6, 7, 8, 9]);
520 let dynamic_matrix = MatrixDyn::from_row_major(3, vec![1, 2, 3, 4, 5, 6, 7, 8, 9]).unwrap();
521 for r in 0..3 {
522 for c in 0..3 {
523 assert_eq!(static_matrix.get(r, c), dynamic_matrix.get(r, c));
524 }
525 }
526
527 Ok(())
528 }
529}