use crate::util::ConstFnBounds;
use core::fmt::Debug;
pub unsafe trait Id: Sized + Copy + PartialEq + Eq + Debug {}
#[derive(Debug, PartialEq, Eq)]
pub struct Unique<I: Id> {
id: I,
}
impl<I> Unique<I>
where
<I as ConstFnBounds>::Type: Id,
{
pub const unsafe fn new(id: I) -> Self {
Self { id }
}
#[must_use]
pub const fn into_inner(self) -> I {
self.id
}
}
unsafe impl<I: Id> Sync for Unique<I> {}
#[cfg(target_has_atomic = "64")]
mod checked {
use super::Id;
use super::Unique;
use core::num::NonZeroU64;
use core::sync::atomic;
use core::sync::atomic::AtomicU64;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Checked(NonZeroU64);
impl Checked {
#[must_use]
pub fn new() -> Unique<Self> {
static COUNTER: AtomicU64 = AtomicU64::new(1);
const MAX_ID: u64 = u64::MAX >> 1;
let id = COUNTER.fetch_add(1, atomic::Ordering::Relaxed);
if id >= MAX_ID {
crate::util::abort();
}
let id = Self(unsafe { NonZeroU64::new_unchecked(id) });
unsafe { Unique::new(id) }
}
}
unsafe impl Id for Checked {}
}
#[cfg(target_has_atomic = "64")]
pub use checked::Checked;
mod unchecked {
use super::Id;
use super::Unique;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct Unchecked;
impl Unchecked {
#[must_use]
pub const unsafe fn new() -> Unique<Self> {
unsafe { Unique::new(Self) }
}
}
unsafe impl Id for Unchecked {}
}
pub use unchecked::Unchecked;
#[cfg(target_has_atomic = "64")]
mod debug_checked {
use super::Id;
use super::Unique;
use crate::id;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DebugChecked {
#[cfg(debug_assertions)]
checked: id::Checked,
}
impl DebugChecked {
#[must_use]
pub unsafe fn new() -> Unique<Self> {
let this = Self {
#[cfg(debug_assertions)]
checked: id::Checked::new().into_inner(),
};
unsafe { Unique::new(this) }
}
}
unsafe impl Id for DebugChecked {}
}
#[cfg(target_has_atomic = "64")]
pub use debug_checked::DebugChecked;
mod lifetime {
use super::Id;
use super::Unique;
use core::marker::PhantomData;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Lifetime<'id> {
invariant: PhantomData<fn(&'id ()) -> &'id ()>,
}
impl Lifetime<'_> {
pub fn scope<O, F>(f: F) -> O
where
F: for<'id> FnOnce(Unique<Lifetime<'id>>) -> O,
{
f(unsafe {
Unique::new(Lifetime {
invariant: PhantomData,
})
})
}
}
unsafe impl Id for Lifetime<'_> {}
}
pub use lifetime::Lifetime;