1use crate::{Discriminant, IsoPoolable, Opaque, Poolable, RawPoolable};
43use crossbeam_queue::ArrayQueue;
44use fxhash::FxHashMap;
45#[cfg(feature = "serde")]
46use serde::{de::DeserializeOwned, Deserialize, Serialize};
47use std::{
48 any::{Any, TypeId},
49 borrow::Borrow,
50 cell::RefCell,
51 cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd},
52 collections::HashMap,
53 default::Default,
54 fmt::{self, Debug, Display},
55 hash::{Hash, Hasher},
56 mem::{self, ManuallyDrop},
57 ops::{Deref, DerefMut},
58 ptr,
59 sync::{Arc, LazyLock, Mutex, Weak},
60};
61
62pub mod arc;
63
64thread_local! {
65 static POOLS: RefCell<FxHashMap<Discriminant, Opaque>> =
66 RefCell::new(HashMap::default());
67}
68
69const DEFAULT_SIZES: (usize, usize) = (1024, 1024);
70
71static SIZES: LazyLock<Mutex<FxHashMap<Discriminant, (usize, usize)>>> =
72 LazyLock::new(|| Mutex::new(FxHashMap::default()));
73
74fn with_pool<T, R, F>(sizes: Option<(usize, usize)>, f: F) -> R
79where
80 T: IsoPoolable,
81 F: FnOnce(Option<&Pool<T>>) -> R,
82{
83 let mut f = Some(f);
84 let res = POOLS.try_with(|pools| match pools.try_borrow_mut() {
88 Err(_) => (f.take().unwrap())(None),
89 Ok(mut pools) => match T::DISCRIMINANT {
90 Some(d) => {
91 let pool = pools.entry(d).or_insert_with(|| {
92 let (size, cap) = sizes.unwrap_or_else(|| {
93 SIZES
94 .lock()
95 .unwrap()
96 .get(&d)
97 .map(|(s, c)| (*s, *c))
98 .unwrap_or(DEFAULT_SIZES)
99 });
100 let b = Box::new(Pool::<T>::new(size, cap));
101 let t = Box::into_raw(b) as *mut ();
102 let drop = Some(Box::new(|t: *mut ()| unsafe {
103 drop(Box::from_raw(t as *mut Pool<T>))
104 }) as Box<dyn FnOnce(*mut ())>);
105 Opaque { t, drop }
106 });
107 (f.take().unwrap())(unsafe { Some(&*(pool.t as *mut Pool<T>)) })
108 }
109 None => (f.take().unwrap())(None),
110 },
111 });
112 match res {
113 Err(_) => (f.take().unwrap())(None),
114 Ok(r) => r,
115 }
116}
117
118pub fn clear() {
122 POOLS.with_borrow_mut(|pools| pools.clear())
123}
124
125pub fn clear_type<T: IsoPoolable>() {
129 POOLS.with_borrow_mut(|pools| {
130 if let Some(d) = T::DISCRIMINANT {
131 pools.remove(&d);
132 }
133 })
134}
135
136pub fn set_size<T: IsoPoolable>(max_pool_size: usize, max_element_capacity: usize) {
142 if let Some(d) = T::DISCRIMINANT {
143 SIZES.lock().unwrap().insert(d, (max_pool_size, max_element_capacity));
144 }
145}
146
147pub fn get_size<T: IsoPoolable>() -> Option<(usize, usize)> {
151 T::DISCRIMINANT.map(|d| {
152 SIZES.lock().unwrap().get(&d).map(|(s, c)| (*s, *c)).unwrap_or(DEFAULT_SIZES)
153 })
154}
155
156fn take_inner<T: IsoPoolable>(sizes: Option<(usize, usize)>) -> GPooled<T> {
157 with_pool(sizes, |pool| {
158 pool.map(|p| p.take()).unwrap_or_else(|| GPooled::orphan(T::empty()))
159 })
160}
161
162pub fn take<T: IsoPoolable>() -> GPooled<T> {
167 take_inner(None)
168}
169
170pub fn take_sz<T: IsoPoolable>(max: usize, max_elements: usize) -> GPooled<T> {
176 take_inner(Some((max, max_elements)))
177}
178
179pub fn pool<T: IsoPoolable>() -> Option<Pool<T>> {
186 with_pool(None, |pool| pool.cloned())
187}
188
189pub fn pool_sz<T: IsoPoolable>(max: usize, max_elements: usize) -> Option<Pool<T>> {
197 with_pool(Some((max, max_elements)), |pool| pool.cloned())
198}
199
200thread_local! {
201 static ANY_POOLS: RefCell<FxHashMap<TypeId, Box<dyn Any>>> =
202 RefCell::new(HashMap::default());
203}
204
205pub fn pool_any<T: Any + Poolable>(size: usize, max: usize) -> Pool<T> {
213 ANY_POOLS.with_borrow_mut(|pools| {
214 pools
215 .entry(TypeId::of::<T>())
216 .or_insert_with(|| Box::new(Pool::<T>::new(size, max)))
217 .downcast_ref::<Pool<T>>()
218 .unwrap()
219 .clone()
220 })
221}
222
223pub fn take_any<T: Any + Poolable>(size: usize, max: usize) -> GPooled<T> {
229 ANY_POOLS.with_borrow_mut(|pools| {
230 pools
231 .entry(TypeId::of::<T>())
232 .or_insert_with(|| Box::new(Pool::<T>::new(size, max)))
233 .downcast_ref::<Pool<T>>()
234 .unwrap()
235 .take()
236 })
237}
238
239#[derive(Clone)]
282pub struct GPooled<T: Poolable> {
283 pool: ManuallyDrop<WeakPool<Self>>,
284 object: ManuallyDrop<T>,
285}
286
287impl<T: Poolable + Debug> fmt::Debug for GPooled<T> {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 write!(f, "{:?}", &self.object)
290 }
291}
292
293impl<T: Poolable + Display> fmt::Display for GPooled<T> {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 write!(f, "{}", &*self.object)
296 }
297}
298
299impl<T: IsoPoolable> Default for GPooled<T> {
300 fn default() -> Self {
301 take()
302 }
303}
304
305impl<T: IsoPoolable> GPooled<T> {
306 pub fn take() -> Self {
307 take()
308 }
309
310 pub fn take_sz(max: usize, max_elements: usize) -> Self {
311 take_sz(max, max_elements)
312 }
313}
314
315impl<T: IsoPoolable + Extend<E>, E> Extend<E> for GPooled<T> {
316 fn extend<I: IntoIterator<Item = E>>(&mut self, iter: I) {
317 self.object.extend(iter)
318 }
319}
320
321unsafe impl<T: Poolable> RawPoolable for GPooled<T> {
322 fn empty(pool: WeakPool<Self>) -> Self {
323 Self {
324 pool: ManuallyDrop::new(pool),
325 object: ManuallyDrop::new(Poolable::empty()),
326 }
327 }
328
329 fn reset(&mut self) {
330 Poolable::reset(&mut *self.object)
331 }
332
333 fn capacity(&self) -> usize {
334 Poolable::capacity(&*self.object)
335 }
336
337 fn really_drop(self) {
338 drop(self.detach())
339 }
340}
341
342impl<T: Poolable> Borrow<T> for GPooled<T> {
343 fn borrow(&self) -> &T {
344 &self.object
345 }
346}
347
348impl Borrow<str> for GPooled<String> {
349 fn borrow(&self) -> &str {
350 &self.object
351 }
352}
353
354impl<T: Poolable + PartialEq> PartialEq for GPooled<T> {
355 fn eq(&self, other: &GPooled<T>) -> bool {
356 self.object.eq(&other.object)
357 }
358}
359
360impl<T: Poolable + Eq> Eq for GPooled<T> {}
361
362impl<T: Poolable + PartialOrd> PartialOrd for GPooled<T> {
363 fn partial_cmp(&self, other: &GPooled<T>) -> Option<Ordering> {
364 self.object.partial_cmp(&other.object)
365 }
366}
367
368impl<T: Poolable + Ord> Ord for GPooled<T> {
369 fn cmp(&self, other: &GPooled<T>) -> Ordering {
370 self.object.cmp(&other.object)
371 }
372}
373
374impl<T: Poolable + Hash> Hash for GPooled<T> {
375 fn hash<H>(&self, state: &mut H)
376 where
377 H: Hasher,
378 {
379 Hash::hash(&self.object, state)
380 }
381}
382
383impl<T: Poolable> GPooled<T> {
384 pub fn orphan(t: T) -> Self {
388 Self { pool: ManuallyDrop::new(WeakPool::new()), object: ManuallyDrop::new(t) }
389 }
390
391 pub fn assign(&mut self, pool: &Pool<T>) {
396 let old = mem::replace(&mut self.pool, ManuallyDrop::new(pool.downgrade()));
397 drop(ManuallyDrop::into_inner(old))
398 }
399
400 pub fn detach(self) -> T {
404 let mut t = ManuallyDrop::new(self);
405 unsafe {
406 ManuallyDrop::drop(&mut t.pool);
407 ManuallyDrop::take(&mut t.object)
408 }
409 }
410}
411
412impl<T: Poolable> AsRef<T> for GPooled<T> {
413 fn as_ref(&self) -> &T {
414 &self.object
415 }
416}
417
418impl<T: Poolable> Deref for GPooled<T> {
419 type Target = T;
420
421 fn deref(&self) -> &T {
422 &self.object
423 }
424}
425
426impl<T: Poolable> DerefMut for GPooled<T> {
427 fn deref_mut(&mut self) -> &mut T {
428 &mut self.object
429 }
430}
431
432impl<T: Poolable> Drop for GPooled<T> {
433 fn drop(&mut self) {
434 if self.really_dropped() {
435 match self.pool.upgrade() {
436 Some(pool) => pool.insert(unsafe { ptr::read(self) }),
437 None => unsafe {
438 ManuallyDrop::drop(&mut self.pool);
439 ManuallyDrop::drop(&mut self.object);
440 },
441 }
442 }
443 }
444}
445
446#[cfg(feature = "serde")]
447impl<T: Poolable + Serialize> Serialize for GPooled<T> {
448 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
449 where
450 S: serde::Serializer,
451 {
452 self.object.serialize(serializer)
453 }
454}
455
456#[cfg(feature = "serde")]
457impl<'de, T: Poolable + DeserializeOwned + 'static> Deserialize<'de> for GPooled<T> {
458 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
459 where
460 D: serde::Deserializer<'de>,
461 {
462 let mut t = take_any::<T>(1024, 1024);
463 Self::deserialize_in_place(deserializer, &mut t)?;
464 Ok(t)
465 }
466
467 fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
468 where
469 D: serde::Deserializer<'de>,
470 {
471 <T as Deserialize>::deserialize_in_place(deserializer, &mut place.object)
472 }
473}
474
475#[derive(Debug)]
476struct PoolInner<T: RawPoolable> {
477 max_elt_capacity: usize,
478 pool: ArrayQueue<T>,
479}
480
481impl<T: RawPoolable> Drop for PoolInner<T> {
482 fn drop(&mut self) {
483 while let Some(t) = self.pool.pop() {
484 RawPoolable::really_drop(t)
485 }
486 }
487}
488
489pub struct WeakPool<T: RawPoolable>(Weak<PoolInner<T>>);
491
492impl<T: RawPoolable> Debug for WeakPool<T> {
493 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494 write!(f, "<weak pool>")
495 }
496}
497
498impl<T: RawPoolable> Clone for WeakPool<T> {
499 fn clone(&self) -> Self {
500 Self(Weak::clone(&self.0))
501 }
502}
503
504impl<T: RawPoolable> WeakPool<T> {
505 pub fn new() -> Self {
506 WeakPool(Weak::new())
507 }
508
509 pub fn upgrade(&self) -> Option<RawPool<T>> {
510 self.0.upgrade().map(RawPool)
511 }
512}
513
514pub type Pool<T> = RawPool<GPooled<T>>;
516
517#[derive(Debug)]
527pub struct RawPool<T: RawPoolable>(Arc<PoolInner<T>>);
528
529impl<T: RawPoolable> Clone for RawPool<T> {
530 fn clone(&self) -> Self {
531 Self(Arc::clone(&self.0))
532 }
533}
534
535impl<T: RawPoolable> RawPool<T> {
536 pub fn downgrade(&self) -> WeakPool<T> {
537 WeakPool(Arc::downgrade(&self.0))
538 }
539
540 pub fn new(max_capacity: usize, max_elt_capacity: usize) -> RawPool<T> {
545 RawPool(Arc::new(PoolInner {
546 pool: ArrayQueue::new(max_capacity),
547 max_elt_capacity,
548 }))
549 }
550
551 pub fn try_take(&self) -> Option<T> {
555 self.0.pool.pop()
556 }
557
558 pub fn take(&self) -> T {
562 self.0.pool.pop().unwrap_or_else(|| RawPoolable::empty(self.downgrade()))
563 }
564
565 pub fn insert(&self, mut t: T) {
570 let cap = t.capacity();
571 if cap > 0 && cap <= self.0.max_elt_capacity {
572 t.reset();
573 if let Err(t) = self.0.pool.push(t) {
574 RawPoolable::really_drop(t)
575 }
576 } else {
577 RawPoolable::really_drop(t)
578 }
579 }
580
581 pub fn prune(&self) {
587 let len = self.0.pool.len();
588 let ten_percent = std::cmp::max(1, self.0.pool.capacity() / 10);
589 let one_percent = std::cmp::max(1, ten_percent / 10);
590 if len > ten_percent {
591 for _ in 0..ten_percent {
592 if let Some(v) = self.0.pool.pop() {
593 RawPoolable::really_drop(v)
594 }
595 }
596 } else if len > one_percent {
597 for _ in 0..one_percent {
598 if let Some(v) = self.0.pool.pop() {
599 RawPoolable::really_drop(v)
600 }
601 }
602 } else if len > 0 {
603 if let Some(v) = self.0.pool.pop() {
604 RawPoolable::really_drop(v)
605 }
606 }
607 }
608}