criterion_plot/
data.rs

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}