use core::fmt;
use core::num::NonZeroU32;
pub use crate::pass::preserved::AnalysisId;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NodeId(NonZeroU32);
const _: () = assert!(size_of::<NodeId>() == 4);
const _: () = assert!(size_of::<Option<NodeId>>() == 4);
impl NodeId {
pub const FIRST: NodeId = NodeId(NonZeroU32::MIN);
#[inline]
#[must_use]
pub const fn from_index(index: u32) -> Option<NodeId> {
match NonZeroU32::new(index.wrapping_add(1)) {
Some(raw) => Some(NodeId(raw)),
None => None,
}
}
#[inline]
#[must_use]
pub const fn index(self) -> u32 {
self.0.get() - 1
}
#[inline]
#[must_use]
pub const fn index_usize(self) -> usize {
self.index() as usize
}
#[inline]
#[must_use]
pub const fn to_raw(self) -> NonZeroU32 {
self.0
}
#[inline]
#[must_use]
pub const fn from_raw(raw: NonZeroU32) -> NodeId {
NodeId(raw)
}
#[inline]
#[must_use]
pub const fn next(self) -> Option<NodeId> {
match self.0.checked_add(1) {
Some(raw) => Some(NodeId(raw)),
None => None,
}
}
}
impl fmt::Debug for NodeId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "NodeId({})", self.index())
}
}
impl fmt::Display for NodeId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "%{}", self.index())
}
}
#[cfg(test)]
mod tests {
use super::NodeId;
use vize_l0::cstr;
#[test]
fn index_round_trips_through_the_niche() {
for index in [0u32, 1, 2, 41, u32::MAX - 1] {
let id = NodeId::from_index(index).expect("index below u32::MAX has an id");
assert_eq!(id.index(), index);
assert_eq!(id.index_usize(), index as usize);
assert_eq!(NodeId::from_raw(id.to_raw()), id);
}
}
#[test]
fn the_first_id_is_index_zero() {
assert_eq!(
NodeId::FIRST,
NodeId::from_index(0).expect("index 0 has an id")
);
assert_eq!(NodeId::FIRST.index(), 0);
}
#[test]
fn exhaustion_yields_none_rather_than_wrapping() {
assert_eq!(NodeId::from_index(u32::MAX), None);
let last = NodeId::from_raw(core::num::NonZeroU32::MAX);
assert_eq!(last.next(), None);
}
#[test]
fn next_walks_the_index_sequence() {
let first = NodeId::FIRST;
let second = first.next().expect("the second id exists");
assert_eq!(second.index(), 1);
assert_eq!(second, NodeId::from_index(1).expect("index 1 has an id"));
}
#[test]
fn debug_and_display_show_the_index() {
let id = NodeId::from_index(7).expect("index 7 has an id");
assert_eq!(cstr!("{id:?}").as_str(), "NodeId(7)");
assert_eq!(cstr!("{id}").as_str(), "%7");
}
#[test]
fn ids_order_by_index() {
let a = NodeId::from_index(1).expect("index 1 has an id");
let b = NodeId::from_index(2).expect("index 2 has an id");
assert!(a < b);
}
}