use std::sync::atomic::Ordering;
use metered::atomic::AtomicInt;
use metered::clear::Clear;
use metered::Enter;
use metered::metric::{Advice, Counter, Metric, OnResult};
use metered::time_source::{Instant, StdInstant};
use serde::{Serialize, Serializer};
pub trait CounterIncrementer: Default + Clear + Serialize {
fn increment_by(&self, number: u64);
}
impl CounterIncrementer for AtomicInt<u64> {
fn increment_by(&self, number: u64) {
self.inner.fetch_add(number, Ordering::Relaxed);
}
}
#[derive(Clone, Debug)]
pub struct TotalTimeElapsed<A: CounterIncrementer = AtomicInt<u64>, C: Instant = StdInstant>(pub A, pub std::marker::PhantomData<C>);
impl<A: CounterIncrementer, C: Instant, R> Metric<R> for TotalTimeElapsed<A, C> {}
impl<A: CounterIncrementer, C: Instant> Enter for TotalTimeElapsed<A, C> {
type E = C;
fn enter(&self) -> Self::E {
C::now()
}
}
impl<A: CounterIncrementer, C: Instant> Default for TotalTimeElapsed<A, C> {
fn default() -> Self {
TotalTimeElapsed(A::default(), std::marker::PhantomData)
}
}
impl<A: CounterIncrementer, C: Instant, R> OnResult<R> for TotalTimeElapsed<A, C> {
fn on_result(&self, enter: C, _: &R) -> Advice {
let elapsed = enter.elapsed_time();
self.0.increment_by(elapsed);
Advice::Return
}
}
impl<A: CounterIncrementer, C: Instant> Clear for TotalTimeElapsed<A, C> {
fn clear(&self) {
self.0.clear()
}
}
impl<A: CounterIncrementer, C: Instant> Serialize for TotalTimeElapsed<A, C> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
Serialize::serialize(&self.0, serializer)
}
}
#[derive(Clone, Default, Debug, Serialize)]
pub struct ErrorCounter<C: Counter = AtomicInt<u64>>(pub C);
impl<C: Counter> Enter for ErrorCounter<C> {
type E = ();
fn enter(&self) {}
}
impl CounterIncrementer for ErrorCounter {
fn increment_by(&self, number: u64) {
self.0.inner.fetch_add(number, Ordering::Relaxed);
}
}
impl<C: Counter, T, E> Metric<Result<T, E>> for ErrorCounter<C> {}
impl<C: Counter, T, E> OnResult<Result<T, E>> for ErrorCounter<C> {
fn on_result(&self, _: (), r: &Result<T, E>) -> Advice {
if r.is_err() {
self.0.incr();
};
Advice::Return
}
}
impl<C: Counter> Clear for ErrorCounter<C> {
fn clear(&self) {
self.0.clear()
}
}