zone_alloc/
strong_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;
9use core::marker::PhantomData;
10
11use crate::{
12    BorrowError,
13    ElementRef,
14    ElementRefMut,
15    Handle,
16    Registry,
17};
18
19/// A strong handle to data registered in a specific [`StrongRegistry`].
20///
21/// Strong handles are useful for separating handles from different registries. A handle from one
22/// strong registry cannot be used for a different strong registry because the handle type is
23/// statically enforced at compile time.
24pub trait StrongHandle: From<Handle> {
25    /// Returns the associated handle.
26    fn handle(&self) -> Handle;
27}
28
29/// The same as [`Registry<T>`], but with strongly-typed handles to prevent handles from being
30/// shared across multiple registries.
31///
32/// The handle type must implement the [`StrongHandle`] trait.
33#[derive(Default)]
34pub struct StrongRegistry<H, T> {
35    registry: Registry<T>,
36    phantom_handle: PhantomData<H>,
37}
38
39impl<H, T> StrongRegistry<H, T>
40where
41    H: StrongHandle,
42{
43    /// Creates a new strong registry.
44    pub fn new() -> Self {
45        Self {
46            registry: Registry::new(),
47            phantom_handle: PhantomData,
48        }
49    }
50
51    /// Creates a new strong registry with the given capacity.
52    pub fn with_capacity(size: usize) -> Self {
53        Self {
54            registry: Registry::with_capacity(size),
55            phantom_handle: PhantomData,
56        }
57    }
58
59    /// Checks if the registry is empty.
60    pub fn is_empty(&self) -> bool {
61        self.registry.is_empty()
62    }
63
64    /// Returns the number of elements owned by the strong registry.
65    pub fn len(&self) -> usize {
66        self.registry.len()
67    }
68
69    /// Registers a new value in the arena, returning a handle to that value.
70    pub fn register(&self, value: T) -> H {
71        H::from(self.registry.register(value))
72    }
73
74    /// Registers the contents of an iterator in the registry.
75    ///
76    /// Returns a numeric range of handles `[a, b)`, where `a` is the handle of the first element
77    /// inserted and `b` is the handle after the last element inserted.
78    pub fn register_extend<I>(&self, iterable: I) -> (H, H)
79    where
80        I: IntoIterator<Item = T>,
81    {
82        let (a, b) = self.registry.register_extend(iterable);
83        (H::from(a), H::from(b))
84    }
85
86    /// Ensures there is enough continuous space for at least `additional` values.
87    pub fn reserve(&self, additional: usize) {
88        self.registry.reserve(additional)
89    }
90
91    /// Converts the [`StrongRegistry<T>`] into a [`Vec<T>`].
92    ///
93    /// Items will maintain their handle as their vector index.
94    pub fn into_vec(self) -> Vec<T> {
95        self.registry.into_vec()
96    }
97
98    /// Returns an iterator that provides immutable access to all elements in the registry, in order
99    /// of registration.
100    pub fn iter(&self) -> impl Iterator<Item = Result<ElementRef<T>, BorrowError>> {
101        self.registry.iter()
102    }
103
104    /// Returns an iterator that provides mutable access to all elements in the registry, in order
105    /// of registration.
106    pub fn iter_mut(&mut self) -> impl Iterator<Item = Result<ElementRefMut<T>, BorrowError>> {
107        self.registry.iter_mut()
108    }
109
110    /// Returns a reference to a value previously registered in the registry.
111    ///
112    /// Panics if there is a borrow error.
113    pub fn get_unchecked(&self, handle: H) -> ElementRef<T> {
114        self.registry.get_unchecked(handle.handle())
115    }
116
117    /// Tries to get a reference to a value previously registered in the registry.
118    pub fn get(&self, handle: H) -> Result<ElementRef<T>, BorrowError> {
119        self.registry.get(handle.handle())
120    }
121
122    /// Returns a mutable reference to a value previously registered in the registry.
123    ///
124    /// Panics if there is a borrow error.
125    pub fn get_mut_unchecked(&self, handle: H) -> ElementRefMut<T> {
126        self.registry.get_mut_unchecked(handle.handle())
127    }
128
129    /// Tries to get a mutable reference to a value previously registered in the registry.
130    pub fn get_mut(&self, handle: H) -> Result<ElementRefMut<T>, BorrowError> {
131        self.registry.get_mut(handle.handle())
132    }
133
134    /// Checks if the registry is safe to drop.
135    ///
136    /// A registry is safe to drop if all elements are not borrowed. This check is not thread safe.
137    pub fn safe_to_drop(&mut self) -> bool {
138        self.registry.safe_to_drop()
139    }
140}
141
142#[cfg(test)]
143mod strong_registry_test {
144    use core::cell::Cell;
145
146    use crate::{
147        Handle,
148        StrongHandle,
149        StrongRegistry,
150    };
151
152    // A shared counter for how many times a value is deallocated.
153    struct DropCounter<'c>(&'c Cell<u32>);
154
155    impl<'c> Drop for DropCounter<'c> {
156        fn drop(&mut self) {
157            self.0.set(self.0.get() + 1);
158        }
159    }
160
161    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
162    struct NodeHandle(Handle);
163
164    impl From<Handle> for NodeHandle {
165        fn from(value: Handle) -> Self {
166            Self(value)
167        }
168    }
169
170    impl StrongHandle for NodeHandle {
171        fn handle(&self) -> Handle {
172            self.0
173        }
174    }
175
176    // A node type, like one used in a list, tree, or graph data structure.
177    //
178    // Helps us verify that arena-allocated values can refer to each other.
179    struct Node<'d, T> {
180        parent: Option<NodeHandle>,
181        value: T,
182        #[allow(dead_code)]
183        drop_counter: DropCounter<'d>,
184    }
185
186    impl<'a, 'd, T> Node<'d, T> {
187        pub fn new(parent: Option<NodeHandle>, value: T, drop_counter: DropCounter<'d>) -> Self {
188            Self {
189                parent,
190                value,
191                drop_counter,
192            }
193        }
194    }
195
196    #[test]
197    fn works_exactly_like_registry() {
198        let drop_counter = Cell::new(0);
199        {
200            let registry = StrongRegistry::with_capacity(2);
201            assert!(registry.is_empty());
202
203            // Allocate a chain of nodes that refer to each other.
204            let mut handle = registry.register(Node::new(None, 1, DropCounter(&drop_counter)));
205            assert_eq!(registry.len(), 1);
206            assert!(!registry.is_empty());
207            handle = registry.register(Node::new(Some(handle), 2, DropCounter(&drop_counter)));
208            assert_eq!(registry.len(), 2);
209            handle = registry.register(Node::new(Some(handle), 3, DropCounter(&drop_counter)));
210            assert_eq!(registry.len(), 3);
211            handle = registry.register(Node::new(Some(handle), 4, DropCounter(&drop_counter)));
212            assert_eq!(registry.len(), 4);
213
214            let mut node = registry.get(handle).unwrap();
215            assert_eq!(node.value, 4);
216            node = registry.get(node.parent.unwrap()).unwrap();
217            assert_eq!(node.value, 3);
218            node = registry.get(node.parent.unwrap()).unwrap();
219            assert_eq!(node.value, 2);
220            node = registry.get(node.parent.unwrap()).unwrap();
221            assert_eq!(node.value, 1);
222            assert_eq!(node.parent, None);
223            assert_eq!(drop_counter.get(), 0);
224        }
225        // All values deallocated at the same time.
226        assert_eq!(drop_counter.get(), 4);
227    }
228}