#![doc = include_str!("../README.md")]
#![no_std]
use core::any::TypeId;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering;
pub use typeslot_macros::TypeSlot;
#[doc(hidden)]
pub use inventory;
pub struct AtomicSlot(AtomicUsize);
impl AtomicSlot {
pub const fn new() -> Self {
Self(AtomicUsize::new(usize::MAX))
}
pub fn get(&self) -> Option<usize> {
let val = self.0.load(Ordering::Acquire);
(val != usize::MAX).then_some(val)
}
pub fn set(&self, index: usize) {
self.0
.compare_exchange(
usize::MAX,
index,
Ordering::Release,
Ordering::Relaxed,
)
.expect("`AtomicSlot::set` called twice");
}
}
impl Default for AtomicSlot {
fn default() -> Self {
Self::new()
}
}
pub struct TypeSlotEntry {
pub type_id: TypeId,
pub group_id: TypeId,
pub slot: &'static AtomicSlot,
}
inventory::collect!(TypeSlotEntry);
pub trait TypeSlot<G: 'static>: 'static {
fn slot() -> Option<usize>;
}
pub fn init<G: 'static>() -> usize {
let group_id = TypeId::of::<G>();
let mut index = 0usize;
for entry in inventory::iter::<TypeSlotEntry>() {
if entry.group_id == group_id {
entry.slot.set(index);
index += 1;
}
}
index
}