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