dambi 0.1.1

Single-threaded (!Send + !Sync) primitives
Documentation
use std::num::NonZeroU32;
use std::num::NonZeroU64;

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(C)]
pub struct SlotId {
    id_raw: NonZeroU64,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct SlotGen(NonZeroU32);

impl SlotGen {
    pub const MIN: Self = Self(NonZeroU32::MIN);

    #[must_use]
    pub const fn new(raw: u32) -> Option<Self> {
        match NonZeroU32::new(raw) {
            Some(raw) => Some(Self(raw)),
            None => None,
        }
    }

    pub const fn get(self) -> u32 {
        self.0.get()
    }

    #[must_use]
    pub const fn checked_add(self, other: u32) -> Option<Self> {
        match self.0.checked_add(other) {
            Some(raw) => Some(Self(raw)),
            None => None,
        }
    }
}

impl SlotId {
    #[must_use]
    pub const fn from_parts(slot: u32, generation: SlotGen) -> Self {
        let raw = ((generation.get() as u64) << 32) | (slot as u64);
        // SAFETY: `generation` is `NonZeroU32`, so the high 32 bits of `raw`
        // are non-zero, hence `raw != 0`.
        Self {
            id_raw: unsafe { NonZeroU64::new_unchecked(raw) },
        }
    }

    pub const fn slot(self) -> u32 {
        self.id_raw.get() as u32
    }

    pub const fn generation(self) -> SlotGen {
        // SAFETY: `from_parts` placed a non-zero `SlotGen` in the high 32 bits.
        SlotGen(unsafe { NonZeroU32::new_unchecked((self.id_raw.get() >> 32) as u32) })
    }
}