use std::collections::HashMap;
use crate::Window;
pub trait HistogramMetric: Send + Sync + 'static {
fn config(&self) -> histogram::Config;
fn load(&self) -> Option<histogram::Histogram>;
}
pub trait CounterGroupMetric: Send + Sync + 'static {
fn entries(&self) -> usize;
fn counter_value(&self, idx: usize) -> Option<u64>;
fn load_counters(&self) -> Option<Vec<u64>>;
fn load_metadata(&self, idx: usize) -> Option<HashMap<String, String>>;
fn metadata_snapshot(&self) -> Vec<(usize, HashMap<String, String>)>;
#[allow(clippy::type_complexity)]
fn with_metadata(&self, idx: usize, f: &mut dyn FnMut(Option<&HashMap<String, String>>)) {
f(self.load_metadata(idx).as_ref());
}
fn for_each_metadata(&self, f: &mut dyn FnMut(usize, &HashMap<String, String>)) {
for (idx, map) in self.metadata_snapshot() {
f(idx, &map);
}
}
fn load_window(&self, _idx: usize) -> Option<Window> {
None
}
fn window_snapshot(&self) -> Vec<(usize, Window)> {
Vec::new()
}
fn load_with_window(&self, idx: usize) -> (Option<u64>, Option<Window>) {
(self.counter_value(idx), self.load_window(idx))
}
}
pub trait GaugeGroupMetric: Send + Sync + 'static {
fn entries(&self) -> usize;
fn gauge_value(&self, idx: usize) -> Option<i64>;
fn load_gauges(&self) -> Option<Vec<i64>>;
fn load_metadata(&self, idx: usize) -> Option<HashMap<String, String>>;
fn metadata_snapshot(&self) -> Vec<(usize, HashMap<String, String>)>;
#[allow(clippy::type_complexity)]
fn with_metadata(&self, idx: usize, f: &mut dyn FnMut(Option<&HashMap<String, String>>)) {
f(self.load_metadata(idx).as_ref());
}
fn for_each_metadata(&self, f: &mut dyn FnMut(usize, &HashMap<String, String>)) {
for (idx, map) in self.metadata_snapshot() {
f(idx, &map);
}
}
fn load_window(&self, _idx: usize) -> Option<Window> {
None
}
fn window_snapshot(&self) -> Vec<(usize, Window)> {
Vec::new()
}
fn load_with_window(&self, idx: usize) -> (Option<i64>, Option<Window>) {
(self.gauge_value(idx), self.load_window(idx))
}
}
pub trait HistogramGroupMetric: Send + Sync + 'static {
fn entries(&self) -> usize;
fn config(&self) -> histogram::Config;
fn load_histogram(&self, idx: usize) -> Option<histogram::Histogram>;
fn load_all_histograms(&self) -> Option<Vec<histogram::Histogram>>;
fn load_metadata(&self, idx: usize) -> Option<HashMap<String, String>>;
fn metadata_snapshot(&self) -> Vec<(usize, HashMap<String, String>)>;
#[allow(clippy::type_complexity)]
fn with_metadata(&self, idx: usize, f: &mut dyn FnMut(Option<&HashMap<String, String>>)) {
f(self.load_metadata(idx).as_ref());
}
fn for_each_metadata(&self, f: &mut dyn FnMut(usize, &HashMap<String, String>)) {
for (idx, map) in self.metadata_snapshot() {
f(idx, &map);
}
}
fn load_window(&self, _idx: usize) -> Option<Window> {
None
}
fn window_snapshot(&self) -> Vec<(usize, Window)> {
Vec::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
struct DefaultOnlyCounterGroup {
metadata: HashMap<usize, HashMap<String, String>>,
}
impl CounterGroupMetric for DefaultOnlyCounterGroup {
fn entries(&self) -> usize {
2
}
fn counter_value(&self, _idx: usize) -> Option<u64> {
None
}
fn load_counters(&self) -> Option<Vec<u64>> {
None
}
fn load_metadata(&self, idx: usize) -> Option<HashMap<String, String>> {
self.metadata.get(&idx).cloned()
}
fn metadata_snapshot(&self) -> Vec<(usize, HashMap<String, String>)> {
self.metadata.iter().map(|(k, v)| (*k, v.clone())).collect()
}
}
struct DefaultOnlyGaugeGroup {
metadata: HashMap<usize, HashMap<String, String>>,
}
impl GaugeGroupMetric for DefaultOnlyGaugeGroup {
fn entries(&self) -> usize {
2
}
fn gauge_value(&self, _idx: usize) -> Option<i64> {
None
}
fn load_gauges(&self) -> Option<Vec<i64>> {
None
}
fn load_metadata(&self, idx: usize) -> Option<HashMap<String, String>> {
self.metadata.get(&idx).cloned()
}
fn metadata_snapshot(&self) -> Vec<(usize, HashMap<String, String>)> {
self.metadata.iter().map(|(k, v)| (*k, v.clone())).collect()
}
}
struct DefaultOnlyHistogramGroup {
metadata: HashMap<usize, HashMap<String, String>>,
}
impl HistogramGroupMetric for DefaultOnlyHistogramGroup {
fn entries(&self) -> usize {
2
}
fn config(&self) -> histogram::Config {
histogram::Config::new(7, 64).unwrap()
}
fn load_histogram(&self, _idx: usize) -> Option<histogram::Histogram> {
None
}
fn load_all_histograms(&self) -> Option<Vec<histogram::Histogram>> {
None
}
fn load_metadata(&self, idx: usize) -> Option<HashMap<String, String>> {
self.metadata.get(&idx).cloned()
}
fn metadata_snapshot(&self) -> Vec<(usize, HashMap<String, String>)> {
self.metadata.iter().map(|(k, v)| (*k, v.clone())).collect()
}
}
fn sample_metadata() -> HashMap<usize, HashMap<String, String>> {
let mut m = HashMap::new();
m.insert(0, [("cpu".to_string(), "0".to_string())].into());
m.insert(1, [("cpu".to_string(), "1".to_string())].into());
m
}
fn sorted(
mut v: Vec<(usize, HashMap<String, String>)>,
) -> Vec<(usize, HashMap<String, String>)> {
v.sort_by_key(|(idx, _)| *idx);
v
}
macro_rules! default_impl_tests {
($mod_name:ident, $group_ty:ident, $trait_ty:ident) => {
mod $mod_name {
use super::*;
#[test]
fn default_with_metadata_matches_load_metadata() {
let group = $group_ty {
metadata: sample_metadata(),
};
let dyn_group: &dyn $trait_ty = &group;
let expected = dyn_group.load_metadata(0);
let mut seen: Option<HashMap<String, String>> = None;
dyn_group.with_metadata(0, &mut |m| seen = m.cloned());
assert_eq!(seen, expected);
let mut seen_absent: Option<HashMap<String, String>> = None;
let mut called = false;
dyn_group.with_metadata(5, &mut |m| {
called = true;
seen_absent = m.cloned();
});
assert!(called, "the callback must still run with None");
assert!(seen_absent.is_none());
}
#[test]
fn default_for_each_metadata_matches_metadata_snapshot() {
let group = $group_ty {
metadata: sample_metadata(),
};
let dyn_group: &dyn $trait_ty = &group;
let mut seen: Vec<(usize, HashMap<String, String>)> = Vec::new();
dyn_group.for_each_metadata(&mut |idx, m| seen.push((idx, m.clone())));
let expected = dyn_group.metadata_snapshot();
assert_eq!(sorted(seen.clone()), sorted(expected.clone()));
assert_eq!(seen.len(), expected.len());
}
}
};
}
default_impl_tests!(
counter_defaults,
DefaultOnlyCounterGroup,
CounterGroupMetric
);
default_impl_tests!(gauge_defaults, DefaultOnlyGaugeGroup, GaugeGroupMetric);
default_impl_tests!(
histogram_defaults,
DefaultOnlyHistogramGroup,
HistogramGroupMetric
);
}