use crossbeam_queue::ArrayQueue;
use std::iter::Iterator;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use tokio::sync::Notify;
#[derive(Clone)]
pub struct Pool<T> {
inner: Arc<PoolInner<T>>,
}
struct PoolInner<T> {
queue: ArrayQueue<T>,
notify: Notify,
}
pub struct Guard<T> {
value: Option<T>,
inner: Arc<PoolInner<T>>,
}
impl<T> Pool<T> {
#[inline]
pub async fn acquire(&self) -> Guard<T> {
let inner = self.inner.clone();
loop {
if let Some(value) = inner.queue.pop() {
return Guard {
value: Some(value),
inner,
};
}
inner.notify.notified().await;
}
}
pub fn remaining_capacity(&self) -> usize {
self.inner.queue.len()
}
pub fn from_vec(vec: Vec<T>) -> Self {
let queue = ArrayQueue::new(vec.len());
for item in vec {
let _ = queue.push(item);
}
Self {
inner: Arc::new(PoolInner {
queue,
notify: Notify::new(),
}),
}
}
pub fn from_initializer<F>(capacity: usize, init: F) -> Self
where
F: Fn() -> T,
{
let queue = ArrayQueue::new(capacity);
for _ in 0..capacity {
let _ = queue.push(init());
}
Self {
inner: Arc::new(PoolInner {
queue,
notify: Notify::new(),
}),
}
}
#[allow(clippy::should_implement_trait)]
pub fn from_iter<I>(iterable: I) -> Self
where
I: IntoIterator<Item = T>,
{
Pool::from_vec(iterable.into_iter().collect())
}
}
impl<T: Default> Pool<T> {
pub fn from_default(capacity: usize) -> Self
where
T: Default,
{
Pool::from_initializer(capacity, T::default)
}
}
impl<T: Copy> Pool<T> {
pub fn from_copy(capacity: usize, value: T) -> Self
where
T: Copy,
{
Pool::from_initializer(capacity, move || value)
}
}
impl<T: Clone> Pool<T> {
pub fn from_clone(capacity: usize, value: &T) -> Self
where
T: Clone,
{
Pool::from_initializer(capacity, move || value.clone())
}
}
impl<T> Drop for Guard<T> {
#[inline]
fn drop(&mut self) {
if let Some(value) = self.value.take() {
let _ = self.inner.queue.push(value);
self.inner.notify.notify_one();
}
}
}
impl<T> Deref for Guard<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.value.as_ref().unwrap()
}
}
impl<T> DerefMut for Guard<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.value.as_mut().unwrap()
}
}
impl<T, I> From<I> for Pool<T>
where
T: Send + Sync + 'static,
I: IntoIterator<Item = T>,
{
fn from(iter: I) -> Self {
let vec: Vec<T> = iter.into_iter().collect();
Self::from_vec(vec)
}
}