lockfree_object_pool/
spin_lock_object_pool.rs

1use crate::{
2    spin_lock::SpinLock, spin_lock_owned_reusable::SpinLockOwnedReusable,
3    spin_lock_reusable::SpinLockReusable,
4};
5use std::mem::ManuallyDrop;
6use std::sync::Arc;
7
8/// ObjectPool use a spin lock over vector to secure multithread access to pull.
9///
10/// The spin lock works like [`std::sync::Mutex`] but
11/// * use [`std::sync::atomic::AtomicBool`] for synchro
12/// * active waiting
13///
14/// cf [wikipedia](https://en.wikipedia.org/wiki/Spinlock) for more information.
15///
16/// # Example
17/// ```rust
18///  use lockfree_object_pool::SpinLockObjectPool;
19///
20///  let pool = SpinLockObjectPool::<u32>::new(
21///    ||  Default::default(),
22///    |v| {
23///      *v = 0;
24///    }
25///  );
26///  let mut item = pool.pull();
27///
28///  *item = 5;
29///  let work = *item * 5;
30/// ```
31pub struct SpinLockObjectPool<T> {
32    objects: SpinLock<Vec<T>>,
33    reset: Box<dyn Fn(&mut T) + Send + Sync>,
34    init: Box<dyn Fn() -> T + Send + Sync>,
35}
36
37impl<T> SpinLockObjectPool<T> {
38    ///
39    /// Create an new [`SpinLockObjectPool`]
40    ///
41    /// # Arguments
42    /// * `init`  closure to create new item
43    /// * `reset` closure to reset item before reusage
44    ///
45    /// # Example
46    /// ```rust
47    ///  use lockfree_object_pool::SpinLockObjectPool;
48    ///
49    ///  let pool = SpinLockObjectPool::<u32>::new(
50    ///    ||  Default::default(),
51    ///    |v| {
52    ///      *v = 0;
53    ///    }
54    ///  );
55    /// ```
56    #[inline]
57    pub fn new<R, I>(init: I, reset: R) -> Self
58    where
59        R: Fn(&mut T) + Send + Sync + 'static,
60        I: Fn() -> T + Send + Sync + 'static,
61    {
62        Self {
63            objects: SpinLock::new(Vec::new()),
64            reset: Box::new(reset),
65            init: Box::new(init),
66        }
67    }
68
69    ///
70    /// Create a new element. When the element is dropped, it returns in the pull.
71    ///
72    /// # Example
73    /// ```rust
74    ///  use lockfree_object_pool::SpinLockObjectPool;
75    ///
76    ///  let pool = SpinLockObjectPool::<u32>::new(
77    ///    ||  Default::default(),
78    ///    |v| {
79    ///      *v = 0;
80    ///    }
81    ///  );
82    ///  let mut item = pool.pull();
83    /// ```
84    #[inline]
85    pub fn pull(&self) -> SpinLockReusable<T> {
86        SpinLockReusable::new(
87            self,
88            ManuallyDrop::new(self.objects.lock().pop().unwrap_or_else(&self.init)),
89        )
90    }
91
92    ///
93    /// Create a new element. When the element is dropped, it returns in the pull.
94    ///
95    /// # Example
96    /// ```rust
97    ///  use lockfree_object_pool::SpinLockObjectPool;
98    ///  use std::sync::Arc;
99    ///
100    ///  let pool = Arc::new(SpinLockObjectPool::<u32>::new(
101    ///    ||  Default::default(),
102    ///    |v| {
103    ///      *v = 0;
104    ///    }
105    ///  ));
106    ///  let mut item = pool.pull_owned();
107    /// ```
108    #[inline]
109    pub fn pull_owned(self: &Arc<Self>) -> SpinLockOwnedReusable<T> {
110        SpinLockOwnedReusable::new(
111            self.clone(),
112            ManuallyDrop::new(self.objects.lock().pop().unwrap_or_else(&self.init)),
113        )
114    }
115
116    #[inline]
117    pub(crate) fn attach(&self, mut data: T) {
118        (self.reset)(&mut data);
119        self.objects.lock().push(data);
120    }
121}