use std::sync::{Arc, LazyLock, Mutex};
use arc_swap::ArcSwap;
use crate::instrumentation::{MAX_INSTRUMENTATIONS, tracer::DynTracer};
#[derive(Clone)]
pub struct Slots {
pub tracers: [Option<Arc<dyn DynTracer>>; MAX_INSTRUMENTATIONS as usize],
pub distributed: Option<u8>,
pub next: u8,
pub freed: Vec<u8>,
}
impl Default for Slots {
fn default() -> Self {
Self {
tracers: std::array::from_fn(|_| None),
distributed: None,
next: 0,
freed: Vec::new(),
}
}
}
impl Slots {
pub fn alloc(&mut self) -> Option<u8> {
if let Some(slot) = self.freed.pop() {
return Some(slot);
}
if u32::from(self.next) < MAX_INSTRUMENTATIONS {
let slot = self.next;
self.next += 1;
return Some(slot);
}
None
}
}
pub static SLOTS: LazyLock<ArcSwap<Slots>> =
LazyLock::new(|| ArcSwap::from_pointee(Slots::default()));
static SLOTS_WRITE: Mutex<()> = Mutex::new(());
pub fn update_slots<T, E>(f: impl FnOnce(&mut Slots) -> Result<T, E>) -> Result<T, E> {
let _guard = SLOTS_WRITE.lock().unwrap_or_else(|e| e.into_inner());
let mut next = (**SLOTS.load()).clone();
let out = f(&mut next)?;
SLOTS.store(Arc::new(next));
Ok(out)
}