use std::cell::UnsafeCell;
use std::mem::MaybeUninit;
use std::ptr;
use std::ptr::NonNull;
use std::sync::atomic::{AtomicBool, Ordering};
#[inline]
pub(crate) unsafe fn slice_from_external_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
if len == 0 {
return &[];
}
core::slice::from_raw_parts(data, len)
}
#[inline]
pub(crate) unsafe fn slice_from_external_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
if len == 0 {
return &mut [];
}
core::slice::from_raw_parts_mut(data, len)
}
pub(crate) struct UnsafeOptionCell<T> {
is_some: AtomicBool,
inner: UnsafeCell<MaybeUninit<T>>,
}
impl<T> UnsafeOptionCell<T> {
pub(crate) fn new() -> Self {
Self {
is_some: AtomicBool::new(false),
inner: UnsafeCell::new(MaybeUninit::uninit()),
}
}
pub fn is_some(&self) -> bool {
self.is_some.load(Ordering::Relaxed)
}
pub fn as_ptr(&self) -> Option<NonNull<T>> {
if !self.is_some() {
return None;
}
let ptr = self.inner.get().cast();
unsafe { Some(NonNull::new_unchecked(ptr)) }
}
pub unsafe fn put(&self, value: T) {
if let Err(true) =
self.is_some
.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
{
ptr::drop_in_place(self.inner.get().cast::<T>())
}
self.inner.get().write(MaybeUninit::new(value));
}
pub unsafe fn take(&self) -> Option<T> {
if let Ok(true) =
self.is_some
.compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
{
Some(self.inner.get().cast::<T>().read())
} else {
None
}
}
}
impl<T> Drop for UnsafeOptionCell<T> {
fn drop(&mut self) {
let is_some = self.is_some.get_mut();
if *is_some {
unsafe { self.inner.get_mut().assume_init_drop() }
}
*is_some = false;
}
}