use std::num::NonZeroU32;
#[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub struct NodeId {
index: u32,
generation: NonZeroU32,
}
impl NodeId {
#[inline]
pub(crate) fn index(self) -> usize {
self.index as usize
}
#[inline]
pub(crate) fn from_parts(index: usize, generation: NonZeroU32) -> Self {
let index = u32::try_from(index).expect("arena overflow: more than u32::MAX nodes");
NodeId { index, generation }
}
#[inline]
pub(crate) fn generation_raw(self) -> NonZeroU32 {
self.generation
}
#[inline]
pub fn generation(self) -> u32 {
self.generation.get()
}
pub fn as_u32(self) -> u32 {
self.index + 1
}
}
impl std::fmt::Debug for NodeId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "NodeId({}", self.index + 1)?;
if self.generation.get() > 1 {
write!(f, "@{}", self.generation.get())?;
}
write!(f, ")")
}
}
impl std::fmt::Display for NodeId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "#{}", self.index + 1)?;
if self.generation.get() > 1 {
write!(f, "@{}", self.generation.get())?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
const G1: NonZeroU32 = NonZeroU32::MIN;
#[test]
fn index_round_trip() {
for i in [0, 1, 2, 7, 99, 1000, 1_000_000] {
let id = NodeId::from_parts(i, G1);
assert_eq!(id.index(), i);
assert_eq!(id.generation(), 1);
}
}
#[test]
fn option_node_id_is_eight_bytes() {
assert_eq!(std::mem::size_of::<NodeId>(), 8);
assert_eq!(std::mem::size_of::<Option<NodeId>>(), 8);
}
#[test]
fn same_slot_different_generation_is_a_different_id() {
let a = NodeId::from_parts(5, G1);
let b = NodeId::from_parts(5, NonZeroU32::new(2).unwrap());
assert_ne!(a, b);
assert_eq!(a.index(), b.index());
}
#[test]
fn debug_is_compact() {
assert_eq!(format!("{:?}", NodeId::from_parts(8, G1)), "NodeId(9)");
assert_eq!(
format!("{:?}", NodeId::from_parts(8, NonZeroU32::new(2).unwrap())),
"NodeId(9@2)"
);
}
#[test]
fn display_shows_slot_and_generation_after_reuse() {
assert_eq!(format!("{}", NodeId::from_parts(41, G1)), "#42");
assert_eq!(
format!("{}", NodeId::from_parts(41, NonZeroU32::new(3).unwrap())),
"#42@3"
);
}
}