use core::fmt;
use crate::MeasurementSummary;
#[cfg(test)]
mod tests;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct HistogramBoundsError {
index: usize,
}
impl HistogramBoundsError {
#[must_use]
pub const fn index(self) -> usize {
self.index
}
}
impl fmt::Display for HistogramBoundsError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"histogram bound {} is not strictly increasing",
self.index
)
}
}
impl core::error::Error for HistogramBoundsError {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct MeasurementHistogram<const N: usize> {
upper_bounds: [u64; N],
bucket_counts: [u64; N],
overflow: u64,
summary: MeasurementSummary,
}
impl<const N: usize> MeasurementHistogram<N> {
pub const fn new(upper_bounds: [u64; N]) -> Result<Self, HistogramBoundsError> {
let mut index = 1;
while index < N {
if upper_bounds[index - 1] >= upper_bounds[index] {
return Err(HistogramBoundsError { index });
}
index += 1;
}
Ok(Self {
upper_bounds,
bucket_counts: [0; N],
overflow: 0,
summary: MeasurementSummary::EMPTY,
})
}
pub const fn record(&mut self, value: u64) {
self.summary.record(value);
let mut index = 0;
while index < N {
if value <= self.upper_bounds[index] {
self.bucket_counts[index] = self.bucket_counts[index].saturating_add(1);
return;
}
index += 1;
}
self.overflow = self.overflow.saturating_add(1);
}
#[must_use]
pub const fn upper_bounds(&self) -> &[u64; N] {
&self.upper_bounds
}
#[must_use]
pub const fn bucket_counts(&self) -> &[u64; N] {
&self.bucket_counts
}
#[must_use]
pub const fn overflow(&self) -> u64 {
self.overflow
}
#[must_use]
pub const fn summary(&self) -> MeasurementSummary {
self.summary
}
}