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