use core::{
cell::UnsafeCell,
mem::{forget, size_of, zeroed, MaybeUninit},
ptr,
};
pub(crate) struct KanalPtr<T>(UnsafeCell<MaybeUninit<*mut T>>);
impl<T> Default for KanalPtr<T> {
fn default() -> Self {
Self(UnsafeCell::new(MaybeUninit::uninit()))
}
}
impl<T> KanalPtr<T> {
#[inline(always)]
pub(crate) fn new_from(addr: *mut T) -> Self {
if size_of::<T>() > size_of::<*mut T>() {
Self(UnsafeCell::new(MaybeUninit::new(addr)))
} else {
Self(UnsafeCell::new(unsafe { store_as_kanal_ptr(addr) }))
}
}
#[cfg(feature = "async")]
#[inline(always)]
pub(crate) fn new_owned(d: T) -> Self {
if size_of::<T>() > size_of::<*mut T>() {
unreachable!("bug: data can't be stored when size of T is bigger than pointer size");
} else {
let ret = Self(UnsafeCell::new(unsafe { store_as_kanal_ptr(&d) }));
forget(d);
ret
}
}
#[inline(always)]
pub(crate) fn new_write_address_ptr(addr: *mut T) -> Self {
if size_of::<T>() > size_of::<*mut T>() {
Self(UnsafeCell::new(MaybeUninit::new(addr)))
} else {
Self(UnsafeCell::new(MaybeUninit::uninit()))
}
}
#[cfg(feature = "async")]
#[inline(always)]
pub(crate) fn new_unchecked(addr: *mut T) -> Self {
Self(UnsafeCell::new(MaybeUninit::new(addr)))
}
#[inline(always)]
pub(crate) unsafe fn read(&self) -> T {
if size_of::<T>() == 0 {
zeroed()
} else if size_of::<T>() > size_of::<*mut T>() {
ptr::read((*self.0.get()).assume_init())
} else {
ptr::read((*self.0.get()).as_ptr() as *const T)
}
}
#[inline(always)]
pub(crate) unsafe fn write(&self, d: T) {
if size_of::<T>() > size_of::<*mut T>() {
ptr::write((*self.0.get()).assume_init(), d);
} else {
if size_of::<T>() > 0 {
*self.0.get() = store_as_kanal_ptr(&d);
}
forget(d);
}
}
#[inline(always)]
#[allow(unused)]
pub(crate) unsafe fn copy(&self, d: *const T) {
if size_of::<T>() > size_of::<*mut T>() {
ptr::copy_nonoverlapping(d, (*self.0.get()).assume_init(), 1);
} else if size_of::<T>() > 0 {
*self.0.get() = store_as_kanal_ptr(d);
}
}
}
#[inline(always)]
unsafe fn store_as_kanal_ptr<T>(ptr: *const T) -> MaybeUninit<*mut T> {
let mut ret = MaybeUninit::uninit();
if size_of::<T>() > 0 {
ptr::copy_nonoverlapping(ptr, ret.as_mut_ptr() as *mut T, 1);
}
ret
}