use crate::{Metric, Value};
use std::sync::OnceLock;
use std::time::Duration;
use heatmap::Instant;
pub use ::heatmap::Error as HeatmapError;
pub use ::heatmap::Iter as HeatmapIter;
pub use ::histogram::Bucket;
pub struct Heatmap {
inner: OnceLock<heatmap::Heatmap>,
m: u32,
r: u32,
n: u32,
span: Duration,
resolution: Duration,
}
impl Heatmap {
pub const fn new(m: u32, r: u32, n: u32, span: Duration, resolution: Duration) -> Self {
Self {
m,
r,
n,
span,
resolution,
inner: OnceLock::new(),
}
}
pub fn percentile(&self, percentile: f64) -> Option<Result<Bucket, HeatmapError>> {
self.inner
.get()
.map(|heatmap| heatmap.percentile(percentile))
}
pub fn increment(&self, time: Instant, value: u64) -> Result<(), HeatmapError> {
self.add(time, value, 1)
}
pub fn add(&self, time: Instant, value: u64, count: u32) -> Result<(), HeatmapError> {
self.get_or_init().increment(time, value, count)
}
pub fn iter(&self) -> Option<HeatmapIter> {
self.inner.get().map(|heatmap| heatmap.iter())
}
fn get_or_init(&self) -> &::heatmap::Heatmap {
self.inner.get_or_init(|| {
::heatmap::Heatmap::new(
self.m,
self.r,
self.n,
::heatmap::Duration::from_nanos(self.span.as_nanos() as u64),
::heatmap::Duration::from_nanos(self.resolution.as_nanos() as u64),
None,
None,
)
.unwrap()
})
}
}
impl Metric for Heatmap {
fn as_any(&self) -> Option<&dyn std::any::Any> {
Some(self)
}
fn value(&self) -> Option<Value> {
Some(Value::Heatmap(self))
}
}