use crate::{
tcell::TCell,
tx::{Error, Ordering, Read, SetError, Write, _TValue},
};
use std::{mem, ptr};
#[repr(transparent)]
struct Ptr<T>(*const T);
unsafe impl<T: Send + Sync> Send for Ptr<T> {}
unsafe impl<T: Send + Sync> Sync for Ptr<T> {}
impl<T> Clone for Ptr<T> {
#[inline]
fn clone(&self) -> Self {
Ptr(self.0)
}
}
impl<T> Copy for Ptr<T> {}
impl<T> From<*mut T> for Ptr<T> {
#[inline]
fn from(ptr: *mut T) -> Self {
Ptr(ptr)
}
}
impl<T> From<*const T> for Ptr<T> {
#[inline]
fn from(ptr: *const T) -> Self {
Ptr(ptr)
}
}
impl<T> Into<*mut T> for Ptr<T> {
#[inline]
fn into(self) -> *mut T {
self.0 as _
}
}
impl<T> Into<*const T> for Ptr<T> {
#[inline]
fn into(self) -> *const T {
self.0 as _
}
}
pub struct TPtr<T> {
ptr: TCell<Ptr<T>>,
}
impl<T> Default for TPtr<T> {
#[inline]
fn default() -> Self {
TPtr::null()
}
}
impl<T> TPtr<T> {
#[inline]
pub const fn new(ptr: *const T) -> Self {
TPtr {
ptr: TCell::new(Ptr(ptr)),
}
}
#[inline]
pub const fn null() -> Self {
Self::new(ptr::null_mut())
}
#[inline]
pub fn into_inner(self) -> *const T {
self.ptr.into_inner().into()
}
#[inline]
pub fn borrow_mut(&mut self) -> &mut *const T {
unsafe { &mut *(self.ptr.borrow_mut() as *mut Ptr<T> as *mut *const T) }
}
#[inline]
pub fn as_ptr<'tcell>(
&'tcell self,
tx: &impl Read<'tcell>,
ordering: Ordering,
) -> Result<*const T, Error> {
self.ptr.get(tx, ordering).map(Into::into)
}
}
impl<T: Send + Sync + 'static> TPtr<T> {
#[inline]
pub fn publish_box<'tcell>(
&'tcell self,
tx: &mut impl Write<'tcell>,
value: Box<T>,
) -> Result<(), SetError<Box<T>>> {
self.publish(
tx,
Publisher::new(Box::into_raw(value), |ptr| unsafe {
drop(Box::from_raw(ptr))
}),
)
.map_err(|err| {
err.map(|publisher| {
let ptr = publisher.ptr;
mem::forget(publisher);
unsafe { Box::from_raw(ptr) }
})
})
}
#[inline]
pub fn publish<'tcell, F: FnOnce(*mut T) + Copy + 'static>(
&'tcell self,
tx: &mut impl Write<'tcell>,
publisher: Publisher<T, F>,
) -> Result<(), SetError<Publisher<T, F>>> {
let destructor = publisher.destructor;
self.ptr.publish(tx, publisher).map_err(|err| {
err.map(move |ptr| Publisher {
ptr: ptr.into(),
destructor,
})
})
}
#[inline]
pub unsafe fn privatize_as_box<'tcell>(tx: &mut impl Write<'tcell>, value: *const T) {
let ptr = Ptr(value);
tx._privatize(move || drop(Box::from_raw(ptr.into())))
}
#[inline]
pub unsafe fn privatize<'tcell, F: FnOnce(*mut T) + Copy + Send + 'static>(
tx: &mut impl Write<'tcell>,
value: *const T,
privatizer: F,
) {
let ptr = Ptr(value);
tx._privatize(move || privatizer(ptr.into()))
}
#[inline]
pub fn set<'tcell>(
&'tcell self,
tx: &mut impl Write<'tcell>,
value: *const T,
) -> Result<(), Error> {
Ok(self.publish(tx, Publisher::new(value as *mut _, |_| {}))?)
}
}
pub struct Publisher<T, F: FnOnce(*mut T) + Copy + 'static> {
ptr: *mut T,
destructor: F,
}
impl<T, F: FnOnce(*mut T) + Copy + 'static> Drop for Publisher<T, F> {
#[inline]
fn drop(&mut self) {
(self.destructor)(self.ptr)
}
}
impl<T: 'static, F: FnOnce(*mut T) + Copy + 'static> Publisher<T, F> {
#[inline]
pub fn new(ptr: *mut T, destructor: F) -> Self {
assert_eq!(
mem::size_of::<F>(),
0,
"Publisher requires the destructor to be zero sized"
);
Publisher { ptr, destructor }
}
}
unsafe impl<T: 'static, F: FnOnce(*mut T) + Copy + 'static> _TValue<Ptr<T>> for Publisher<T, F> {
const REQUEST_TCELL_LIFETIME: bool = true;
}