Skip to main content

radix_wasmi_arena/
lib.rs

1//! Fast arena allocators for different usage purposes.
2//!
3//! They cannot deallocate single allocated entities for extra efficiency.
4//! These allocators mainly serve as the backbone for an efficient Wasm store
5//! implementation.
6
7#![cfg_attr(not(feature = "std"), no_std)]
8#![warn(
9    clippy::cast_lossless,
10    clippy::missing_errors_doc,
11    clippy::used_underscore_binding,
12    clippy::redundant_closure_for_method_calls,
13    clippy::type_repetition_in_bounds,
14    clippy::inconsistent_struct_constructor,
15    clippy::default_trait_access,
16    clippy::map_unwrap_or,
17    clippy::items_after_statements
18)]
19#[cfg(not(feature = "std"))]
20#[macro_use]
21extern crate alloc;
22#[cfg(feature = "std")]
23extern crate std as alloc;
24
25mod component_vec;
26mod dedup;
27mod guarded;
28
29#[cfg(test)]
30mod tests;
31
32pub use self::{component_vec::ComponentVec, dedup::DedupArena, guarded::GuardedEntity};
33use alloc::vec::Vec;
34use core::{
35    iter::{DoubleEndedIterator, Enumerate, ExactSizeIterator},
36    marker::PhantomData,
37    ops::{Index, IndexMut},
38    slice,
39};
40
41/// Types that can be used as indices for arenas.
42pub trait ArenaIndex: Copy {
43    /// Converts the [`ArenaIndex`] into the underlying `usize` value.
44    fn into_usize(self) -> usize;
45    /// Converts the `usize` value into the associated [`ArenaIndex`].
46    fn from_usize(value: usize) -> Self;
47}
48
49/// An arena allocator with a given index and entity type.
50///
51/// For performance reasons the arena cannot deallocate single entities.
52#[derive(Debug, Clone)]
53pub struct Arena<Idx, T> {
54    entities: Vec<T>,
55    marker: PhantomData<Idx>,
56}
57
58/// `Arena` does not store `Idx` therefore it is `Send` without its bound.
59unsafe impl<Idx, T> Send for Arena<Idx, T> where T: Send {}
60
61/// `Arena` does not store `Idx` therefore it is `Sync` without its bound.
62unsafe impl<Idx, T> Sync for Arena<Idx, T> where T: Send {}
63
64impl<Idx, T> Default for Arena<Idx, T> {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70impl<Idx, T> PartialEq for Arena<Idx, T>
71where
72    T: PartialEq,
73{
74    fn eq(&self, other: &Self) -> bool {
75        self.entities.eq(&other.entities)
76    }
77}
78
79impl<Idx, T> Eq for Arena<Idx, T> where T: Eq {}
80
81impl<Idx, T> Arena<Idx, T> {
82    /// Creates a new empty entity arena.
83    pub fn new() -> Self {
84        Self {
85            entities: Vec::new(),
86            marker: PhantomData,
87        }
88    }
89
90    /// Returns the allocated number of entities.
91    #[inline]
92    pub fn len(&self) -> usize {
93        self.entities.len()
94    }
95
96    /// Returns `true` if the arena has not yet allocated entities.
97    #[inline]
98    pub fn is_empty(&self) -> bool {
99        self.len() == 0
100    }
101
102    /// Clears all entities from the arena.
103    pub fn clear(&mut self) {
104        self.entities.clear();
105    }
106
107    /// Returns an iterator over the shared reference of the arena entities.
108    pub fn iter(&self) -> Iter<Idx, T> {
109        Iter {
110            iter: self.entities.iter().enumerate(),
111            marker: PhantomData,
112        }
113    }
114
115    /// Returns an iterator over the exclusive reference of the arena entities.
116    pub fn iter_mut(&mut self) -> IterMut<Idx, T> {
117        IterMut {
118            iter: self.entities.iter_mut().enumerate(),
119            marker: PhantomData,
120        }
121    }
122}
123
124impl<Idx, T> Arena<Idx, T>
125where
126    Idx: ArenaIndex,
127{
128    /// Returns the next entity index.
129    fn next_index(&self) -> Idx {
130        Idx::from_usize(self.entities.len())
131    }
132
133    /// Allocates a new entity and returns its index.
134    #[inline]
135    pub fn alloc(&mut self, entity: T) -> Idx {
136        let index = self.next_index();
137        self.entities.push(entity);
138        index
139    }
140
141    /// Returns a shared reference to the entity at the given index if any.
142    #[inline]
143    pub fn get(&self, index: Idx) -> Option<&T> {
144        self.entities.get(index.into_usize())
145    }
146
147    /// Returns an exclusive reference to the entity at the given index if any.
148    #[inline]
149    pub fn get_mut(&mut self, index: Idx) -> Option<&mut T> {
150        self.entities.get_mut(index.into_usize())
151    }
152}
153
154impl<Idx, T> FromIterator<T> for Arena<Idx, T> {
155    fn from_iter<I>(iter: I) -> Self
156    where
157        I: IntoIterator<Item = T>,
158    {
159        Self {
160            entities: Vec::from_iter(iter),
161            marker: PhantomData,
162        }
163    }
164}
165
166impl<'a, Idx, T> IntoIterator for &'a Arena<Idx, T>
167where
168    Idx: ArenaIndex,
169{
170    type Item = (Idx, &'a T);
171    type IntoIter = Iter<'a, Idx, T>;
172
173    fn into_iter(self) -> Self::IntoIter {
174        self.iter()
175    }
176}
177
178impl<'a, Idx, T> IntoIterator for &'a mut Arena<Idx, T>
179where
180    Idx: ArenaIndex,
181{
182    type Item = (Idx, &'a mut T);
183    type IntoIter = IterMut<'a, Idx, T>;
184
185    fn into_iter(self) -> Self::IntoIter {
186        self.iter_mut()
187    }
188}
189
190/// An iterator over shared references of arena entities and their indices.
191#[derive(Debug)]
192pub struct Iter<'a, Idx, T> {
193    iter: Enumerate<slice::Iter<'a, T>>,
194    marker: PhantomData<fn() -> Idx>,
195}
196
197impl<'a, Idx, T> Iterator for Iter<'a, Idx, T>
198where
199    Idx: ArenaIndex,
200{
201    type Item = (Idx, &'a T);
202
203    #[inline]
204    fn next(&mut self) -> Option<Self::Item> {
205        self.iter
206            .next()
207            .map(|(idx, entity)| (Idx::from_usize(idx), entity))
208    }
209
210    #[inline]
211    fn size_hint(&self) -> (usize, Option<usize>) {
212        self.iter.size_hint()
213    }
214}
215
216impl<'a, Idx, T> DoubleEndedIterator for Iter<'a, Idx, T>
217where
218    Idx: ArenaIndex,
219{
220    #[inline]
221    fn next_back(&mut self) -> Option<Self::Item> {
222        self.iter
223            .next()
224            .map(|(idx, entity)| (Idx::from_usize(idx), entity))
225    }
226}
227
228impl<'a, Idx, T> ExactSizeIterator for Iter<'a, Idx, T>
229where
230    Idx: ArenaIndex,
231{
232    fn len(&self) -> usize {
233        self.iter.len()
234    }
235}
236
237/// An iterator over exclusive references of arena entities and their indices.
238#[derive(Debug)]
239pub struct IterMut<'a, Idx, T> {
240    iter: Enumerate<slice::IterMut<'a, T>>,
241    marker: PhantomData<fn() -> Idx>,
242}
243
244impl<'a, Idx, T> Iterator for IterMut<'a, Idx, T>
245where
246    Idx: ArenaIndex,
247{
248    type Item = (Idx, &'a mut T);
249
250    #[inline]
251    fn next(&mut self) -> Option<Self::Item> {
252        self.iter
253            .next()
254            .map(|(idx, entity)| (Idx::from_usize(idx), entity))
255    }
256
257    #[inline]
258    fn size_hint(&self) -> (usize, Option<usize>) {
259        self.iter.size_hint()
260    }
261}
262
263impl<'a, Idx, T> DoubleEndedIterator for IterMut<'a, Idx, T>
264where
265    Idx: ArenaIndex,
266{
267    #[inline]
268    fn next_back(&mut self) -> Option<Self::Item> {
269        self.iter
270            .next()
271            .map(|(idx, entity)| (Idx::from_usize(idx), entity))
272    }
273}
274
275impl<'a, Idx, T> ExactSizeIterator for IterMut<'a, Idx, T>
276where
277    Idx: ArenaIndex,
278{
279    #[inline]
280    fn len(&self) -> usize {
281        self.iter.len()
282    }
283}
284
285impl<Idx, T> Arena<Idx, T> {
286    /// Panics with an index out of bounds message.
287    fn index_out_of_bounds(len: usize, index: usize) -> ! {
288        panic!("index out of bounds: the len is {len} but the index is {index}")
289    }
290}
291
292impl<Idx, T> Index<Idx> for Arena<Idx, T>
293where
294    Idx: ArenaIndex,
295{
296    type Output = T;
297
298    #[inline]
299    fn index(&self, index: Idx) -> &Self::Output {
300        self.get(index)
301            .unwrap_or_else(|| Self::index_out_of_bounds(self.len(), index.into_usize()))
302    }
303}
304
305impl<Idx, T> IndexMut<Idx> for Arena<Idx, T>
306where
307    Idx: ArenaIndex,
308{
309    #[inline]
310    fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
311        let len = self.len();
312        self.get_mut(index)
313            .unwrap_or_else(|| Self::index_out_of_bounds(len, index.into_usize()))
314    }
315}