use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Archive, RkyvSerialize, RkyvDeserialize)]
pub enum Throughput {
Bytes(u64),
Elements(u64),
}
impl Throughput {
pub fn per_second(self, mean_ns: f64) -> Option<f64> {
let amount = match self {
Throughput::Bytes(n) | Throughput::Elements(n) => n as f64,
};
(mean_ns.is_finite() && mean_ns > 0.0).then(|| amount * 1e9 / mean_ns)
}
}
#[cfg(test)]
mod tests {
use super::*;
use rkyv::rancor;
#[test]
fn per_second_scales_by_mean() {
assert_eq!(
Throughput::Bytes(1024).per_second(1_000.0),
Some(1_024_000_000.0)
);
assert_eq!(Throughput::Elements(4).per_second(2.0), Some(2e9));
}
#[test]
fn per_second_rejects_zero_and_bad_means() {
assert_eq!(Throughput::Bytes(8).per_second(0.0), None);
assert_eq!(Throughput::Bytes(8).per_second(-1.0), None);
assert_eq!(Throughput::Bytes(8).per_second(f64::NAN), None);
assert_eq!(Throughput::Bytes(8).per_second(f64::INFINITY), None);
}
#[test]
fn rkyv_roundtrip() {
for original in [Throughput::Bytes(7), Throughput::Elements(u64::MAX)] {
let bytes = rkyv::to_bytes::<rancor::Error>(&original).unwrap();
let decoded = rkyv::from_bytes::<Throughput, rancor::Error>(&bytes).unwrap();
assert_eq!(original, decoded);
}
}
}