use std::{any::Any, cell::RefCell, collections::HashMap};
use super::LazyGroupId;
thread_local! {
static STACK: RefCell<Vec<ScrapeContext>> = const { RefCell::new(Vec::new()) };
}
#[inline]
pub(crate) fn enter() -> ScrapeGuard {
STACK.with(|stack| stack.borrow_mut().push(ScrapeContext::default()));
ScrapeGuard { _private: () }
}
#[inline]
pub(crate) fn with_current<R>(f: impl FnOnce(&mut ScrapeContext) -> R) -> Option<R> {
STACK.with(|stack| {
let mut stack = stack.borrow_mut();
let ctx = stack.last_mut()?;
Some(f(ctx))
})
}
pub(crate) struct ScrapeGuard {
_private: (),
}
impl Drop for ScrapeGuard {
fn drop(&mut self) {
STACK.with(|stack| {
let mut stack = stack.borrow_mut();
let _ = stack.pop();
});
}
}
#[derive(Default)]
pub(crate) struct ScrapeContext {
samples: HashMap<LazyGroupId, Box<dyn Any + Send + Sync>>,
}
impl ScrapeContext {
#[inline]
pub(crate) fn get_or_init<T>(&mut self, key: LazyGroupId, init: impl FnOnce() -> T) -> &T
where
T: Any + Send + Sync,
{
self.samples.entry(key).or_insert_with(|| Box::new(init()));
self.samples
.get(&key)
.and_then(|v| v.downcast_ref::<T>())
.expect("lazy_group::scrape_ctx: cached sample type mismatch")
}
}