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}