zone_alloc/
registry.rs

1#[cfg(not(feature = "std"))]
2extern crate alloc;
3
4#[cfg(feature = "std")]
5extern crate core;
6
7#[cfg(not(feature = "std"))]
8use alloc::vec::Vec;
9
10use crate::{
11    base_registry::{
12        BaseRegistry,
13        BaseRegistryEntry,
14    },
15    BorrowError,
16    ElementRef,
17    ElementRefMut,
18};
19
20/// A handle to data registered in a specific [`Registry`].
21///
22/// A handle is returned when an element is registered in a registry. It can be passed back to the
23/// registry to get a mutable reference to the same data.
24pub type Handle = usize;
25
26/// A container that can be used for registering values of a given type and retrieving references by
27/// handle.
28///
29/// A registry is a centralized container that values can be inserted into and borrowed from. A
30/// registry provides several guarantees:
31/// - Arena-based allocated values using an [`Arena`][`crate::Arena`] (all references are valid for
32///   the lifetime of the container).
33/// - Runtime-checked immutable and mutable borrow rules.
34/// - Values can be borrowed completely independent of one another.
35///
36/// A single value can be moved into the registry using [`Registry::register`], and multiple values
37/// can be moved in using [`Registry::register_extend`].
38#[derive(Default)]
39pub struct Registry<T> {
40    base: BaseRegistry<usize, T, Vec<BaseRegistryEntry<T>>>,
41}
42
43impl<T> Registry<T> {
44    /// Creates a new registry.
45    pub fn new() -> Self {
46        Self {
47            base: BaseRegistry::new(),
48        }
49    }
50
51    /// Creates a new registry with the given capacity.
52    pub fn with_capacity(size: usize) -> Self {
53        Self {
54            base: BaseRegistry::with_capacity(size),
55        }
56    }
57
58    /// Checks if the registry is empty.
59    pub fn is_empty(&self) -> bool {
60        self.base.is_empty()
61    }
62
63    /// Returns the number of elements owned by the registry.
64    pub fn len(&self) -> usize {
65        self.base.len()
66    }
67
68    /// Registers a new value in the arena, returning a handle to that value.
69    pub fn register(&self, value: T) -> Handle {
70        let handle = self.base.len();
71        let (data, borrow_state) = self.base.insert(value);
72        self.base
73            .entries_mut()
74            .push(BaseRegistryEntry::new(data, borrow_state));
75        handle
76    }
77
78    /// Registers the contents of an iterator in the registry.
79    ///
80    /// Returns a numeric range of handles `[a, b)`, where `a` is the handle of the first element
81    /// inserted and `b` is the handle after the last element inserted.
82    pub fn register_extend<I>(&self, iterable: I) -> (Handle, Handle)
83    where
84        I: IntoIterator<Item = T>,
85    {
86        let data = self.base.insert_extend(iterable);
87        let first = self.base.entries().len();
88        self.base.entries_mut().extend(
89            data.into_iter()
90                .map(|data| BaseRegistryEntry::new(data.0, data.1)),
91        );
92        let next = self.base.len();
93        (first, next)
94    }
95
96    /// Ensures there is enough continuous space for at least `additional` values.
97    pub fn reserve(&self, additional: usize) {
98        self.base.reserve(additional)
99    }
100
101    /// Converts the [`Registry<T>`] into a [`Vec<T>`].
102    ///
103    /// Items will maintain their handle as their vector index.
104    pub fn into_vec(self) -> Vec<T> {
105        self.base.into_vec()
106    }
107
108    /// Returns an iterator that provides immutable access to all elements in the registry, in order
109    /// of registration.
110    pub fn iter(&self) -> impl Iterator<Item = Result<ElementRef<T>, BorrowError>> {
111        self.base.entries().iter().map(|entry| entry.borrow())
112    }
113
114    /// Returns an iterator that provides mutable access to all elements in the registry, in order
115    /// of registration.
116    pub fn iter_mut(&mut self) -> impl Iterator<Item = Result<ElementRefMut<T>, BorrowError>> {
117        self.base
118            .entries_mut()
119            .iter_mut()
120            .map(|entry| entry.borrow_mut())
121    }
122
123    /// Returns a reference to a value previously registered in the registry.
124    ///
125    /// Panics if there is a borrow error.
126    pub fn get_unchecked(&self, handle: Handle) -> ElementRef<T> {
127        self.base.borrow(&handle)
128    }
129
130    /// Tries to get a reference to a value previously registered in the registry.
131    pub fn get(&self, handle: Handle) -> Result<ElementRef<T>, BorrowError> {
132        self.base.try_borrow(&handle)
133    }
134
135    /// Returns a mutable reference to a value previously registered in the registry.
136    ///
137    /// Panics if there is a borrow error.
138    pub fn get_mut_unchecked(&self, handle: Handle) -> ElementRefMut<T> {
139        self.base.borrow_mut(&handle)
140    }
141
142    /// Tries to get a mutable reference to a value previously registered in the registry.
143    pub fn get_mut(&self, handle: Handle) -> Result<ElementRefMut<T>, BorrowError> {
144        self.base.try_borrow_mut(&handle)
145    }
146
147    /// Checks if the registry is safe to drop.
148    ///
149    /// A registry is safe to drop if all elements are not borrowed. This check is not thread safe.
150    pub fn safe_to_drop(&mut self) -> bool {
151        self.base.safe_to_drop()
152    }
153}
154
155#[cfg(test)]
156mod registry_test {
157    #[cfg(not(feature = "std"))]
158    extern crate alloc;
159
160    #[cfg(not(feature = "std"))]
161    use alloc::{
162        vec,
163        vec::Vec,
164    };
165    use core::{
166        cell::Cell,
167        mem,
168    };
169
170    use crate::{
171        BorrowError,
172        ElementRef,
173        ElementRefMut,
174        Handle,
175        Registry,
176    };
177
178    // A shared counter for how many times a value is deallocated.
179    struct DropCounter<'c>(&'c Cell<u32>);
180
181    impl<'c> Drop for DropCounter<'c> {
182        fn drop(&mut self) {
183            self.0.set(self.0.get() + 1);
184        }
185    }
186
187    // A node type, like one used in a list, tree, or graph data structure.
188    //
189    // Helps us verify that arena-allocated values can refer to each other.
190    struct Node<'d, T> {
191        parent: Option<Handle>,
192        value: T,
193        #[allow(dead_code)]
194        drop_counter: DropCounter<'d>,
195    }
196
197    impl<'a, 'd, T> Node<'d, T> {
198        pub fn new(parent: Option<Handle>, value: T, drop_counter: DropCounter<'d>) -> Self {
199            Self {
200                parent,
201                value,
202                drop_counter,
203            }
204        }
205    }
206
207    #[test]
208    #[allow(dropping_references)]
209    fn allocates_and_owns_values() {
210        let drop_counter = Cell::new(0);
211        {
212            let registry = Registry::with_capacity(2);
213            assert!(registry.is_empty());
214
215            // Allocate a chain of nodes that refer to each other.
216            let mut handle = registry.register(Node::new(None, 1, DropCounter(&drop_counter)));
217            assert_eq!(registry.len(), 1);
218            assert!(!registry.is_empty());
219            handle = registry.register(Node::new(Some(handle), 2, DropCounter(&drop_counter)));
220            assert_eq!(registry.len(), 2);
221            handle = registry.register(Node::new(Some(handle), 3, DropCounter(&drop_counter)));
222            assert_eq!(registry.len(), 3);
223            handle = registry.register(Node::new(Some(handle), 4, DropCounter(&drop_counter)));
224            assert_eq!(registry.len(), 4);
225
226            let node = registry.get(handle).unwrap();
227            assert_eq!(node.value, 4);
228            let node = registry.get(node.parent.unwrap()).unwrap();
229            assert_eq!(node.value, 3);
230            let node = registry.get(node.parent.unwrap()).unwrap();
231            assert_eq!(node.value, 2);
232            let node = registry.get(node.parent.unwrap()).unwrap();
233            assert_eq!(node.value, 1);
234            assert_eq!(node.parent, None);
235            assert_eq!(drop_counter.get(), 0);
236        }
237        // All values deallocated at the same time.
238        assert_eq!(drop_counter.get(), 4);
239    }
240
241    #[test]
242    fn register_extend_allocates_and_returns_handle_range() {
243        let registry = Registry::new();
244        let mut next_handle = 0;
245        for i in 0..15 {
246            let (begin, end) = registry.register_extend(0..i);
247            assert_eq!(begin, next_handle);
248            assert_eq!(end - begin, i);
249            for (j, handle) in (0..i).zip(begin..end) {
250                assert!(registry.get_unchecked(handle).eq(&j));
251            }
252            next_handle = end;
253        }
254    }
255
256    #[test]
257    fn register_extend_allocates_and_owns_values() {
258        let drop_counter = Cell::new(0);
259        {
260            let registry = Registry::with_capacity(2);
261            let iter = (0..100).map(|i| Node::new(None, i, DropCounter(&drop_counter)));
262            let root = registry.register_extend(iter).0;
263            let iter = (0..100).map(|i| Node::new(Some(root), i, DropCounter(&drop_counter)));
264            registry.register_extend(iter);
265            assert_eq!(drop_counter.get(), 0);
266        }
267        assert_eq!(drop_counter.get(), 200);
268    }
269
270    #[test]
271    fn into_vec_reflects_insertion_order() {
272        let registry = Registry::new();
273        for &s in &["a", "b", "c", "d"] {
274            registry.register(s);
275        }
276        let vec = registry.into_vec();
277        assert_eq!(vec, vec!["a", "b", "c", "d"])
278    }
279
280    #[test]
281    fn iter_itereates_in_order() {
282        #[derive(Debug, PartialEq, Eq)]
283        struct NoCopy(usize);
284
285        let registry = Registry::new();
286        for i in 0..10 {
287            registry.register(NoCopy(i));
288        }
289        assert!(registry
290            .iter()
291            .zip((0..10).map(|i| NoCopy(i)))
292            .all(|(a, b)| a.is_ok_and(|a| a.eq(&b))));
293    }
294
295    #[test]
296    fn iter_mut_itereates_in_order() {
297        #[derive(Debug, PartialEq, Eq)]
298        struct NoCopy(usize);
299
300        let mut registry = Registry::new();
301        for i in 0..10 {
302            registry.register(NoCopy(i));
303        }
304        assert!(registry
305            .iter_mut()
306            .zip((0..10).map(|i| NoCopy(i)))
307            .all(|(a, b)| a.is_ok_and(|a| a.eq(&b))));
308    }
309
310    #[test]
311    fn iter_mut_allows_mutable_access() {
312        let mut registry = Registry::new();
313        for i in 0..10 {
314            registry.register(i);
315        }
316        for i in registry.iter_mut() {
317            assert!(i.is_ok());
318            *i.unwrap() += 1;
319        }
320        assert!(registry
321            .iter_mut()
322            .zip(1..11)
323            .all(|(a, b)| a.is_ok_and(|a| a.eq(&b))));
324    }
325
326    #[test]
327    fn handles_valid_with_large_blocks() {
328        let registry = Registry::with_capacity(2);
329        // Commit the first block and start the next.
330        let first_range = registry.register_extend(0..1);
331        let second_range = registry.register_extend(0..100);
332        // Since the current block has elements in it, a new block is created.
333        registry.reserve(1000);
334        // These should fit in the same block.
335        let third_range = registry.register_extend(0..500);
336        let fourth_range = registry.register_extend(501..1000);
337
338        // Validate that all handles still refer to the inserted values.
339        assert!((first_range.0..first_range.1)
340            .zip(0..1)
341            .all(|(handle, value)| *registry.get_unchecked(handle) == value));
342        assert!((second_range.0..second_range.1)
343            .zip(0..100)
344            .all(|(handle, value)| *registry.get_unchecked(handle) == value));
345        assert!((third_range.0..third_range.1)
346            .zip(0..500)
347            .all(|(handle, value)| *registry.get_unchecked(handle) == value));
348        assert!((fourth_range.0..fourth_range.1)
349            .zip(501..1000)
350            .all(|(handle, value)| *registry.get_unchecked(handle) == value));
351    }
352
353    #[test]
354    fn tracks_length() {
355        let registry = Registry::with_capacity(16);
356        registry.register_extend(0..4);
357        assert_eq!(registry.len(), 4);
358        registry.register(5);
359        assert_eq!(registry.len(), 5);
360        registry.register(6);
361        assert_eq!(registry.len(), 6);
362        registry.register_extend(0..100);
363        assert_eq!(registry.len(), 106);
364    }
365
366    #[test]
367    fn borrow_out_of_bounds() {
368        let registry = Registry::new();
369        registry.register_extend(0..4);
370        assert_eq!(registry.get(5).err(), Some(BorrowError::OutOfBounds));
371        assert_eq!(registry.get_mut(6).err(), Some(BorrowError::OutOfBounds));
372    }
373
374    #[test]
375    fn counts_immutable_borrws() {
376        let registry = Registry::new();
377        registry.register_extend(1..5);
378        {
379            let borrow_1 = registry.get(1);
380            let borrow_2 = registry.get(1);
381            let borrow_3 = registry.get(1);
382            assert!(borrow_1.as_ref().is_ok_and(|val| val.eq(&2)));
383            assert!(borrow_2.as_ref().is_ok_and(|val| val.eq(&2)));
384            drop(borrow_1);
385            drop(borrow_2);
386            assert_eq!(
387                registry.get_mut(1).err(),
388                Some(BorrowError::AlreadyBorrowed)
389            );
390            assert!(borrow_3.is_ok_and(|val| val.eq(&2)));
391        }
392        assert!(registry.get_mut(1).is_ok_and(|val| val.eq(&2)));
393    }
394
395    #[test]
396    fn only_one_mutable_borrow() {
397        let registry = Registry::new();
398        registry.register_extend(1..5);
399        let mut borrow_1 = registry.get_mut(2);
400        assert!(borrow_1.as_ref().is_ok_and(|val| val.eq(&3)));
401        assert_eq!(
402            registry.get_mut(2).err(),
403            Some(BorrowError::AlreadyBorrowed)
404        );
405        *borrow_1.as_deref_mut().unwrap() *= 2;
406        drop(borrow_1);
407        let borrow_2 = registry.get_mut(2);
408        assert!(borrow_2.as_ref().is_ok_and(|val| val.eq(&6)));
409    }
410
411    #[test]
412    fn borrows_do_not_interfere() {
413        let registry = Registry::new();
414        registry.register_extend(1..5);
415        let borrow_0_1 = registry.get(0);
416        let borrow_1_1 = registry.get_mut(1);
417        let borrow_2_1 = registry.get(2);
418        let borrow_2_2 = registry.get(2);
419        let borrow_3_1 = registry.get_mut(3);
420        assert!(borrow_0_1.as_ref().is_ok_and(|val| val.eq(&1)));
421        assert!(borrow_1_1.as_ref().is_ok_and(|val| val.eq(&2)));
422        assert!(borrow_2_1.as_ref().is_ok_and(|val| val.eq(&3)));
423        assert!(borrow_2_2.as_ref().is_ok_and(|val| val.eq(&3)));
424        assert!(borrow_3_1.as_ref().is_ok_and(|val| val.eq(&4)));
425    }
426
427    #[test]
428    fn immutable_borrow_can_be_cloned() {
429        let registry = Registry::new();
430        registry.register_extend(1..5);
431        let borrow_1 = registry.get_unchecked(0);
432        let borrow_2 = borrow_1.clone();
433        assert!(borrow_1.eq(&1));
434        assert!(borrow_2.eq(&1));
435        drop(borrow_1);
436        assert_eq!(
437            registry.get_mut(0).err(),
438            Some(BorrowError::AlreadyBorrowed)
439        );
440        drop(borrow_2);
441        assert!(registry.get_mut(0).is_ok_and(|val| val.eq(&1)));
442    }
443
444    #[test]
445    fn can_register_with_borrows_out() {
446        let registry = Registry::with_capacity(16);
447        registry.register_extend(1..5);
448        let borrow_1 = registry.get(0);
449        let borrow_2 = registry.get_mut(1);
450        registry.register_extend(5..100);
451        let borrow_3 = registry.get(4);
452        let borrow_4 = registry.get(97);
453        assert!(borrow_1.is_ok_and(|a| a.eq(&1)));
454        assert!(borrow_2.is_ok_and(|a| a.eq(&2)));
455        assert!(borrow_3.is_ok_and(|a| a.eq(&5)));
456        assert!(borrow_4.is_ok_and(|a| a.eq(&98)));
457    }
458
459    #[test]
460    fn borrow_in_iterator_succeeds_with_borrow_out() {
461        let registry = Registry::new();
462        registry.register_extend(1..5);
463        let borrow = registry.get(2);
464        assert_eq!(
465            registry
466                .iter()
467                .map(|result| result.err())
468                .collect::<Vec<Option<BorrowError>>>(),
469            vec![None, None, None, None]
470        );
471        drop(borrow);
472    }
473
474    #[test]
475    fn borrow_in_iterator_fails_with_mutable_borrow_out() {
476        let registry = Registry::new();
477        registry.register_extend(1..5);
478        let borrow = registry.get_mut(2);
479        assert_eq!(
480            registry
481                .iter()
482                .map(|result| result.err())
483                .collect::<Vec<Option<BorrowError>>>(),
484            vec![None, None, Some(BorrowError::AlreadyBorrowed), None]
485        );
486        drop(borrow);
487    }
488
489    #[test]
490    fn safe_to_drop_tracks_borrows() {
491        let mut registry = Registry::new();
492        registry.register_extend(1..5);
493        assert!(registry.safe_to_drop());
494
495        let borrow_1: ElementRef<'_, i32> = unsafe { mem::transmute(registry.get(0)) };
496        let borrow_2: ElementRef<'_, i32> = unsafe { mem::transmute(registry.get(0)) };
497        let borrow_3: ElementRefMut<'_, i32> = unsafe { mem::transmute(registry.get_mut(1)) };
498        assert!(!registry.safe_to_drop());
499
500        assert!(borrow_1.eq(&1));
501        assert!(borrow_2.eq(&1));
502        assert!(borrow_3.eq(&2));
503
504        drop(borrow_1);
505        assert!(!registry.safe_to_drop());
506        drop(borrow_2);
507        assert!(!registry.safe_to_drop());
508        drop(borrow_3);
509        assert!(registry.safe_to_drop());
510    }
511}