plotpy/
as_matrix.rs

1/// Defines a trait to handle Matrix-like data
2///
3/// # Example
4///
5/// ```
6/// use plotpy::AsMatrix;
7///
8/// fn sum<'a, T, U>(array: &'a T) -> f64
9/// where
10///     T: AsMatrix<'a, U>,
11///     U: 'a + Into<f64>,
12/// {
13///     let mut res = 0.0;
14///     let (m, n) = array.size();
15///     for i in 0..m {
16///         for j in 0..n {
17///             res += array.at(i, j).into();
18///         }
19///     }
20///     res
21/// }
22///
23/// // heap-allocated 2D array (vector of vectors)
24/// const IGNORED: f64 = 123.456;
25/// let a = vec![
26///     vec![1.0, 2.0],
27///     vec![3.0, 4.0, IGNORED, IGNORED, IGNORED],
28///     vec![5.0, 6.0],
29/// ];
30/// assert_eq!(sum(&a), 21.0);
31///
32/// // heap-allocated 2D array (aka slice of slices)
33/// let b: &[&[f64]] = &[
34///     &[10.0, 20.0],
35///     &[30.0, 40.0, IGNORED],
36///     &[50.0, 60.0, IGNORED, IGNORED],
37/// ];
38/// assert_eq!(sum(&b), 210.0);
39///
40/// // stack-allocated (fixed-size) 2D array
41/// let c = [
42///     [100.0, 200.0],
43///     [300.0, 400.0],
44///     [500.0, 600.0],
45/// ];
46/// assert_eq!(sum(&c), 2100.0);
47/// ```
48pub trait AsMatrix<'a, U: 'a> {
49    /// Returns the size of the matrix
50    fn size(&self) -> (usize, usize);
51
52    /// Returns the value at index i
53    fn at(&self, i: usize, j: usize) -> U;
54}
55
56/// Defines a heap-allocated 2D array (vector of vectors)
57///
58/// # Notes
59///
60/// * The number of columns is defined by the first row
61/// * The next rows must have at least the same number of columns as the first row
62impl<'a, U: 'a> AsMatrix<'a, U> for Vec<Vec<U>>
63where
64    U: 'a + Copy,
65{
66    fn size(&self) -> (usize, usize) {
67        (self.len(), self[0].len())
68    }
69    fn at(&self, i: usize, j: usize) -> U {
70        self[i][j]
71    }
72}
73
74/// Defines a heap-allocated 2D array (slice of slices)
75///
76/// # Notes
77///
78/// * The number of columns is defined by the first row
79/// * The next rows must have at least the same number of columns as the first row
80impl<'a, U> AsMatrix<'a, U> for &'a [&'a [U]]
81where
82    U: 'a + Copy,
83{
84    fn size(&self) -> (usize, usize) {
85        (self.len(), self[0].len())
86    }
87    fn at(&self, i: usize, j: usize) -> U {
88        self[i][j]
89    }
90}
91
92/// Defines a stack-allocated (fixed-size) 2D array
93impl<'a, U, const M: usize, const N: usize> AsMatrix<'a, U> for [[U; N]; M]
94where
95    U: 'a + Copy,
96{
97    fn size(&self) -> (usize, usize) {
98        (self.len(), self[0].len())
99    }
100    fn at(&self, i: usize, j: usize) -> U {
101        self[i][j]
102    }
103}
104
105////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
106
107#[cfg(test)]
108mod tests {
109    use super::AsMatrix;
110    use std::fmt::Write;
111
112    fn matrix_str<'a, T, U>(array: &'a T) -> String
113    where
114        T: AsMatrix<'a, U>,
115        U: 'a + std::fmt::Display,
116    {
117        let mut buf = String::new();
118        let (m, n) = array.size();
119        for i in 0..m {
120            for j in 0..n {
121                write!(&mut buf, "{},", array.at(i, j)).unwrap();
122            }
123            write!(&mut buf, "\n").unwrap();
124        }
125        buf
126    }
127
128    #[test]
129    fn as_matrix_works() {
130        // heap-allocated 2D array (vector of vectors)
131        const IGNORED: f64 = 123.456;
132        let a = vec![
133            vec![1.0, 2.0],
134            vec![3.0, 4.0, IGNORED, IGNORED, IGNORED],
135            vec![5.0, 6.0],
136        ];
137        assert_eq!(
138            matrix_str(&a),
139            "1,2,\n\
140             3,4,\n\
141             5,6,\n"
142        );
143
144        // heap-allocated 2D array (aka slice of slices)
145        let b: &[&[f64]] = &[&[10.0, 20.0], &[30.0, 40.0, IGNORED], &[50.0, 60.0, IGNORED, IGNORED]];
146        assert_eq!(
147            matrix_str(&b),
148            "10,20,\n\
149             30,40,\n\
150             50,60,\n"
151        );
152
153        // stack-allocated (fixed-size) 2D array
154        let c = [[100.0, 200.0], [300.0, 400.0], [500.0, 600.0]];
155        assert_eq!(
156            matrix_str(&c),
157            "100,200,\n\
158             300,400,\n\
159             500,600,\n"
160        );
161    }
162}