1 | use std::mem; |
2 | |
3 | use cast::From as _0; |
4 | |
5 | use crate::traits::Data; |
6 | |
7 | macro_rules! impl_data { |
8 | ($($ty:ty),+) => { |
9 | $( |
10 | impl Data for $ty { |
11 | fn f64(self) -> f64 { |
12 | f64::cast(self) |
13 | } |
14 | } |
15 | |
16 | impl<'a> Data for &'a $ty { |
17 | fn f64(self) -> f64 { |
18 | f64::cast(*self) |
19 | } |
20 | } |
21 | )+ |
22 | } |
23 | } |
24 | |
25 | impl_data!(f32, f64, i16, i32, i64, i8, isize, u16, u32, u64, u8, usize); |
26 | |
27 | #[derive(Clone)] |
28 | pub struct Matrix { |
29 | bytes: Vec<u8>, |
30 | ncols: usize, |
31 | nrows: usize, |
32 | } |
33 | |
34 | impl Matrix { |
35 | pub fn new<I>(rows: I, scale: <I::Item as Row>::Scale) -> Matrix |
36 | where |
37 | I: Iterator, |
38 | I::Item: Row, |
39 | { |
40 | let ncols = I::Item::ncols(); |
41 | let bytes_per_row = ncols * mem::size_of::<f64>(); |
42 | let mut bytes = Vec::with_capacity(rows.size_hint().0 * bytes_per_row); |
43 | |
44 | let mut nrows = 0; |
45 | for row in rows { |
46 | nrows += 1; |
47 | row.append_to(&mut bytes, scale); |
48 | } |
49 | |
50 | Matrix { |
51 | bytes, |
52 | ncols, |
53 | nrows, |
54 | } |
55 | } |
56 | |
57 | pub fn bytes(&self) -> &[u8] { |
58 | &self.bytes |
59 | } |
60 | |
61 | pub fn ncols(&self) -> usize { |
62 | self.ncols |
63 | } |
64 | |
65 | pub fn nrows(&self) -> usize { |
66 | self.nrows |
67 | } |
68 | } |
69 | |
70 | /// Data that can serve as a row of the data matrix |
71 | pub trait Row { |
72 | /// Private |
73 | type Scale: Copy; |
74 | |
75 | /// Append this row to a buffer |
76 | fn append_to(self, buffer: &mut Vec<u8>, scale: Self::Scale); |
77 | /// Number of columns of the row |
78 | fn ncols() -> usize; |
79 | } |
80 | |
81 | fn write_f64(w: &mut impl std::io::Write, f: f64) -> std::io::Result<()> { |
82 | w.write_all(&f.to_bits().to_le_bytes()) |
83 | } |
84 | |
85 | impl<A, B> Row for (A, B) |
86 | where |
87 | A: Data, |
88 | B: Data, |
89 | { |
90 | type Scale = (f64, f64); |
91 | |
92 | fn append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64)) { |
93 | let (a, b) = self; |
94 | |
95 | write_f64(buffer, a.f64() * scale.0).unwrap(); |
96 | write_f64(buffer, b.f64() * scale.1).unwrap(); |
97 | } |
98 | |
99 | fn ncols() -> usize { |
100 | 2 |
101 | } |
102 | } |
103 | |
104 | impl<A, B, C> Row for (A, B, C) |
105 | where |
106 | A: Data, |
107 | B: Data, |
108 | C: Data, |
109 | { |
110 | type Scale = (f64, f64, f64); |
111 | |
112 | fn append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64, f64)) { |
113 | let (a, b, c) = self; |
114 | |
115 | write_f64(buffer, a.f64() * scale.0).unwrap(); |
116 | write_f64(buffer, b.f64() * scale.1).unwrap(); |
117 | write_f64(buffer, c.f64() * scale.2).unwrap(); |
118 | } |
119 | |
120 | fn ncols() -> usize { |
121 | 3 |
122 | } |
123 | } |
124 | |
125 | impl<A, B, C, D> Row for (A, B, C, D) |
126 | where |
127 | A: Data, |
128 | B: Data, |
129 | C: Data, |
130 | D: Data, |
131 | { |
132 | type Scale = (f64, f64, f64, f64); |
133 | |
134 | fn append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64, f64, f64)) { |
135 | let (a, b, c, d) = self; |
136 | |
137 | write_f64(buffer, a.f64() * scale.0).unwrap(); |
138 | write_f64(buffer, b.f64() * scale.1).unwrap(); |
139 | write_f64(buffer, c.f64() * scale.2).unwrap(); |
140 | write_f64(buffer, d.f64() * scale.3).unwrap(); |
141 | } |
142 | |
143 | fn ncols() -> usize { |
144 | 4 |
145 | } |
146 | } |
147 | |
148 | impl<A, B, C, D, E> Row for (A, B, C, D, E) |
149 | where |
150 | A: Data, |
151 | B: Data, |
152 | C: Data, |
153 | D: Data, |
154 | E: Data, |
155 | { |
156 | type Scale = (f64, f64, f64, f64, f64); |
157 | |
158 | #[cfg_attr (feature = "cargo-clippy" , allow(clippy::many_single_char_names))] |
159 | fn append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64, f64, f64, f64)) { |
160 | let (a, b, c, d, e) = self; |
161 | |
162 | write_f64(buffer, a.f64() * scale.0).unwrap(); |
163 | write_f64(buffer, b.f64() * scale.1).unwrap(); |
164 | write_f64(buffer, c.f64() * scale.2).unwrap(); |
165 | write_f64(buffer, d.f64() * scale.3).unwrap(); |
166 | write_f64(buffer, e.f64() * scale.4).unwrap(); |
167 | } |
168 | |
169 | fn ncols() -> usize { |
170 | 5 |
171 | } |
172 | } |
173 | |