use parking_lot::Mutex;
use std::iter::FromIterator;
use std::mem::{forget, ManuallyDrop};
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
#[cfg(feature = "experimental")]
pub mod experimental;
pub type Stack<T> = Vec<T>;
pub struct Pool<T> {
objects: Mutex<Stack<T>>,
}
impl<T> Pool<T> {
#[inline]
pub fn new<F>(cap: usize, init: F) -> Pool<T>
where
F: Fn() -> T,
{
Pool {
objects: Mutex::new((0..cap).into_iter().map(|_| init()).collect()),
}
}
#[inline]
pub fn from_vec(v: Vec<T>) -> Pool<T> {
Pool {
objects: Mutex::new(v),
}
}
#[inline]
pub fn len(&self) -> usize {
self.objects.lock().len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.objects.lock().is_empty()
}
#[inline]
pub fn try_pull(&self) -> Option<Reusable<T>> {
self.objects
.lock()
.pop()
.map(|data| Reusable::new(self, data))
}
#[inline]
pub fn pull<F: Fn() -> T>(&self, fallback: F) -> Reusable<T> {
self.try_pull()
.unwrap_or_else(|| Reusable::new(self, fallback()))
}
#[inline]
pub fn try_pull_owned(self: &Arc<Self>) -> Option<ReusableOwned<T>> {
self.objects
.lock()
.pop()
.map(|data| ReusableOwned::new(self.clone(), data))
}
#[inline]
pub fn pull_owned<F: Fn() -> T>(self: &Arc<Self>, fallback: F) -> ReusableOwned<T> {
self.try_pull_owned()
.unwrap_or_else(|| ReusableOwned::new(self.clone(), fallback()))
}
#[inline]
pub fn attach(&self, t: T) {
self.objects.lock().push(t)
}
}
impl<T> FromIterator<T> for Pool<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
Self {
objects: Mutex::new(iter.into_iter().collect()),
}
}
}
pub struct Reusable<'a, T> {
pool: &'a Pool<T>,
data: ManuallyDrop<T>,
}
impl<'a, T> Reusable<'a, T> {
#[inline]
pub fn new(pool: &'a Pool<T>, t: T) -> Self {
Self {
pool,
data: ManuallyDrop::new(t),
}
}
#[inline]
pub fn detach(mut self) -> (&'a Pool<T>, T) {
let ret = unsafe { (self.pool, self.take()) };
forget(self);
ret
}
unsafe fn take(&mut self) -> T {
ManuallyDrop::take(&mut self.data)
}
}
impl<'a, T> Deref for Reusable<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<'a, T> DerefMut for Reusable<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<'a, T> Drop for Reusable<'a, T> {
#[inline]
fn drop(&mut self) {
unsafe { self.pool.attach(self.take()) }
}
}
pub struct ReusableOwned<T> {
pool: ManuallyDrop<Arc<Pool<T>>>,
data: ManuallyDrop<T>,
}
impl<T> ReusableOwned<T> {
#[inline]
pub fn new(pool: Arc<Pool<T>>, t: T) -> Self {
Self {
pool: ManuallyDrop::new(pool),
data: ManuallyDrop::new(t),
}
}
#[inline]
pub fn detach(mut self) -> (Arc<Pool<T>>, T) {
let ret = unsafe { self.take() };
forget(self);
ret
}
unsafe fn take(&mut self) -> (Arc<Pool<T>>, T) {
(
ManuallyDrop::take(&mut self.pool),
ManuallyDrop::take(&mut self.data),
)
}
}
impl<T> Deref for ReusableOwned<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T> DerefMut for ReusableOwned<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<T> Drop for ReusableOwned<T> {
#[inline]
fn drop(&mut self) {
let (pool, data) = unsafe { self.take() };
pool.attach(data);
}
}
#[cfg(test)]
mod tests {
use crate::{Pool, Reusable};
use std::mem::drop;
#[test]
fn detach() {
let pool = Pool::new(1, || Vec::new());
let (pool, mut object) = pool.try_pull().unwrap().detach();
object.push(1);
Reusable::new(&pool, object);
assert_eq!(pool.try_pull().unwrap()[0], 1);
}
#[test]
fn detach_then_attach() {
let pool = Pool::new(1, || Vec::new());
let (pool, mut object) = pool.try_pull().unwrap().detach();
object.push(1);
pool.attach(object);
assert_eq!(pool.try_pull().unwrap()[0], 1);
}
#[test]
fn pull() {
let pool = Pool::<Vec<u8>>::new(1, || Vec::new());
let object1 = pool.try_pull();
let object2 = pool.try_pull();
let object3 = pool.pull(|| Vec::new());
assert!(object1.is_some());
assert!(object2.is_none());
drop(object1);
drop(object2);
drop(object3);
assert_eq!(pool.len(), 2);
}
#[test]
fn e2e() {
let pool = Pool::new(10, || Vec::new());
let mut objects = Vec::new();
for i in 0..10 {
let mut object = pool.try_pull().unwrap();
object.push(i);
objects.push(object);
}
assert!(pool.try_pull().is_none());
drop(objects);
assert!(pool.try_pull().is_some());
for i in (10..0).rev() {
let mut object = pool.objects.lock().pop().unwrap();
assert_eq!(object.pop(), Some(i));
}
}
}