anchored_pool/
unbounded.rs1#![expect(
2 unsafe_code,
3 reason = "Use UnsafeCell instead of the needless overhead of RefCell;
4 let unsafe code in Pools rely on PooledResource Drop impl",
5)]
6
7use std::{cell::UnsafeCell, rc::Rc};
8
9#[cfg(feature = "clone-behavior")]
10use clone_behavior::{MirroredClone, Speed};
11
12use crate::{
13 pooled_resource::{PooledResource, SealedPool},
14 other_utils::{ResetNothing, ResetResource},
15};
16
17
18#[derive(Debug)]
20pub struct UnboundedPool<Resource, Reset> {
21 pool: Rc<UnsafeCell<(
30 Vec<Resource>,
32 usize,
34 )>>,
35 reset_resource: Reset,
36}
37
38impl<Resource, Reset> UnboundedPool<Resource, Reset> {
39 #[inline]
43 #[must_use]
44 pub fn new(reset_resource: Reset) -> Self
45 where
46 Reset: ResetResource<Resource> + Clone,
47 {
48 Self {
49 pool: Rc::new(UnsafeCell::new((Vec::new(), 0))),
50 reset_resource,
51 }
52 }
53}
54
55impl<Resource> UnboundedPool<Resource, ResetNothing> {
56 #[inline]
60 #[must_use]
61 pub fn new_without_reset() -> Self {
62 Self::new(ResetNothing)
63 }
64}
65
66impl<Resource, Reset> UnboundedPool<Resource, Reset>
67where
68 Resource: Default,
69 Reset: ResetResource<Resource> + Clone,
70{
71 #[inline]
74 #[must_use]
75 pub fn get_default(&self) -> PooledResource<Self, Resource> {
76 self.get(Resource::default)
77 }
78}
79
80impl<Resource, Reset: ResetResource<Resource> + Clone> UnboundedPool<Resource, Reset> {
81 #[must_use]
83 pub fn get<F>(&self, init_resource: F) -> PooledResource<Self, Resource>
84 where
85 F: FnOnce() -> Resource,
86 {
87 let raw_cell_contents: *mut (Vec<Resource>, usize) = self.pool.get();
88
89 let mut cell_contents: &mut (Vec<Resource>, usize) = unsafe { &mut *raw_cell_contents };
94
95 let resource = if let Some(resource) = cell_contents.0.pop() {
96 resource
97 } else {
98 #[expect(
99 dropping_references,
100 reason = "ensure there is no active borrow while the callback is run",
101 )]
102 drop(cell_contents);
103 let resource = init_resource();
104 cell_contents = unsafe { &mut *raw_cell_contents };
109 resource
110 };
111
112 let pool = self.clone();
113 cell_contents.1 += 1;
114
115 unsafe { PooledResource::new(pool, resource) }
119 }
120
121 #[inline]
123 #[must_use]
124 pub fn pool_size(&self) -> usize {
125 let raw_cell_contents: *const (Vec<Resource>, usize) = self.pool.get().cast_const();
126
127 let cell_contents: &(Vec<Resource>, usize) = unsafe { &*raw_cell_contents };
133
134 cell_contents.0.len() + cell_contents.1
135 }
136
137 #[must_use]
139 pub fn available_resources(&self) -> usize {
140 let raw_cell_contents: *const (Vec<Resource>, usize) = self.pool.get().cast_const();
141
142 let cell_contents: &(Vec<Resource>, usize) = unsafe { &*raw_cell_contents };
148
149 cell_contents.0.len()
150 }
151}
152
153impl<Resource, Reset> SealedPool<Resource> for UnboundedPool<Resource, Reset>
154where
155 Reset: ResetResource<Resource> + Clone,
156{
157 type Returner = Self;
158
159 unsafe fn return_resource(returner: &Self::Returner, mut resource: Resource) {
166 returner.reset_resource.reset(&mut resource);
168
169 let raw_cell_contents: *mut (Vec<Resource>, usize) = returner.pool.get();
170
171 let cell_contents: &mut (Vec<Resource>, usize) = unsafe { &mut *raw_cell_contents };
177
178 cell_contents.1 -= 1;
179 cell_contents.0.push(resource);
180 }
181}
182
183impl<Resource, Reset> Default for UnboundedPool<Resource, Reset>
184where
185 Reset: ResetResource<Resource> + Clone + Default,
186{
187 #[inline]
188 fn default() -> Self {
189 Self::new(Reset::default())
190 }
191}
192
193impl<Resource, ResetResource: Clone> Clone for UnboundedPool<Resource, ResetResource> {
194 #[inline]
195 fn clone(&self) -> Self {
196 Self {
197 pool: Rc::clone(&self.pool),
198 reset_resource: self.reset_resource.clone(),
199 }
200 }
201
202 #[inline]
203 fn clone_from(&mut self, source: &Self) {
204 self.pool.clone_from(&source.pool);
205 self.reset_resource.clone_from(&source.reset_resource);
206 }
207}
208
209#[cfg(feature = "clone-behavior")]
210impl<Resource, ResetResource, S> MirroredClone<S> for UnboundedPool<Resource, ResetResource>
211where
212 ResetResource: MirroredClone<S>,
213 S: Speed,
214{
215 #[inline]
216 fn mirrored_clone(&self) -> Self {
217 Self {
218 pool: Rc::clone(&self.pool),
219 reset_resource: self.reset_resource.mirrored_clone(),
220 }
221 }
222}
223
224
225#[cfg(all(test, not(tests_with_leaks)))]
226mod tests {
227 use std::array;
228 use super::*;
229
230
231 #[test]
232 fn zero_or_one_size() {
233 let pool: UnboundedPool<(), ResetNothing> = UnboundedPool::new_without_reset();
234 assert_eq!(pool.pool_size(), 0);
235 assert_eq!(pool.available_resources(), 0);
236
237 let unit = pool.get_default();
238 let _: &() = &unit;
239 assert_eq!(pool.pool_size(), 1);
240 assert_eq!(pool.available_resources(), 0);
241
242 drop(unit);
243 assert_eq!(pool.pool_size(), 1);
244 assert_eq!(pool.available_resources(), 1);
245 }
246
247 #[test]
248 fn init_and_reset() {
249 const SIZE: usize = 10;
250
251 let pool = UnboundedPool::new(|int: &mut usize| *int = 1);
252 let integers: [_; SIZE] = array::from_fn(|_| pool.get(|| 1_usize));
253
254 for (idx, mut integer) in integers.into_iter().enumerate() {
255 assert_eq!(*integer, 1);
256 *integer = idx;
257 assert_eq!(*integer, idx);
258 }
259
260 let integers: [_; SIZE] = array::from_fn(|_| pool.get(|| 2_usize));
262 for integer in integers {
263 assert_eq!(*integer, 1);
264 }
265 }
266
267 #[test]
268 fn no_reset() {
269 const SIZE: usize = 10;
270
271 let pool = UnboundedPool::new(ResetNothing);
272 let integers: [_; SIZE] = array::from_fn(|_| pool.get(|| 1_usize));
273 for (idx, mut integer) in integers.into_iter().enumerate() {
274 assert_eq!(*integer, 1);
275 *integer = idx;
276 assert_eq!(*integer, idx);
277 }
278
279 let integers: [_; SIZE] = array::from_fn(|_| pool.get(|| 1_usize));
282 assert_eq!(*pool.get(|| 11), 11);
284
285 for (idx, integer) in integers.into_iter().rev().enumerate() {
286 assert_eq!(*integer, idx);
287 }
288 }
289
290 #[test]
292 fn init_and_reset_disagreeing() {
293 let pool = UnboundedPool::new(|int: &mut i32| *int = 2);
294 let first_int = pool.get_default();
295 assert_eq!(*first_int, 0);
296 drop(first_int);
297 let mut reset_first_int = pool.get_default();
298 assert_eq!(*reset_first_int, 2);
299 let second_int = pool.get_default();
300 assert_eq!(*second_int, 0);
301 *reset_first_int = 3;
302 assert_eq!(*reset_first_int, 3);
303 drop(reset_first_int);
304 let re_reset_first_int = pool.get_default();
305 assert_eq!(*re_reset_first_int, 2);
306 }
307}