use alloc::{fmt, sync::Arc};
use core::{
hash::{Hash, Hasher},
mem::{forget, MaybeUninit},
ops::{Deref, DerefMut},
ptr,
};
use crossbeam_queue::ArrayQueue;
use crate::PoolAllocator;
#[derive(Debug)]
pub struct Pool<P: PoolAllocator<T>, T> {
allocator: P,
storage: ArrayQueue<T>,
}
unsafe impl<P: PoolAllocator<T>, T: Send> Send for Pool<P, T> {}
impl<P: PoolAllocator<T>, T> Pool<P, T> {
pub fn new_prefilled(pool_size: usize, allocator: P) -> Self {
let storage = ArrayQueue::new(pool_size);
for _ in 0..pool_size {
let _ = storage.push(allocator.allocate());
}
Pool { allocator, storage }
}
pub fn new(pool_size: usize, allocator: P) -> Self {
let storage = ArrayQueue::new(pool_size);
Pool { allocator, storage }
}
pub fn to_rc(self) -> Arc<Self> {
Arc::new(self)
}
pub fn try_get(&self) -> Option<RefGuard<'_, P, T>> {
self.storage.pop().map(|mut obj| {
self.allocator.reset(&mut obj);
RefGuard::new(obj, self)
})
}
pub fn get(&'_ self) -> RefGuard<'_, P, T> {
match self.storage.pop() {
Some(mut obj) => {
self.allocator.reset(&mut obj);
RefGuard::new(obj, self)
}
None => RefGuard::new(self.allocator.allocate(), self),
}
}
pub fn try_get_rc(self: Arc<Self>) -> Option<RcGuard<P, T>> {
self.storage.pop().map(|mut obj| {
self.allocator.reset(&mut obj);
RcGuard::new(obj, &self)
})
}
pub fn get_rc(self: Arc<Self>) -> RcGuard<P, T> {
match self.storage.pop() {
Some(mut obj) => {
self.allocator.reset(&mut obj);
RcGuard::new(obj, &self)
}
None => RcGuard::new(self.allocator.allocate(), &self),
}
}
pub fn len(&self) -> usize {
self.storage.len()
}
pub fn is_empty(&self) -> bool {
self.storage.is_empty()
}
pub fn capacity(&self) -> usize {
self.storage.capacity()
}
}
pub struct RefGuard<'a, P: PoolAllocator<T>, T> {
obj: MaybeUninit<T>,
pool: &'a Pool<P, T>,
}
impl<'a, P: PoolAllocator<T>, T> RefGuard<'a, P, T> {
fn new(obj: T, pool: &'a Pool<P, T>) -> Self {
RefGuard {
obj: MaybeUninit::new(obj),
pool,
}
}
pub fn into_inner(self) -> T {
let obj = unsafe { self.obj.as_ptr().read() };
forget(self);
obj
}
}
impl<'a, P: PoolAllocator<T>, T> Deref for RefGuard<'a, P, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { &*self.obj.as_ptr() }
}
}
impl<'a, P: PoolAllocator<T>, T> DerefMut for RefGuard<'a, P, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.obj.as_mut_ptr() }
}
}
impl<'a, P: PoolAllocator<T>, T> Drop for RefGuard<'a, P, T> {
fn drop(&mut self) {
if self.pool.allocator.is_valid(self.deref()) {
let _ = self
.pool
.storage
.push(unsafe { self.obj.as_mut_ptr().read() });
} else {
unsafe {
ptr::drop_in_place(self.obj.as_mut_ptr());
}
}
}
}
impl<'a, P: PoolAllocator<T>, T: Hash> Hash for RefGuard<'a, P, T> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<'a, P: PoolAllocator<T>, T: fmt::Display> fmt::Display for RefGuard<'a, P, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<'a, P: PoolAllocator<T>, T: fmt::Debug> fmt::Debug for RefGuard<'a, P, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<'a, P: PoolAllocator<T>, T> fmt::Pointer for RefGuard<'a, P, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&(&**self as *const T), f)
}
}
impl<'a, P: PoolAllocator<T>, T: PartialEq> PartialEq for RefGuard<'a, P, T> {
#[inline]
fn eq(&self, other: &RefGuard<'a, P, T>) -> bool {
self.deref().eq(other)
}
}
impl<'a, P: PoolAllocator<T>, T: Eq> Eq for RefGuard<'a, P, T> {}
impl<'a, P: PoolAllocator<T>, T: PartialOrd> PartialOrd for RefGuard<'a, P, T> {
#[inline]
fn partial_cmp(&self, other: &RefGuard<'a, P, T>) -> Option<core::cmp::Ordering> {
(**self).partial_cmp(&**other)
}
#[inline]
fn lt(&self, other: &RefGuard<'a, P, T>) -> bool {
**self < **other
}
#[inline]
fn le(&self, other: &RefGuard<'a, P, T>) -> bool {
**self <= **other
}
#[inline]
fn gt(&self, other: &RefGuard<'a, P, T>) -> bool {
**self > **other
}
#[inline]
fn ge(&self, other: &RefGuard<'a, P, T>) -> bool {
**self >= **other
}
}
impl<'a, P: PoolAllocator<T>, T: Ord> Ord for RefGuard<'a, P, T> {
#[inline]
fn cmp(&self, other: &RefGuard<'a, P, T>) -> core::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl<'a, P: PoolAllocator<T>, T> core::borrow::Borrow<T> for RefGuard<'a, P, T> {
#[inline(always)]
fn borrow(&self) -> &T {
self
}
}
impl<'a, P: PoolAllocator<T>, T> AsRef<T> for RefGuard<'a, P, T> {
#[inline(always)]
fn as_ref(&self) -> &T {
self
}
}
pub struct RcGuard<P: PoolAllocator<T>, T> {
obj: MaybeUninit<T>,
pool: Arc<Pool<P, T>>,
}
impl<P: PoolAllocator<T>, T> RcGuard<P, T> {
fn new(obj: T, pool: &Arc<Pool<P, T>>) -> Self {
Self {
obj: MaybeUninit::new(obj),
pool: pool.clone(),
}
}
pub fn into_inner(mut self) -> T {
let obj = unsafe { self.obj.as_ptr().read() };
unsafe { ptr::drop_in_place(&mut self.pool) }
forget(self);
obj
}
}
impl<P: PoolAllocator<T>, T> Deref for RcGuard<P, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.obj.as_ptr() }
}
}
impl<P: PoolAllocator<T>, T> DerefMut for RcGuard<P, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.obj.as_mut_ptr() }
}
}
impl<P: PoolAllocator<T>, T> Drop for RcGuard<P, T> {
fn drop(&mut self) {
if self.pool.allocator.is_valid(self.deref()) {
let _ = self
.pool
.storage
.push(unsafe { self.obj.as_mut_ptr().read() });
} else {
unsafe {
ptr::drop_in_place(self.obj.as_mut_ptr());
}
}
}
}
impl<P: PoolAllocator<T>, T: Hash> Hash for RcGuard<P, T> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<P: PoolAllocator<T>, T: fmt::Display> fmt::Display for RcGuard<P, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&**self, f)
}
}
impl<P: PoolAllocator<T>, T: fmt::Debug> fmt::Debug for RcGuard<P, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<P: PoolAllocator<T>, T> fmt::Pointer for RcGuard<P, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&(&**self as *const T), f)
}
}
impl<P: PoolAllocator<T>, T: PartialEq> PartialEq for RcGuard<P, T> {
#[inline]
fn eq(&self, other: &RcGuard<P, T>) -> bool {
self.deref().eq(other)
}
}
impl<P: PoolAllocator<T>, T: Eq> Eq for RcGuard<P, T> {}
impl<P: PoolAllocator<T>, T: PartialOrd> PartialOrd for RcGuard<P, T> {
#[inline]
fn partial_cmp(&self, other: &RcGuard<P, T>) -> Option<core::cmp::Ordering> {
(**self).partial_cmp(&**other)
}
#[inline]
fn lt(&self, other: &RcGuard<P, T>) -> bool {
**self < **other
}
#[inline]
fn le(&self, other: &RcGuard<P, T>) -> bool {
**self <= **other
}
#[inline]
fn gt(&self, other: &RcGuard<P, T>) -> bool {
**self > **other
}
#[inline]
fn ge(&self, other: &RcGuard<P, T>) -> bool {
**self >= **other
}
}
impl<P: PoolAllocator<T>, T: Ord> Ord for RcGuard<P, T> {
#[inline]
fn cmp(&self, other: &RcGuard<P, T>) -> core::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl<P: PoolAllocator<T>, T> core::borrow::Borrow<T> for RcGuard<P, T> {
#[inline(always)]
fn borrow(&self) -> &T {
self
}
}
impl<P: PoolAllocator<T>, T> AsRef<T> for RcGuard<P, T> {
#[inline(always)]
fn as_ref(&self) -> &T {
self
}
}