use std::iter;
pub const BUCKET_LABEL: &str = "le";
pub const DEFAULT_BUCKETS: [f64; 11] =
[0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0];
#[derive(Copy, Clone, Debug)]
pub struct Bucket {
upper_bound: f64,
count: u64,
}
impl Bucket {
pub const fn new(upper_bound: f64, count: u64) -> Self {
Self { upper_bound, count }
}
pub fn inc(&mut self) {
self.count += 1;
}
pub const fn upper_bound(&self) -> f64 {
self.upper_bound
}
pub const fn count(&self) -> u64 {
self.count
}
}
pub fn linear_buckets(start: f64, width: f64, count: usize) -> impl Iterator<Item = f64> {
assert!(width > 0.0, "linear buckets must have a width greater than 0");
assert!(count >= 1, "linear buckets must have at least 1 bucket");
iter::repeat(())
.enumerate()
.map(move |(step, _)| start + (width * (step as f64)))
.take(count)
}
pub fn exponential_buckets(start: f64, factor: f64, count: usize) -> impl Iterator<Item = f64> {
assert!(start > 0.0, "exponential buckets must have a positive start value");
assert!(factor > 1.0, "exponential buckets must have a factor greater than 1");
assert!(count >= 1, "exponential buckets must have at least 1 bucket");
iter::repeat(())
.enumerate()
.map(move |(next, _)| start * factor.powi(next as i32))
.take(count)
}
pub fn exponential_buckets_range(min: f64, max: f64, count: usize) -> impl Iterator<Item = f64> {
assert!(min > 0.0, "exponential buckets must have a positive min value");
assert!(count >= 1, "exponential buckets must have at least 1 bucket");
let factor = (max / min).powf(1.0 / (count - 1) as f64);
iter::repeat(())
.enumerate()
.map(move |(next, _)| min * factor.powi(next as i32))
.take(count)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn gen_linear_buckets() {
let cases = [(
(0.0, 1.0, 10),
vec![0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0],
)];
for ((start, width, count), expected) in cases {
let got = linear_buckets(start, width, count).collect::<Vec<_>>();
assert_eq!(got, expected);
}
}
#[test]
fn gen_exponential_buckets() {
let cases = [
(
(1.0, 2.0, 10),
vec![1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0],
),
(
(1.0, 3.0, 10),
vec![1.0, 3.0, 9.0, 27.0, 81.0, 243.0, 729.0, 2187.0, 6561.0, 19683.0],
),
((1.0, 2.0, 1), vec![1.0]),
];
for ((start, factor, count), expected) in cases {
let got = exponential_buckets(start, factor, count).collect::<Vec<_>>();
assert_eq!(got, expected);
}
}
#[test]
fn gen_exponential_buckets_range() {
let cases = [
(
(1.0, 512.0, 10),
vec![1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0],
),
(
(1.0, 19683.0, 10),
vec![1.0, 3.0, 9.0, 27.0, 81.0, 243.0, 729.0, 2187.0, 6561.0, 19683.0],
),
((1.0, 4.0, 1), vec![1.0]),
];
for ((start, factor, count), expected) in cases {
let got = exponential_buckets_range(start, factor, count).collect::<Vec<_>>();
assert_eq!(got, expected);
}
}
}