bounded_pool/
lib.rs

1//! A generic but simple pool implemention.
2
3use std::sync::{Arc, Weak};
4
5use parking_lot::Mutex;
6
7/// A Vec based buffer pool.
8#[derive(Default)]
9pub struct Pool<T, F = fn() -> T> {
10    cached: Vec<T>,
11    limit: usize,
12
13    default: F,
14}
15pub type DynPool<T> = Pool<T, Box<dyn Fn() -> T + Send + Sync + 'static>>;
16
17impl<T, F> std::fmt::Debug for Pool<T, F> {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        write!(
20            f,
21            "Pool with limit {} and size {}",
22            self.limit,
23            self.cached.len()
24        )
25    }
26}
27
28impl<T, F> Pool<T, F>
29where
30    F: Fn() -> T,
31{
32    #[inline]
33    pub fn new(limit: usize, pre_allocate: usize, initialize: bool, default: F) -> Self {
34        let mut cached = Vec::with_capacity(pre_allocate);
35        if initialize {
36            for _ in 0..pre_allocate {
37                cached.push(default());
38            }
39        }
40
41        Self {
42            cached,
43            limit,
44            default,
45        }
46    }
47
48    pub fn pop(&mut self) -> T {
49        if let Some(val) = self.cached.pop() {
50            return val;
51        }
52        (self.default)()
53    }
54}
55
56impl<T, F> Pool<T, F> {
57    #[inline]
58    pub fn try_pop(&mut self) -> Option<T> {
59        self.cached.pop()
60    }
61
62    #[inline]
63    pub fn push(&mut self, val: T) {
64        if self.cached.len() < self.limit {
65            self.cached.push(val);
66        }
67    }
68
69    #[inline]
70    pub fn clear(&mut self) {
71        self.cached.clear();
72    }
73
74    #[inline]
75    pub fn len(&self) -> usize {
76        self.cached.len()
77    }
78
79    #[inline]
80    pub fn is_empty(&self) -> bool {
81        self.cached.is_empty()
82    }
83
84    #[inline]
85    pub fn limit(&self) -> usize {
86        self.limit
87    }
88}
89
90impl<T> Pool<T, fn() -> T>
91where
92    T: Default,
93{
94    #[inline]
95    pub fn new_with_default(limit: usize) -> Self {
96        Self::new(limit, 0, false, T::default)
97    }
98}
99
100/// Shared Pool.
101#[derive(Default)]
102pub struct SharedPool<T, F = fn() -> T>(Arc<Mutex<Pool<T, F>>>);
103pub type DynSharedPool<T> = SharedPool<T, Box<dyn Fn() -> T + Send + Sync + 'static>>;
104
105impl<T, F> std::fmt::Debug for SharedPool<T, F> {
106    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107        write!(
108            f,
109            "SharedPool with limit {} and size {}",
110            self.limit(),
111            self.len()
112        )
113    }
114}
115
116impl<T, F> Clone for SharedPool<T, F> {
117    fn clone(&self) -> Self {
118        Self(self.0.clone())
119    }
120}
121
122impl<T, F> SharedPool<T, F>
123where
124    F: Fn() -> T,
125{
126    #[inline]
127    pub fn new(limit: usize, pre_allocate: usize, initialize: bool, default: F) -> Self {
128        Self(Arc::new(Mutex::new(Pool::new(
129            limit,
130            pre_allocate,
131            initialize,
132            default,
133        ))))
134    }
135
136    #[inline]
137    pub fn pop(&self) -> T {
138        self.0.lock().pop()
139    }
140
141    #[inline]
142    pub fn pop_guarded(&self) -> Guard<T, F> {
143        Guard {
144            pool: Arc::downgrade(&self.0),
145            val: Some(self.pop()),
146        }
147    }
148}
149
150impl<T> SharedPool<T, fn() -> T>
151where
152    T: Default,
153{
154    #[inline]
155    pub fn new_with_default(limit: usize) -> Self {
156        Self(Arc::new(Mutex::new(Pool::new_with_default(limit))))
157    }
158}
159
160impl<T, F> SharedPool<T, F> {
161    #[inline]
162    pub fn try_pop(&self) -> Option<T> {
163        self.0.lock().try_pop()
164    }
165
166    #[inline]
167    pub fn try_pop_guarded(&self) -> Option<Guard<T, F>> {
168        self.0.lock().try_pop().map(|inner| Guard {
169            pool: Arc::downgrade(&self.0),
170            val: Some(inner),
171        })
172    }
173
174    #[inline]
175    pub fn push(&self, val: T) {
176        self.0.lock().push(val)
177    }
178
179    #[inline]
180    pub fn clear(&self) {
181        self.0.lock().clear();
182    }
183
184    #[inline]
185    pub fn len(&self) -> usize {
186        self.0.lock().len()
187    }
188
189    #[inline]
190    pub fn is_empty(&self) -> bool {
191        self.0.lock().is_empty()
192    }
193
194    #[inline]
195    pub fn limit(&self) -> usize {
196        self.0.lock().limit()
197    }
198}
199
200#[derive(Clone, Debug)]
201pub struct Guard<T, F = fn() -> T> {
202    pool: Weak<Mutex<Pool<T, F>>>,
203    val: Option<T>,
204}
205
206impl<T, F> Guard<T, F> {
207    #[inline]
208    pub fn into_inner(mut self) -> T {
209        self.val.take().unwrap()
210    }
211}
212
213impl<T, F> std::ops::Deref for Guard<T, F> {
214    type Target = T;
215
216    #[inline]
217    fn deref(&self) -> &Self::Target {
218        self.val.as_ref().unwrap()
219    }
220}
221
222impl<T, F> std::ops::DerefMut for Guard<T, F> {
223    #[inline]
224    fn deref_mut(&mut self) -> &mut Self::Target {
225        self.val.as_mut().unwrap()
226    }
227}
228
229impl<T, F> Drop for Guard<T, F> {
230    #[inline]
231    fn drop(&mut self) {
232        if let Some(pool) = self.pool.upgrade() {
233            if let Some(val) = self.val.take() {
234                SharedPool(pool).push(val);
235            }
236        }
237    }
238}
239
240#[cfg(test)]
241mod tests {
242    use super::*;
243
244    #[test]
245    fn default_pool() {
246        type BufferPool = SharedPool<()>;
247        let pool = BufferPool::new_with_default(10);
248        assert!(pool.is_empty());
249        let buf = pool.pop_guarded();
250        drop(buf);
251        assert_eq!(pool.len(), 1);
252    }
253
254    #[test]
255    fn dynamic_pool() {
256        type DynBufferPool = SharedPool<(), Box<dyn Fn()>>;
257        let pool = DynBufferPool::new(10, 0, false, Box::new(|| ()));
258        assert!(pool.is_empty());
259        pool.pop();
260        assert!(pool.is_empty());
261        pool.push(());
262        assert_eq!(pool.len(), 1);
263    }
264
265    #[test]
266    fn sized() {
267        type BufferPool = Pool<u8>;
268        let mut pool = BufferPool::new_with_default(3);
269        assert!(pool.is_empty());
270        for _ in 0..10 {
271            let element = pool.pop();
272            pool.push(element);
273        }
274        assert_eq!(pool.len(), 1);
275
276        for _ in 0..10 {
277            pool.push(0);
278        }
279        assert_eq!(pool.len(), 3);
280    }
281
282    #[test]
283    fn new_pool() {
284        type BufferPool = SharedPool<()>;
285        let _pool = BufferPool::new_with_default(10);
286        let _pool = BufferPool::new(10, 0, false, || ());
287
288        type DynBufferPool = Pool<u8, Box<dyn Fn() -> u8>>;
289        let number = 100;
290        let _pool = DynBufferPool::new(10, 0, false, Box::new(move || number));
291    }
292}