triple_r/vec.rs
1use crate::ReuseCastInto;
2use std::{
3 cell::UnsafeCell,
4 marker::PhantomData,
5 ops::{Deref, DerefMut},
6};
7
8/// A wrapper around [`Vec`] that allows for reusing its allocation.
9///
10/// In performance-sensitive applications, frequent creation and destruction of
11/// vectors can lead to significant overhead from memory allocations. `ReusableVec`
12/// mitigates this by providing a mechanism to recycle a vector's allocation.
13///
14/// The [`recycle`](ReusableVec::recycle) method returns a [`ReusableVecGuard`], which provides temporary, exclusive access
15/// to the underlying vector. When the guard is dropped, the vector is cleared,
16/// but its underlying memory allocation is preserved for subsequent use.
17///
18/// # Type Parameters
19///
20/// - `T`: The type of elements in the `Vec`. This type must be `'static` because
21/// the `ReusableVec` itself holds onto the allocation indefinitely.
22///
23/// # Safety
24///
25/// This struct uses an [`UnsafeCell`] to hold the `Vec`, which allows for mutating
26/// its contents through a shared reference. The safety of this pattern is
27/// guaranteed by the `recycle` method, which requires a mutable reference (`&mut self`).
28/// This ensures that only one `ReusableVecGuard` can exist at a time for a given
29/// `ReusableVec`, thereby preventing data races.
30///
31/// # Examples
32///
33/// ## Basic Reuse
34///
35/// ```
36/// use triple_r::ReusableVec;
37///
38/// let mut reusable_vec = ReusableVec::<i32>::default();
39///
40/// // First use: populate the vector
41/// {
42/// let mut vec_guard = reusable_vec.recycle();
43/// vec_guard.push(10);
44/// vec_guard.push(20);
45/// assert_eq!(*vec_guard, vec![10, 20]);
46/// } // Guard is dropped, vector is cleared, but allocation is kept.
47///
48/// // Second use: the vector is empty but has retained its capacity.
49/// {
50/// let mut vec_guard = reusable_vec.recycle();
51/// assert!(vec_guard.is_empty());
52/// assert!(vec_guard.capacity() >= 2);
53/// vec_guard.push(30);
54/// assert_eq!(*vec_guard, vec![30]);
55/// }
56/// ```
57#[derive(Debug)]
58pub struct ReusableVec<T: 'static> {
59 inner: UnsafeCell<Vec<T>>,
60}
61
62// The `ReusableVec` is safe to send across threads if `T` is `Send`.
63unsafe impl<T: Send> Send for ReusableVec<T> {}
64
65// The `ReusableVec` is safe to share across threads if `T` is `Send`.
66// The `recycle` method requires `&mut self`, which prevents concurrent access
67// without external synchronization (like a `Mutex`).
68unsafe impl<T: Send> Sync for ReusableVec<T> {}
69
70impl<T: 'static> Default for ReusableVec<T> {
71 /// Creates a new, empty `ReusableVec` with no allocation.
72 fn default() -> Self {
73 Self {
74 inner: UnsafeCell::new(Vec::new()),
75 }
76 }
77}
78
79/// A RAII guard that provides temporary, exclusive access to a `Vec` from a
80/// [`ReusableVec`].
81///
82/// This guard is created by [`ReusableVec::recycle`]. It allows the underlying
83/// `Vec` to be accessed and modified. When the guard goes out of scope, it
84/// automatically clears the `Vec`, preserving its allocation for the next cycle.
85///
86/// The lifetime `'parent` ensures that this guard cannot outlive the
87/// [`ReusableVec`] from which it was borrowed.
88pub struct ReusableVecGuard<'parent, T1, T2>
89where
90 T1: 'static,
91{
92 inner: *mut Vec<T2>,
93 _parent: PhantomData<&'parent mut ReusableVec<T1>>,
94}
95
96impl<'parent, T1, T2> Deref for ReusableVecGuard<'parent, T1, T2>
97where
98 T1: 'static,
99{
100 type Target = Vec<T2>;
101
102 /// Provides immutable access to the underlying `Vec`.
103 fn deref(&self) -> &Self::Target {
104 // SAFETY: `self.inner` is a valid pointer for the lifetime `'parent`.
105 // This is enforced by `_parent` and the `recycle` method signature,
106 // which takes `&mut self` on the parent `ReusableVec`.
107 unsafe { &*self.inner }
108 }
109}
110
111impl<'parent, T1, T2> DerefMut for ReusableVecGuard<'parent, T1, T2>
112where
113 T1: 'static,
114{
115 /// Provides mutable access to the underlying `Vec`.
116 fn deref_mut(&mut self) -> &mut Self::Target {
117 // SAFETY: The same guarantees as `deref` apply. Mutable access is safe
118 // because the `&mut self` borrow on the parent `ReusableVec` prevents
119 // any other access.
120 unsafe { &mut *self.inner }
121 }
122}
123
124impl<T1> ReusableVec<T1>
125where
126 T1: 'static,
127{
128 /// Reuses the `Vec`'s allocation, returning a guard for temporary access.
129 ///
130 /// This method allows the `Vec`'s element type to be "cast" to a new type `T2`,
131 /// as long as the original type `T1` implements [`ReuseCastInto<T2>`].
132 ///
133 /// The `&mut self` requirement is a key safety feature, as it ensures that
134 /// only one guard can be active at any given time.
135 pub fn recycle<'parent, T2>(&'parent mut self) -> ReusableVecGuard<'parent, T1, T2>
136 where
137 T1: ReuseCastInto<T2>,
138 {
139 // SAFETY: We use `get()` to obtain a raw pointer to the vector.
140 // This is safe because `&mut self` guarantees exclusive access.
141 let inner_ptr = self.inner.get() as *mut Vec<T2>;
142
143 ReusableVecGuard {
144 inner: inner_ptr,
145 _parent: PhantomData,
146 }
147 }
148}
149
150impl<'parent, T1, T2> Drop for ReusableVecGuard<'parent, T1, T2>
151where
152 T1: 'static,
153{
154 /// Clears the `Vec` when the guard is dropped.
155 fn drop(&mut self) {
156 // SAFETY: The pointer `self.inner` is guaranteed to be valid because
157 // the guard's lifetime is tied to the parent `ReusableVec`.
158 // Clearing the vector prepares it for the next reuse cycle.
159 unsafe {
160 (*self.inner).clear();
161 }
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn primitive_reuse_works() {
171 let mut vec = ReusableVec::<i32>::default();
172 {
173 let mut r_vec = vec.recycle::<i32>();
174 r_vec.push(1);
175 r_vec.push(2);
176 assert_eq!(r_vec.as_slice(), &[1, 2]);
177 }
178 let r_vec = unsafe { &*vec.inner.get() };
179 assert!(r_vec.is_empty());
180 assert!(r_vec.capacity() >= 2);
181 }
182
183 #[test]
184 fn reference_reuse_works() {
185 let mut vec = ReusableVec::<&'static str>::default();
186 let capacity;
187 {
188 let hello = String::from("Hello");
189 let world = String::from("World");
190 let mut r_vec = vec.recycle();
191 r_vec.push(hello.as_str());
192 r_vec.push(world.as_str());
193 assert_eq!(r_vec.as_slice(), &["Hello", "World"]);
194 capacity = r_vec.capacity();
195 }
196 let r_vec = unsafe { &*vec.inner.get() };
197 assert!(r_vec.is_empty());
198 assert_eq!(r_vec.capacity(), capacity);
199 }
200
201 #[test]
202 fn sequential_reuse_works() {
203 let mut vec = ReusableVec::<String>::default();
204 let mut last_capacity;
205 {
206 let mut r_vec = vec.recycle::<String>();
207 r_vec.push("one".to_string());
208 assert_eq!(r_vec.len(), 1);
209 last_capacity = r_vec.capacity();
210 }
211
212 let r_vec = unsafe { &*vec.inner.get() };
213 assert!(r_vec.is_empty());
214 assert_eq!(r_vec.capacity(), last_capacity);
215
216 {
217 let mut r_vec = vec.recycle::<String>();
218 r_vec.push("two".to_string());
219 r_vec.push("three".to_string());
220 assert_eq!(r_vec.len(), 2);
221 last_capacity = r_vec.capacity();
222 }
223
224 let r_vec = unsafe { &*vec.inner.get() };
225 assert!(r_vec.is_empty());
226 assert_eq!(r_vec.capacity(), last_capacity);
227 }
228}