use std::sync::atomic::{AtomicU64, Ordering};
pub trait Metric {
fn add(&self, value: u64);
fn inc(&self) {
self.add(1);
}
fn count(&self) -> u64;
fn reset(&self);
fn set(&self, value: u64);
}
impl Metric for AtomicU64 {
fn add(&self, value: u64) {
self.fetch_add(value, Ordering::Relaxed);
}
fn count(&self) -> u64 {
self.load(Ordering::Relaxed)
}
fn reset(&self) {
self.store(0, Ordering::Relaxed)
}
fn set(&self, value: u64) {
self.store(value, Ordering::Relaxed);
}
}
#[cfg(test)]
mod tests {
use crate::metric::Metric;
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
struct Dog<T: DogEvents> {
metrics: T,
}
trait DogEvents {
fn inc_bark(&self);
fn inc_eat(&self);
fn set_eat(&self, no_times: u64);
}
impl<T: DogEvents> Dog<T> {
fn bark(&self) {
println!("bark! bark!");
self.metrics.inc_bark();
}
fn eat(&self) {
println!("nom! nom!");
self.metrics.inc_eat();
}
fn eat_more_times(&self, no_times: u64) {
self.metrics.set_eat(no_times);
}
}
impl<T: DogEvents> Dog<T> {
fn new_with_metrics(metrics: T) -> Self {
Self { metrics }
}
}
#[test]
fn test_main() {
#[derive(Default, Debug)]
struct DogEventMetrics {
bark: AtomicU64,
eat: AtomicU64,
}
impl DogEvents for Arc<DogEventMetrics> {
fn inc_bark(&self) {
self.bark.inc();
}
fn inc_eat(&self) {
self.eat.inc();
}
fn set_eat(&self, no_times: u64) {
self.eat.set(no_times);
}
}
impl DogEventMetrics {
fn reset(&self) {
self.bark.reset();
self.eat.reset();
}
}
#[derive(Default)]
struct SystemMetrics {
pub(crate) dog_metrics: Arc<DogEventMetrics>,
}
impl SystemMetrics {
fn serialize(&self) -> String {
let mut serialized_metrics = format!("{:#?}", &self.dog_metrics);
self.dog_metrics.reset();
serialized_metrics.retain(|c| !c.is_whitespace());
serialized_metrics
}
}
let system_metrics = SystemMetrics::default();
let dog = Dog::new_with_metrics(system_metrics.dog_metrics.clone());
dog.bark();
dog.bark();
dog.eat();
let expected_metrics = String::from("DogEventMetrics{bark:2,eat:1,}");
let actual_metrics = system_metrics.serialize();
assert_eq!(expected_metrics, actual_metrics);
assert_eq!(system_metrics.dog_metrics.eat.count(), 0);
assert_eq!(system_metrics.dog_metrics.bark.count(), 0);
dog.eat_more_times(u64::MAX);
assert_eq!(system_metrics.dog_metrics.eat.count(), u64::MAX);
dog.eat();
dog.eat();
assert_eq!(system_metrics.dog_metrics.eat.count(), 1);
}
}