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}