1#![doc = include_str!("../README.md")]
2
3use std::ops::{Deref, DerefMut};
4use std::sync::atomic::{AtomicUsize, Ordering};
5use std::sync::Arc;
6
7use tokio::sync::{mpsc, Mutex};
8
9#[cfg(test)]
10mod tests;
11
12pub struct Pool<T: PoolEntry> {
16 len: Arc<AtomicUsize>,
17 tx: mpsc::UnboundedSender<T>,
18 rx: Mutex<mpsc::UnboundedReceiver<T>>,
19}
20
21pub trait PoolEntry {
23 fn is_closed(&self) -> bool;
30}
31
32#[must_use = "if unused the PoolEntry will immediately reinserted"]
45pub struct PoolGuard<T: PoolEntry> {
46 inner: Option<T>,
47 back: mpsc::UnboundedSender<T>,
48 pool_len: Arc<AtomicUsize>,
49}
50
51unsafe impl<T: Send + PoolEntry> Send for PoolGuard<T> {}
52unsafe impl<T: Sync + PoolEntry> Sync for PoolGuard<T> {}
53
54impl<T: PoolEntry> Drop for PoolGuard<T> {
55 fn drop(&mut self) {
56 if let Some(inner) = self.inner.take() {
57 if inner.is_closed() {
58 self.pool_len.fetch_sub(1, Ordering::Relaxed);
59 } else if self.back.send(inner).is_err() {
60 }
63 }
64 }
65}
66
67impl<T: PoolEntry> Deref for PoolGuard<T> {
68 type Target = T;
69 fn deref(&self) -> &Self::Target {
70 match self.inner.as_ref() {
71 Some(inner) => inner,
72 None => unreachable!("PoolGuard can only be None after itself got dropped."),
73 }
74 }
75}
76
77impl<T: PoolEntry> DerefMut for PoolGuard<T> {
78 fn deref_mut(&mut self) -> &mut Self::Target {
79 match self.inner.as_mut() {
80 Some(inner) => inner,
81 None => unreachable!("PoolGuard can only be None after itself got dropped."),
82 }
83 }
84}
85
86impl<T: PoolEntry> Default for Pool<T> {
87 fn default() -> Self {
88 let (tx, rx) = mpsc::unbounded_channel();
89 Self {
90 len: Arc::new(AtomicUsize::new(0)),
91 tx,
92 rx: Mutex::new(rx),
93 }
94 }
95}
96
97impl<T: PoolEntry> Pool<T> {
98 pub async fn acquire(&self) -> Option<PoolGuard<T>> {
103 if self.is_empty() {
104 return None;
105 }
106
107 let mut rx = self.rx.lock().await;
108
109 let inner = match rx.recv().await {
110 Some(inner) => inner,
111 None => unreachable!("Channel is closed"),
112 };
113
114 Some(PoolGuard {
115 inner: Some(inner),
116 back: self.tx.clone(),
117 pool_len: self.len.clone(),
118 })
119 }
120}
121
122impl<T: PoolEntry> Pool<T> {
123 pub fn push(&self, inner: T) {
125 self.len.fetch_add(1, Ordering::Relaxed);
126 if self.tx.send(inner).is_err() {
127 unreachable!("Cannel is closed");
128 }
129 }
130
131 pub fn len(&self) -> usize {
133 self.len.load(Ordering::SeqCst)
134 }
135
136 pub fn is_empty(&self) -> bool {
138 self.len() == 0
139 }
140}