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}