use std::{marker::PhantomData, sync::Arc, time::Duration};
use super::scrape_ctx;
use crate::{
encoder::{EncodeCounterValue, EncodeGaugeValue},
metrics::{
counter::{CounterValue, LazyCounter},
gauge::{GaugeValue, LazyGauge},
internal::lazy::LazySource,
lazy_group::LazyGroup,
},
};
pub(crate) fn counter_from_group<S, N, M>(
group: LazyGroup<S>,
map: M,
created: Option<Duration>,
) -> LazyCounter<N>
where
S: Send + Sync + 'static,
M: Fn(&S) -> N + Send + Sync + 'static,
N: EncodeCounterValue + CounterValue + 'static,
{
LazyCounter::from_source(
Arc::new(GroupedLazySource::<S, N, _>::new(group, Arc::new(map))),
created,
)
}
pub(crate) fn gauge_from_group<S, N, M>(group: LazyGroup<S>, map: M) -> LazyGauge<N>
where
S: Send + Sync + 'static,
M: Fn(&S) -> N + Send + Sync + 'static,
N: EncodeGaugeValue + GaugeValue + 'static,
{
LazyGauge::from_source(Arc::new(GroupedLazySource::<S, N, _>::new(group, Arc::new(map))))
}
pub(crate) struct GroupedLazySource<S, N, M> {
pub(crate) group: LazyGroup<S>,
pub(crate) map: Arc<M>,
pub(crate) _marker: PhantomData<N>,
}
impl<S, N, M> GroupedLazySource<S, N, M> {
#[inline]
pub(crate) fn new(group: LazyGroup<S>, map: Arc<M>) -> Self {
Self { group, map, _marker: PhantomData }
}
}
impl<S, N, M> LazySource<N> for GroupedLazySource<S, N, M>
where
S: Send + Sync + 'static,
M: Fn(&S) -> N + Send + Sync + 'static,
N: Send + Sync + 'static,
{
#[inline]
fn load(&self) -> N {
let map = self.map.as_ref();
if let Some(r) = scrape_ctx::with_current(|ctx| {
let sample = ctx.get_or_init::<S>(self.group.id, || (self.group.sample.as_ref())());
map(sample)
}) {
r
} else {
let sample = (self.group.sample.as_ref())();
map(&sample)
}
}
}