use crate::traits::NonNullable;
use core::mem::MaybeUninit;
#[derive(Debug, Clone, Copy)]
pub struct MaybeNullCopy<T: NonNullable + Copy> {
inner: MaybeUninit<T>,
}
impl<T: NonNullable + Copy> MaybeNullCopy<T> {
#[inline(always)]
#[must_use]
pub const fn null() -> Self {
Self {
inner: MaybeUninit::zeroed(),
}
}
#[inline(always)]
#[must_use]
pub const fn new(val: T) -> Self {
Self {
inner: MaybeUninit::new(val),
}
}
#[inline(always)]
pub const fn is_null(&self) -> bool {
let ptr = self.inner.as_ptr().cast::<u8>();
let mut i = 0;
while i < size_of::<T>() {
if unsafe { ptr.add(i).read() } != 0 {
return false;
}
i += 1;
}
true
}
#[inline(always)]
pub const fn is_init(&self) -> bool {
let ptr = self.inner.as_ptr().cast::<u8>();
let mut i = 0;
while i < size_of::<T>() {
if unsafe { ptr.add(i).read() } == 0 {
return false;
}
i += 1;
}
true
}
#[inline(always)]
pub fn into_inner(self) -> Option<T> {
if self.is_init() {
unsafe { Some(self.into_inner_unchecked()) }
} else {
None
}
}
#[inline(always)]
pub unsafe fn into_inner_unchecked(self) -> T {
unsafe { self.inner.assume_init_read() }
}
#[inline(always)]
pub const fn get(&self) -> Option<&T> {
if self.is_init() {
unsafe { Some(self.get_unchecked()) }
} else {
None
}
}
#[inline(always)]
pub const fn get_mut(&mut self) -> Option<&mut T> {
if self.is_init() {
unsafe { Some(self.get_mut_unchecked()) }
} else {
None
}
}
#[inline(always)]
pub const unsafe fn get_unchecked(&self) -> &T {
unsafe { self.inner.assume_init_ref() }
}
#[inline(always)]
pub const unsafe fn get_mut_unchecked(&mut self) -> &mut T {
unsafe { self.inner.assume_init_mut() }
}
#[inline(always)]
pub const fn as_ptr(&self) -> *const T {
self.inner.as_ptr()
}
#[inline(always)]
pub const fn as_mut_ptr(&mut self) -> *mut T {
self.inner.as_mut_ptr()
}
#[inline(always)]
pub const fn set(&mut self, val: T) -> bool {
if self.is_null() {
unsafe {
self.inner.as_mut_ptr().write(val);
}
true
} else {
false
}
}
#[inline(always)]
pub const fn force_set(&mut self, val: T) {
unsafe {
self.inner.as_mut_ptr().write(val);
}
}
#[inline(always)]
pub const fn nullify(&mut self) {
if self.is_init() {
unsafe {
core::ptr::write_bytes(self.inner.as_mut_ptr().cast::<u8>(), 0, size_of::<T>());
}
}
}
#[inline(always)]
pub const unsafe fn nullify_unchecked(&mut self) {
unsafe {
core::ptr::write_bytes(self.inner.as_mut_ptr().cast::<u8>(), 0, size_of::<T>());
}
}
pub fn match_null_ref<R>(
&self,
if_init: impl FnOnce(&T) -> R,
if_null: impl FnOnce() -> R,
) -> R {
if self.is_init() {
unsafe { if_init(self.get_unchecked()) }
} else {
if_null()
}
}
pub fn match_null_mut<R>(
&mut self,
if_init: impl FnOnce(&mut T) -> R,
if_null: impl FnOnce() -> R,
) -> R {
if self.is_init() {
unsafe { if_init(self.get_mut_unchecked()) }
} else {
if_null()
}
}
pub fn match_null<R>(self, if_init: impl FnOnce(T) -> R, if_null: impl FnOnce() -> R) -> R {
if self.is_init() {
unsafe { if_init(self.into_inner_unchecked()) }
} else {
if_null()
}
}
}