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 {
new<I>(rows: I, scale: <I::Item as Row>::Scale) -> Matrix where I: Iterator, I::Item: Row,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
bytes(&self) -> &[u8]57 pub fn bytes(&self) -> &[u8] {
58 &self.bytes
59 }
60
ncols(&self) -> usize61 pub fn ncols(&self) -> usize {
62 self.ncols
63 }
64
nrows(&self) -> usize65 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
append_to(self, buffer: &mut Vec<u8>, scale: Self::Scale)76 fn append_to(self, buffer: &mut Vec<u8>, scale: Self::Scale);
77 /// Number of columns of the row
ncols() -> usize78 fn ncols() -> usize;
79 }
80
write_f64(w: &mut impl std::io::Write, f: f64) -> std::io::Result<()>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
append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64))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
ncols() -> usize99 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
append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64, f64))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
ncols() -> usize120 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
append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64, f64, f64))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
ncols() -> usize143 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))]
append_to(self, buffer: &mut Vec<u8>, scale: (f64, f64, f64, f64, f64))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
ncols() -> usize169 fn ncols() -> usize {
170 5
171 }
172 }
173