use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt::{Debug, Display, Error, Formatter};
use std::hash::{Hash, Hasher};
use std::mem::MaybeUninit;
use std::ops::Deref;
use std::pin::Pin;
use crate::counter::Counter;
use crate::pointer::Pointer;
use crate::sync_type::PoolSyncType;
use crate::{Pool, PoolClone, PoolDefault};
unsafe fn assume_init<A>(maybe_boxed: Box<MaybeUninit<A>>) -> Box<A> {
Box::from_raw(Box::into_raw(maybe_boxed).cast())
}
unsafe fn data_ptr<A, S>(this: &mut MaybeUninit<RefBox<A, S>>) -> &mut MaybeUninit<A>
where
S: PoolSyncType<A>,
{
(*this.as_mut_ptr())
.value_as_mut_ptr()
.cast::<MaybeUninit<A>>()
.as_mut()
.unwrap()
}
pub struct PoolRef<A, S>
where
S: PoolSyncType<A>,
{
pub(crate) handle: S::ElementPointer,
}
impl<A, S> PoolRef<A, S>
where
S: PoolSyncType<A>,
{
pub fn default(pool: &Pool<A, S>) -> Self
where
A: PoolDefault,
{
let mut handle = pool.pop();
unsafe {
PoolDefault::default_uninit(data_ptr(&mut handle));
assume_init(handle)
}
.into_ref()
}
pub fn new(pool: &Pool<A, S>, value: A) -> Self {
let mut handle = pool.pop();
unsafe {
data_ptr(&mut handle).as_mut_ptr().write(value);
assume_init(handle)
}
.into_ref()
}
pub fn clone_from(pool: &Pool<A, S>, value: &A) -> Self
where
A: PoolClone,
{
let mut handle = pool.pop();
unsafe {
value.clone_uninit(data_ptr(&mut handle));
assume_init(handle)
}
.into_ref()
}
pub fn pin_default(pool: &Pool<A, S>) -> Pin<Self>
where
A: PoolDefault,
{
unsafe { Pin::new_unchecked(Self::default(pool)) }
}
pub fn pin(pool: &Pool<A, S>, value: A) -> Pin<Self> {
unsafe { Pin::new_unchecked(Self::new(pool, value)) }
}
pub fn cloned(&self, pool: &Pool<A, S>) -> Self
where
A: PoolClone,
{
let mut handle = pool.pop();
unsafe {
self.clone_uninit(data_ptr(&mut handle));
assume_init(handle)
}
.into_ref()
}
pub fn make_mut<'a>(pool: &Pool<A, S>, this: &'a mut Self) -> &'a mut A
where
A: PoolClone,
{
if this.box_ref().is_shared() {
let mut new_handle = pool.pop();
let mut new_handle = unsafe {
this.clone_uninit(data_ptr(&mut new_handle));
assume_init(new_handle)
};
new_handle.inc();
this.box_ref_mut().dec();
this.handle = S::ElementPointer::wrap(Box::into_raw(new_handle));
}
this.box_ref_mut().value_as_mut()
}
pub fn get_mut(this: &mut Self) -> Option<&mut A> {
let handle = this.box_ref_mut();
if handle.is_shared() {
None
} else {
Some(handle.value_as_mut())
}
}
pub fn try_unwrap(mut this: Self) -> Result<A, Self> {
if this.box_ref().is_shared() {
Err(this)
} else {
let handle = unsafe { Box::from_raw(this.handle.get_ptr()) };
this.handle = S::ElementPointer::wrap(std::ptr::null_mut());
Ok(handle.value)
}
}
pub fn unwrap_or_clone(mut this: Self) -> A
where
A: PoolClone,
{
if this.box_ref().is_shared() {
this.deref().clone()
} else {
let handle = unsafe { Box::from_raw(this.handle.get_ptr()) };
this.handle = S::ElementPointer::wrap(std::ptr::null_mut());
handle.value
}
}
pub fn ptr_eq(left: &Self, right: &Self) -> bool {
std::ptr::eq(left.handle.get_ptr(), right.handle.get_ptr())
}
pub fn strong_count(this: &Self) -> usize {
this.box_ref().count.count()
}
fn box_ref(&self) -> &RefBox<A, S> {
unsafe { &*self.handle.get_ptr() }
}
fn box_ref_mut(&mut self) -> &mut RefBox<A, S> {
unsafe { &mut *self.handle.get_ptr() }
}
}
impl<A, S> Drop for PoolRef<A, S>
where
S: PoolSyncType<A>,
{
fn drop(&mut self) {
if self.handle.get_ptr().is_null() {
return;
}
if self.box_ref_mut().dec() != 1 {
return;
}
let handle = unsafe { Box::from_raw(self.handle.get_ptr()) };
handle.return_to_pool();
}
}
impl<A, S> Clone for PoolRef<A, S>
where
S: PoolSyncType<A>,
{
fn clone(&self) -> Self {
let mut new_ref: Self = PoolRef {
handle: S::ElementPointer::wrap(self.handle.get_ptr()),
};
new_ref.box_ref_mut().inc();
new_ref
}
}
impl<A, S> Deref for PoolRef<A, S>
where
S: PoolSyncType<A>,
{
type Target = A;
fn deref(&self) -> &Self::Target {
self.box_ref().value_as_ref()
}
}
impl<A, S> AsRef<A> for PoolRef<A, S>
where
S: PoolSyncType<A>,
{
fn as_ref(&self) -> &A {
self.deref()
}
}
impl<A, S> Borrow<A> for PoolRef<A, S>
where
S: PoolSyncType<A>,
{
fn borrow(&self) -> &A {
self.deref()
}
}
impl<A, S> PartialEq for PoolRef<A, S>
where
A: PartialEq,
S: PoolSyncType<A>,
{
fn eq(&self, other: &Self) -> bool {
(**self) == (**other)
}
}
impl<A, S> Eq for PoolRef<A, S>
where
A: Eq,
S: PoolSyncType<A>,
{
}
impl<A, S> PartialOrd for PoolRef<A, S>
where
A: PartialOrd,
S: PoolSyncType<A>,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
}
impl<A, S> Ord for PoolRef<A, S>
where
A: Ord,
S: PoolSyncType<A>,
{
fn cmp(&self, other: &Self) -> Ordering {
(**self).cmp(&**other)
}
}
impl<A, S> Hash for PoolRef<A, S>
where
A: Hash,
S: PoolSyncType<A>,
{
fn hash<H: Hasher>(&self, hasher: &mut H) {
(**self).hash(hasher)
}
}
impl<A, S> Display for PoolRef<A, S>
where
A: Display,
S: PoolSyncType<A>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
(**self).fmt(f)
}
}
impl<A, S> Debug for PoolRef<A, S>
where
A: Debug,
S: PoolSyncType<A>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
(**self).fmt(f)
}
}
impl<A, S> std::fmt::Pointer for PoolRef<A, S>
where
S: PoolSyncType<A>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
std::fmt::Pointer::fmt(&(&**self as *const A), f)
}
}
#[doc(hidden)]
pub struct RefBox<A, S>
where
S: PoolSyncType<A>,
{
pub(crate) count: S::Counter,
pub(crate) pool: Pool<A, S>,
pub(crate) value: A,
}
impl<A, S: PoolSyncType<A>> RefBox<A, S> {
fn into_ref(mut self: Box<Self>) -> PoolRef<A, S> {
let ref_handle = self.new_ref();
Box::leak(self);
ref_handle
}
fn new_ref(&mut self) -> PoolRef<A, S> {
self.inc();
PoolRef {
handle: S::ElementPointer::wrap(self),
}
}
fn return_to_pool(self: Box<Self>) {
if !self.pool.is_full() {
let ptr = Box::into_raw(self);
unsafe {
((*ptr).pool).push(S::ElementPointer::wrap(ptr));
ptr.drop_in_place();
};
}
}
fn value_as_ref(&self) -> &A {
&self.value
}
fn value_as_mut(&mut self) -> &mut A {
&mut self.value
}
unsafe fn value_as_mut_ptr(&mut self) -> *mut A {
&mut self.value
}
#[inline(always)]
fn inc(&mut self) {
self.count.inc()
}
#[inline(always)]
fn dec(&mut self) -> usize {
self.count.dec()
}
#[inline(always)]
fn is_shared(&self) -> bool {
self.count.count() > 1
}
}