derivable_object_pool/lib.rs
1//! # Derivable Object Pool
2//!
3//! This crate provides a trait that can be derived to implement an object pool
4//! for a type with a single line of code. Allowing the user to forget about
5//! the implementation details of the [`ObjectPool`] and focus on the important
6//! parts of their code
7//!
8//! This crate has the following features compared to other object pool crates:
9//! - **Derivable**: The pool is simple to use and can be used with any type. Can
10//! be just derived using the [`#[derive(ObjectPool)]`](derive@ObjectPool)
11//! attribute macro.
12//! - **Reusable**: The user can use the [`ObjectPool::new`] function to create
13//! objects from the pool, which will reuse objects from the pool if possible.
14//! This items are wrapped in a [`Reusable`] struct, which will be returned to
15//! the pool when dropped.
16//! - **Thread Safe**: The pool is thread-safe (through the use of a [`Mutex`])
17//! and can be used in a multi-threaded environment.
18//! - **Simple**: The user doesn't need to create a pool for each type manually
19//! and can use the [`ObjectPool::new`] function to create objects from the
20//! pool.
21//! - **Flexible**: The user can configure the pool to use a custom generator
22//! function (see attributes in [`#[derive(ObjectPool)]`](derive@ObjectPool)) or
23//! just use the [`Default`] trait to create new objects.
24//!
25//! # Example
26//!
27//! ```
28//! use derivable_object_pool::prelude::*;
29//!
30//! #[derive(Default, ObjectPool)]
31//! struct Test(i32);
32//!
33//! fn main() {
34//! let mut obj = Test::new();
35//! obj.0 += 1;
36//! assert_eq!(obj.0, 1);
37//! drop(obj); // obj is returned to the pool
38//! assert_eq!(Test::pool().len(), 1);
39//! let mut obj = Test::new();
40//! assert_eq!(Test::pool().len(), 0);
41//! assert_eq!(obj.0, 1);
42//! }
43//! ```
44use std::borrow::{Borrow, BorrowMut};
45use std::mem::{forget, ManuallyDrop};
46use std::ops::{Deref, DerefMut};
47use std::sync::{Mutex, MutexGuard};
48
49pub use derivable_object_pool_macros::ObjectPool;
50
51/// Allows for the creation of objects that can be reused. This is useful for
52/// objects that are expensive to create, but are used frequently. This trait
53/// can be derived using the `#[derive(ObjectPool)]` attribute macro (for more
54/// information, see the documentation for the [`ObjectPool`] trait)
55///
56/// The new objects will be created using a generator function, which can be
57/// specified using the `#[generator(function_name)]` attribute macro on the
58/// struct. If no generator is specified, the trait will use the [`Default`]
59/// trait to create new objects.
60///
61/// # Example
62///
63/// Example without a generator:
64/// ```
65/// use derivable_object_pool::prelude::*;
66///
67/// #[derive(Default, ObjectPool)]
68/// struct Test {
69/// a: i32,
70/// b: f64,
71/// }
72///
73/// fn main() {
74/// let obj = Test::new();
75/// drop(obj); // obj is returned to the pool
76/// let obj2 = Test::new(); // obj2 is the same object as obj
77/// }
78/// ```
79///
80/// Example with a generator:
81/// ```
82///
83/// use derivable_object_pool::prelude::*;
84///
85/// #[derive(ObjectPool)]
86/// #[generator(Test::new_item)]
87/// struct Test {
88/// a: i32,
89/// b: f64,
90/// }
91///
92/// impl Test {
93/// fn new_item() -> Self {
94/// Self {
95/// a: 1,
96/// b: 1.0,
97/// }
98/// }
99/// }
100///
101/// fn main() {
102/// let obj = Test::new();
103/// drop(obj); // obj is returned to the pool
104/// let obj2 = Test::new(); // obj2 is the same object as obj
105/// }
106/// ```
107pub trait ObjectPool: Sized {
108 /// Returns a reference to the pool for this type of object. This allows
109 /// you to interact with the pool directly, if you need to.
110 ///
111 /// # Example
112 /// ```
113 /// use derivable_object_pool::prelude::*;
114 ///
115 /// #[derive(Default, ObjectPool)]
116 /// struct Test;
117 ///
118 /// fn main() {
119 /// let pool = Test::pool();
120 /// assert_eq!(pool.len(), 0);
121 /// let obj = Test::new();
122 /// drop(obj);
123 /// assert_eq!(pool.len(), 1);
124 /// pool.clear();
125 /// assert_eq!(pool.len(), 0);
126 /// }
127 /// ```
128 fn pool<'a>() -> &'a Pool<Self>;
129
130 /// Creates a new object. If there are any objects in the pool, one of them
131 /// will be returned. Otherwise, a new object will be created using the
132 /// generator function.
133 ///
134 /// # Example
135 /// ```
136 /// use derivable_object_pool::prelude::*;
137 ///
138 /// #[derive(Default, ObjectPool)]
139 /// struct Test(i32);
140 ///
141 /// fn main() {
142 /// let mut obj = Test::new();
143 /// assert_eq!(obj.0, 0);
144 /// obj.0 = 1;
145 /// drop(obj);
146 /// let obj = Test::new();
147 /// assert_eq!(obj.0, 1);
148 /// }
149 /// ```
150 #[must_use]
151 #[inline]
152 fn new() -> Reusable<Self> {
153 let mut pool = Self::pool().get_pool();
154 match pool.pop() {
155 Some(item) => Reusable::new(item),
156 None => Reusable::new((Self::pool().generator)()),
157 }
158 }
159}
160
161/// A pool of objects that can be reused. This is useful for objects that are
162/// expensive to create, but are used frequently. This struct can be created
163/// using the [`Pool::new`] function. However, it is highly recommended that
164/// you use the [`ObjectPool`] trait instead, as it is much easier to use.
165///
166///
167/// # Example
168///
169/// Example without deriving [`ObjectPool`]:
170///
171/// ```
172/// use derivable_object_pool::prelude::*;
173///
174/// #[derive(Default)]
175/// struct Test;
176///
177/// static POOL: Pool<Test> = Pool::new(Test::default);
178///
179/// impl ObjectPool for Test {
180/// fn pool<'a>() -> &'a Pool<Self> {
181/// &POOL
182/// }
183/// }
184///
185/// fn main() {
186/// let obj = Test::new();
187/// drop(obj); // obj is returned to the pool
188/// assert_eq!(POOL.len(), 1);
189/// }
190/// ```
191pub struct Pool<T> {
192 /// The pool of objects that can be reused. The pool uses a [`Mutex`] to
193 /// ensure that it is thread-safe.
194 pool: Mutex<Vec<T>>,
195 /// The generator function that is used to create new objects.
196 generator: fn() -> T,
197}
198
199impl<T> Pool<T> {
200 /// Creates a new pool of objects. The pool will use the specified generator
201 /// function to create new objects.
202 #[must_use]
203 #[inline]
204 pub const fn new(generator: fn() -> T) -> Self {
205 Self {
206 pool: Mutex::new(Vec::new()),
207 generator,
208 }
209 }
210
211 /// Returns a locked reference to the pool. This is used internally by the
212 /// rest of the library, but it can also be used to interact with the pool
213 /// directly.
214 #[inline]
215 fn get_pool(&self) -> MutexGuard<'_, Vec<T>> {
216 self.pool.lock().unwrap()
217 }
218
219 /// Returns the number of objects in the pool.
220 #[inline]
221 pub fn len(&self) -> usize {
222 self.get_pool().len()
223 }
224
225 /// Returns `true` if the pool is empty.
226 #[inline]
227 pub fn is_empty(&self) -> bool {
228 self.get_pool().is_empty()
229 }
230
231 /// Inserts an object into the pool while taking ownership of it.
232 #[inline]
233 pub fn insert(&self, item: T) {
234 self.get_pool().push(item);
235 }
236
237 /// Removes all objects from the pool.
238 #[inline]
239 pub fn clear(&self) {
240 self.get_pool().clear();
241 }
242
243 /// Removes an object from the pool and returns the object while taking
244 /// ownership of it.
245 #[inline]
246 pub fn remove(&self) -> Option<T> {
247 self.get_pool().pop()
248 }
249}
250
251impl<T: ObjectPool> Pool<T> {
252 /// Removes an object from the pool and returns a resuable wrapper for it,
253 /// which will return the object to the pool when it is dropped.
254 #[inline]
255 pub fn remove_reusable(&self) -> Option<Reusable<T>> {
256 self.remove().map(Reusable::new)
257 }
258}
259
260/// A wrapper for an object that will return the object to the pool when it is
261/// dropped. This is useful for objects that are expensive to create, but are
262/// used frequently. This struct can be created using the
263/// [`Pool::remove_reusable`] function. However, it is highly recommended that
264/// you use the [`ObjectPool::new`] function instead, as it will reuse objects
265/// from the pool if possible.
266///
267/// The object implements [`Deref`] and [`DerefMut`] to allow you to access the
268/// object inside the wrapper. It also implements [`Borrow`] and [`BorrowMut`]
269/// to allow you to access the object inside the wrapper immutably or mutably.
270/// Finally, it implements [`AsRef`] and [`AsMut`] to allow you to access the
271/// object inside the wrapper immutably or mutably.
272///
273/// # Example
274///
275/// ```
276/// use derivable_object_pool::prelude::*;
277///
278/// #[derive(Default, ObjectPool)]
279/// struct Test(i32);
280///
281/// fn test(obj: &mut Test) {
282/// obj.0 += 1;
283/// }
284///
285/// fn main() {
286/// let mut obj = Test::new();
287/// assert_eq!(obj.0, 0);
288/// test(&mut obj);
289/// assert_eq!(obj.0, 1);
290/// }
291/// ```
292#[repr(transparent)]
293pub struct Reusable<T: ObjectPool> {
294 /// The wrapped object. This is a `ManuallyDrop` to ensure that the object
295 /// is not dropped when the wrapper is dropped.
296 item: ManuallyDrop<T>,
297}
298
299impl<T: ObjectPool> Reusable<T> {
300 /// Creates a new reusable wrapper for the specified object.
301 #[inline]
302 const fn new(item: T) -> Self {
303 Self {
304 item: ManuallyDrop::new(item),
305 }
306 }
307
308 /// Returns the owned object inside the wrapper. This will return the object
309 /// without returning it to the pool. This is useful if you want to take
310 /// ownership of the object.
311 pub fn into_inner(mut self) -> T {
312 let ret = unsafe { ManuallyDrop::take(&mut self.item) };
313 forget(self);
314 ret
315 }
316}
317
318impl<T: ObjectPool> Borrow<T> for Reusable<T> {
319 #[inline]
320 fn borrow(&self) -> &T {
321 &self.item
322 }
323}
324
325impl<T: ObjectPool> BorrowMut<T> for Reusable<T> {
326 #[inline]
327 fn borrow_mut(&mut self) -> &mut T {
328 &mut self.item
329 }
330}
331
332impl<T: ObjectPool> AsRef<T> for Reusable<T> {
333 #[inline]
334 fn as_ref(&self) -> &T {
335 &self.item
336 }
337}
338
339impl<T: ObjectPool> AsMut<T> for Reusable<T> {
340 #[inline]
341 fn as_mut(&mut self) -> &mut T {
342 &mut self.item
343 }
344}
345
346impl<T: ObjectPool> Deref for Reusable<T> {
347 type Target = T;
348
349 #[inline]
350 fn deref(&self) -> &Self::Target {
351 &self.item
352 }
353}
354
355impl<T: ObjectPool> DerefMut for Reusable<T> {
356 #[inline]
357 fn deref_mut(&mut self) -> &mut Self::Target {
358 &mut self.item
359 }
360}
361
362impl<T: ObjectPool> Drop for Reusable<T> {
363 #[inline]
364 fn drop(&mut self) {
365 T::pool().insert(unsafe { ManuallyDrop::take(&mut self.item) });
366 }
367}
368
369impl<T: ObjectPool> From<T> for Reusable<T> {
370 #[inline]
371 fn from(item: T) -> Self {
372 Self::new(item)
373 }
374}
375
376/// This is the prelude for the `derivable-object-pool` crate. It contains the
377/// main traits and structs that you will need to use the crate. It is
378/// recommended that you import this prelude at the top of your file.
379pub mod prelude {
380 pub use crate::{ObjectPool, Pool, Reusable};
381}
382
383#[cfg(test)]
384#[allow(unused)]
385mod tests {
386 use super::*;
387
388 #[derive(Default, ObjectPool)]
389 struct Test {
390 a: i32,
391 b: f64,
392 c: bool,
393 d: Vec<usize>,
394 }
395
396 #[test]
397 fn new_objects() {
398 let obj = Test::new();
399 drop(obj);
400 assert_eq!(1, Test::pool().len());
401
402 let obj = Test::new();
403 assert_eq!(0, Test::pool().len());
404 let obj2 = Test::new();
405
406 drop(obj);
407 drop(obj2);
408
409 assert_eq!(2, Test::pool().len());
410 }
411
412 #[derive(ObjectPool)]
413 #[generator(Test2::new_item)]
414 /// This is a different attribute: a comment, tests the macro ignores it properly
415 struct Test2 {
416 a: i32,
417 b: f64,
418 c: bool,
419 d: Vec<usize>,
420 }
421
422 impl Test2 {
423 fn new_item() -> Self {
424 Self {
425 a: 0,
426 b: 0.0,
427 c: false,
428 d: Vec::new(),
429 }
430 }
431 }
432
433 #[test]
434 fn new_objects_with_generator() {
435 let obj = Test2::new();
436 drop(obj);
437 assert_eq!(1, Test2::pool().len());
438
439 let obj = Test2::new();
440 assert_eq!(0, Test2::pool().len());
441 let obj2 = Test2::new();
442
443 drop(obj);
444 drop(obj2);
445
446 assert_eq!(2, Test2::pool().len());
447 }
448}