object_pool/
lib.rs

1//! A thread-safe object pool with automatic return and attach/detach semantics
2//!
3//! The goal of an object pool is to reuse expensive to allocate objects or frequently allocated objects
4//!
5//! # Examples
6//!
7//! ## Creating a Pool
8//!
9//! The general pool creation looks like this
10//! ```
11//! # use object_pool::Pool;
12//! # type T = Vec<u32>;
13//! # const capacity: usize = 5;
14//!  let pool: Pool<T> = Pool::new(capacity, || T::new());
15//! ```
16//! Example pool with 32 `Vec<u8>` with capacity of 4096
17//! ```
18//! # use object_pool::Pool;
19//!  let pool: Pool<Vec<u8>> = Pool::new(32, || Vec::with_capacity(4096));
20//! ```
21//!
22//! ## Using a Pool
23//!
24//! Basic usage for pulling from the pool
25//! ```
26//! # use object_pool::Pool;
27//! # use std::io::Read;
28//! # let mut some_file = std::io::empty();
29//! let pool: Pool<Vec<u8>> = Pool::new(32, || Vec::with_capacity(4096));
30//! let mut reusable_buff = pool.try_pull().unwrap(); // returns None when the pool is saturated
31//! reusable_buff.clear(); // clear the buff before using
32//! some_file.read_to_end(&mut reusable_buff).ok();
33//! // reusable_buff is automatically returned to the pool when it goes out of scope
34//! ```
35//! Pull from pool and `detach()`
36//! ```
37//! # use object_pool::Pool;
38//! let pool: Pool<Vec<u8>> = Pool::new(32, || Vec::with_capacity(4096));
39//! let mut reusable_buff = pool.try_pull().unwrap(); // returns None when the pool is saturated
40//! reusable_buff.clear(); // clear the buff before using
41//! let (pool, reusable_buff) = reusable_buff.detach();
42//! let mut s = String::from_utf8(reusable_buff).unwrap();
43//! s.push_str("hello, world!");
44//! pool.attach(s.into_bytes()); // reattach the buffer before reusable goes out of scope
45//! // reusable_buff is automatically returned to the pool when it goes out of scope
46//! ```
47//!
48//! ## Using Across Threads
49//!
50//! You simply wrap the pool in a [`std::sync::Arc`]
51//! ```
52//! # use std::sync::Arc;
53//! # use object_pool::Pool;
54//! # type T = Vec<u32>;
55//! # const cap: usize = 5;
56//! let pool: Arc<Pool<T>> = Arc::new(Pool::new(cap, || T::new()));
57//! ```
58//!
59//! With threads, you may also find it convenient to have owned reused objects
60//! ```
61//! # use std::sync::Arc;
62//! # use object_pool::Pool;
63//! # type T = Vec<u32>;
64//! # const cap: usize = 5;
65//! let pool: Arc<Pool<T>> = Arc::new(Pool::new(cap, || T::new()));
66//!
67//! let owned_reusable = pool.pull_owned(|| T::new());
68//! ```
69//!
70//! # Warning
71//!
72//! Objects in the pool are not automatically reset, they are returned but NOT reset
73//! You may want to call `object.reset()` or  `object.clear()`
74//! or any other equivalent for the object that you are using, after pulling from the pool
75//!
76//! [`std::sync::Arc`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html
77
78use parking_lot::Mutex;
79use std::iter::FromIterator;
80use std::mem::{forget, ManuallyDrop};
81use std::ops::{Deref, DerefMut};
82use std::sync::Arc;
83
84#[cfg(feature = "experimental")]
85pub mod experimental;
86
87pub type Stack<T> = Vec<T>;
88
89pub struct Pool<T> {
90    objects: Mutex<Stack<T>>,
91}
92
93impl<T> Pool<T> {
94    #[inline]
95    pub fn new<F>(cap: usize, init: F) -> Pool<T>
96    where
97        F: Fn() -> T,
98    {
99        Pool {
100            objects: Mutex::new((0..cap).into_iter().map(|_| init()).collect()),
101        }
102    }
103
104    #[inline]
105    pub fn from_vec(v: Vec<T>) -> Pool<T> {
106        Pool {
107            objects: Mutex::new(v),
108        }
109    }
110
111    #[inline]
112    pub fn len(&self) -> usize {
113        self.objects.lock().len()
114    }
115
116    #[inline]
117    pub fn is_empty(&self) -> bool {
118        self.objects.lock().is_empty()
119    }
120
121    #[inline]
122    pub fn try_pull(&self) -> Option<Reusable<T>> {
123        self.objects
124            .lock()
125            .pop()
126            .map(|data| Reusable::new(self, data))
127    }
128
129    #[inline]
130    pub fn pull<F: Fn() -> T>(&self, fallback: F) -> Reusable<T> {
131        self.try_pull()
132            .unwrap_or_else(|| Reusable::new(self, fallback()))
133    }
134
135    /// Like try_pull, but returns an owned reusable wrapper.
136    ///
137    /// `try_pull_owned()` is about 10% slower than `try_pull()`, but it may be
138    /// necessary in some cases where you cannot satisfy a `'lifetime` borrow
139    /// check on the pool.
140    #[inline]
141    pub fn try_pull_owned(self: &Arc<Self>) -> Option<ReusableOwned<T>> {
142        self.objects
143            .lock()
144            .pop()
145            .map(|data| ReusableOwned::new(self.clone(), data))
146    }
147
148    /// Like pull, but returns an owned reusable wrapper.
149    ///
150    /// `pull_owned()` is about 10% slower than `pull()`, but it may be necessary in
151    /// some cases where you cannot satisfy a `'lifetime` borrow check on the pool.
152    #[inline]
153    pub fn pull_owned<F: Fn() -> T>(self: &Arc<Self>, fallback: F) -> ReusableOwned<T> {
154        self.try_pull_owned()
155            .unwrap_or_else(|| ReusableOwned::new(self.clone(), fallback()))
156    }
157
158    #[inline]
159    pub fn attach(&self, t: T) {
160        self.objects.lock().push(t)
161    }
162}
163
164impl<T> FromIterator<T> for Pool<T> {
165    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
166        Self {
167            objects: Mutex::new(iter.into_iter().collect()),
168        }
169    }
170}
171
172pub struct Reusable<'a, T> {
173    pool: &'a Pool<T>,
174    data: ManuallyDrop<T>,
175}
176
177impl<'a, T> Reusable<'a, T> {
178    #[inline]
179    pub fn new(pool: &'a Pool<T>, t: T) -> Self {
180        Self {
181            pool,
182            data: ManuallyDrop::new(t),
183        }
184    }
185
186    #[inline]
187    pub fn detach(mut self) -> (&'a Pool<T>, T) {
188        let ret = unsafe { (self.pool, self.take()) };
189        forget(self);
190        ret
191    }
192
193    unsafe fn take(&mut self) -> T {
194        ManuallyDrop::take(&mut self.data)
195    }
196}
197
198impl<'a, T> Deref for Reusable<'a, T> {
199    type Target = T;
200
201    #[inline]
202    fn deref(&self) -> &Self::Target {
203        &self.data
204    }
205}
206
207impl<'a, T> DerefMut for Reusable<'a, T> {
208    #[inline]
209    fn deref_mut(&mut self) -> &mut Self::Target {
210        &mut self.data
211    }
212}
213
214impl<'a, T> Drop for Reusable<'a, T> {
215    #[inline]
216    fn drop(&mut self) {
217        unsafe { self.pool.attach(self.take()) }
218    }
219}
220
221pub struct ReusableOwned<T> {
222    pool: ManuallyDrop<Arc<Pool<T>>>,
223    data: ManuallyDrop<T>,
224}
225
226impl<T> ReusableOwned<T> {
227    #[inline]
228    pub fn new(pool: Arc<Pool<T>>, t: T) -> Self {
229        Self {
230            pool: ManuallyDrop::new(pool),
231            data: ManuallyDrop::new(t),
232        }
233    }
234
235    #[inline]
236    pub fn detach(mut self) -> (Arc<Pool<T>>, T) {
237        let ret = unsafe { self.take() };
238        forget(self);
239        ret
240    }
241
242    unsafe fn take(&mut self) -> (Arc<Pool<T>>, T) {
243        (
244            ManuallyDrop::take(&mut self.pool),
245            ManuallyDrop::take(&mut self.data),
246        )
247    }
248}
249
250impl<T> Deref for ReusableOwned<T> {
251    type Target = T;
252
253    #[inline]
254    fn deref(&self) -> &Self::Target {
255        &self.data
256    }
257}
258
259impl<T> DerefMut for ReusableOwned<T> {
260    #[inline]
261    fn deref_mut(&mut self) -> &mut Self::Target {
262        &mut self.data
263    }
264}
265
266impl<T> Drop for ReusableOwned<T> {
267    #[inline]
268    fn drop(&mut self) {
269        let (pool, data) = unsafe { self.take() };
270        pool.attach(data);
271    }
272}
273
274#[cfg(test)]
275mod tests {
276    use crate::{Pool, Reusable};
277    use std::mem::drop;
278
279    #[test]
280    fn detach() {
281        let pool = Pool::new(1, || Vec::new());
282        let (pool, mut object) = pool.try_pull().unwrap().detach();
283        object.push(1);
284        Reusable::new(&pool, object);
285        assert_eq!(pool.try_pull().unwrap()[0], 1);
286    }
287
288    #[test]
289    fn detach_then_attach() {
290        let pool = Pool::new(1, || Vec::new());
291        let (pool, mut object) = pool.try_pull().unwrap().detach();
292        object.push(1);
293        pool.attach(object);
294        assert_eq!(pool.try_pull().unwrap()[0], 1);
295    }
296
297    #[test]
298    fn pull() {
299        let pool = Pool::<Vec<u8>>::new(1, || Vec::new());
300
301        let object1 = pool.try_pull();
302        let object2 = pool.try_pull();
303        let object3 = pool.pull(|| Vec::new());
304
305        assert!(object1.is_some());
306        assert!(object2.is_none());
307        drop(object1);
308        drop(object2);
309        drop(object3);
310        assert_eq!(pool.len(), 2);
311    }
312
313    #[test]
314    fn e2e() {
315        let pool = Pool::new(10, || Vec::new());
316        let mut objects = Vec::new();
317
318        for i in 0..10 {
319            let mut object = pool.try_pull().unwrap();
320            object.push(i);
321            objects.push(object);
322        }
323
324        assert!(pool.try_pull().is_none());
325        drop(objects);
326        assert!(pool.try_pull().is_some());
327
328        for i in (10..0).rev() {
329            let mut object = pool.objects.lock().pop().unwrap();
330            assert_eq!(object.pop(), Some(i));
331        }
332    }
333}