1use std::mem;
2
3use cast::From as _0;
4
5use crate::traits::Data;
6
7macro_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
25impl_data!(f32, f64, i16, i32, i64, i8, isize, u16, u32, u64, u8, usize);
26
27#[derive(Clone)]
28pub struct Matrix {
29 bytes: Vec<u8>,
30 ncols: usize,
31 nrows: usize,
32}
33
34impl 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
71pub 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
81fn 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
85impl<A, B> Row for (A, B)
86where
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
104impl<A, B, C> Row for (A, B, C)
105where
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
125impl<A, B, C, D> Row for (A, B, C, D)
126where
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
148impl<A, B, C, D, E> Row for (A, B, C, D, E)
149where
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