1use std::sync::{Arc, Weak};
4
5use parking_lot::Mutex;
6
7#[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#[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}