naga/arena/
handle.rs

1//! Well-typed indices into [`Arena`]s and [`UniqueArena`]s.
2//!
3//! This module defines [`Handle`] and related types.
4//!
5//! [`Arena`]: super::Arena
6//! [`UniqueArena`]: super::UniqueArena
7
8use std::{cmp::Ordering, fmt, hash, marker::PhantomData};
9
10/// An unique index in the arena array that a handle points to.
11/// The "non-max" part ensures that an `Option<Handle<T>>` has
12/// the same size and representation as `Handle<T>`.
13pub type Index = crate::non_max_u32::NonMaxU32;
14
15#[derive(Clone, Copy, Debug, thiserror::Error, PartialEq)]
16#[error("Handle {index} of {kind} is either not present, or inaccessible yet")]
17pub struct BadHandle {
18    pub kind: &'static str,
19    pub index: usize,
20}
21
22impl BadHandle {
23    pub fn new<T>(handle: Handle<T>) -> Self {
24        Self {
25            kind: std::any::type_name::<T>(),
26            index: handle.index(),
27        }
28    }
29}
30
31/// A strongly typed reference to an arena item.
32///
33/// A `Handle` value can be used as an index into an [`Arena`] or [`UniqueArena`].
34///
35/// [`Arena`]: super::Arena
36/// [`UniqueArena`]: super::UniqueArena
37#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
38#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
39#[cfg_attr(
40    any(feature = "serialize", feature = "deserialize"),
41    serde(transparent)
42)]
43#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
44pub struct Handle<T> {
45    index: Index,
46    #[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(skip))]
47    marker: PhantomData<T>,
48}
49
50impl<T> Clone for Handle<T> {
51    fn clone(&self) -> Self {
52        *self
53    }
54}
55
56impl<T> Copy for Handle<T> {}
57
58impl<T> PartialEq for Handle<T> {
59    fn eq(&self, other: &Self) -> bool {
60        self.index == other.index
61    }
62}
63
64impl<T> Eq for Handle<T> {}
65
66impl<T> PartialOrd for Handle<T> {
67    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
68        Some(self.cmp(other))
69    }
70}
71
72impl<T> Ord for Handle<T> {
73    fn cmp(&self, other: &Self) -> Ordering {
74        self.index.cmp(&other.index)
75    }
76}
77
78impl<T> fmt::Debug for Handle<T> {
79    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
80        write!(formatter, "[{}]", self.index)
81    }
82}
83
84impl<T> hash::Hash for Handle<T> {
85    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
86        self.index.hash(hasher)
87    }
88}
89
90impl<T> Handle<T> {
91    pub(crate) const fn new(index: Index) -> Self {
92        Handle {
93            index,
94            marker: PhantomData,
95        }
96    }
97
98    /// Returns the index of this handle.
99    pub const fn index(self) -> usize {
100        self.index.get() as usize
101    }
102
103    /// Convert a `usize` index into a `Handle<T>`.
104    pub(super) fn from_usize(index: usize) -> Self {
105        let handle_index = u32::try_from(index)
106            .ok()
107            .and_then(Index::new)
108            .expect("Failed to insert into arena. Handle overflows");
109        Handle::new(handle_index)
110    }
111
112    /// Convert a `usize` index into a `Handle<T>`, without range checks.
113    pub(super) const unsafe fn from_usize_unchecked(index: usize) -> Self {
114        Handle::new(Index::new_unchecked(index as u32))
115    }
116
117    /// Write this handle's index to `formatter`, preceded by `prefix`.
118    pub fn write_prefixed(
119        &self,
120        formatter: &mut fmt::Formatter,
121        prefix: &'static str,
122    ) -> fmt::Result {
123        formatter.write_str(prefix)?;
124        <usize as fmt::Display>::fmt(&self.index(), formatter)
125    }
126}