genarena 0.1.2

A slot-reservable arena with generational keys
Documentation
use std::marker::PhantomData;
use std::mem;
use std::num::NonZeroUsize;

/// A reservation for a slot in the arena.
///
/// The key that will be used for that slot after claiming the reservation can
/// be obtained using [`Reservation::key`].
pub struct Reservation<K> {
    pub(crate) key: Key,
    _marker: PhantomData<K>,
}

impl<K> Reservation<K> {
    pub(crate) fn new(key: Key) -> Self {
        Self { key, _marker: PhantomData }
    }
}

impl<K> Reservation<K>
where
    K: From<Key>,
{
    /// The key for the slot that this reservation reserves.
    pub fn key(&self) -> K {
        K::from(self.key)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct Generation(NonZeroUsize);

impl Generation {
    pub(crate) const FIRST: Self = Self(NonZeroUsize::MIN);

    pub(crate) fn next(&self) -> Option<Self> {
        let n = self.0.get().checked_add(1)?;
        Some(Self(NonZeroUsize::new(n).unwrap()))
    }
}

/// A generational key.
///
/// The key type maintains the same size even when inside an [`Option`]:
///
/// ```
/// # use std::mem::size_of;
/// # use genarena::key::Key;
/// #
/// assert_eq!(size_of::<Key>(), size_of::<Option<Key>>());
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Key {
    pub(crate) index: usize,
    pub(crate) generation: Generation,
}

const _NON_ZERO_OPTION_SIZE_OPTIMIZATION: () = {
    assert!(mem::size_of::<Key>() == mem::size_of::<Option<Key>>());
};

/// Makes a newtype usable as an [`Arena`] key.
///
/// Generates `From` implementations to convert between the newtype and [`Key`].
///
/// # Examples
///
/// ```
/// # use genarena::{Arena, key::Key, key_newtype_impls};
/// #
/// pub struct CustomKey(Key);
/// key_newtype_impls!(CustomKey);
///
/// let arena: Arena<CustomKey, i32> = Arena::new();
/// ```
///
/// [`Arena`]: crate::Arena
#[macro_export]
macro_rules! key_newtype_impls {
    ($name:ident) => {
        impl From<$crate::key::Key> for $name {
            fn from(key: $crate::key::Key) -> $name {
                $name(key)
            }
        }

        impl From<$name> for $crate::key::Key {
            fn from(val: $name) -> $crate::key::Key {
                val.0
            }
        }
    };
}