use crate::trivial_type::TrivialType;
use crate::{DerefWrapper, IoType, IoTypeOptional};
use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
#[derive(Debug)]
pub struct MaybeData<Data>
where
Data: TrivialType,
{
data: NonNull<Data>,
size: NonNull<u32>,
}
unsafe impl<Data> IoType for MaybeData<Data>
where
Data: TrivialType,
{
const METADATA: &[u8] = Data::METADATA;
type PointerType = Data;
#[inline(always)]
fn size(&self) -> u32 {
unsafe { self.size.read() }
}
#[inline(always)]
fn capacity(&self) -> u32 {
Data::SIZE
}
#[inline(always)]
#[track_caller]
unsafe fn set_size(&mut self, size: u32) {
debug_assert!(
size == 0 || size == Data::SIZE,
"`set_size` called with invalid input {size} (self size {})",
self.size()
);
unsafe {
self.size.write(size);
}
}
#[inline(always)]
#[track_caller]
unsafe fn from_ptr<'a>(
data: &'a NonNull<Self::PointerType>,
size: &'a u32,
capacity: u32,
) -> impl Deref<Target = Self> + 'a {
debug_assert!(data.is_aligned(), "Misaligned pointer");
debug_assert!(
*size == 0 || *size <= capacity,
"Invalid size {size} for capacity {capacity}"
);
debug_assert!(
capacity == 0 || capacity >= Data::SIZE,
"Invalid capacity {capacity} for size {}",
Data::SIZE
);
let size = NonNull::from_ref(size);
DerefWrapper(MaybeData { data: *data, size })
}
#[inline(always)]
#[track_caller]
unsafe fn from_mut_ptr<'a>(
data: &'a mut NonNull<Self::PointerType>,
size: &'a mut u32,
capacity: u32,
) -> impl DerefMut<Target = Self> + 'a {
debug_assert!(data.is_aligned(), "Misaligned pointer");
debug_assert!(
*size == 0 || *size <= capacity,
"Invalid size {size} for capacity {capacity}"
);
debug_assert!(
capacity >= Data::SIZE,
"Invalid capacity {capacity} for size {}",
Data::SIZE
);
DerefWrapper(MaybeData {
data: *data,
size: NonNull::from_mut(size),
})
}
#[inline(always)]
unsafe fn as_ptr(&self) -> impl Deref<Target = NonNull<Self::PointerType>> {
&self.data
}
#[inline(always)]
unsafe fn as_mut_ptr(&mut self) -> impl DerefMut<Target = NonNull<Self::PointerType>> {
&mut self.data
}
}
impl<Data> IoTypeOptional for MaybeData<Data> where Data: TrivialType {}
impl<Data> MaybeData<Data>
where
Data: TrivialType,
{
pub const fn from_ref(data: Option<&'_ Data>) -> impl Deref<Target = Self> + '_ {
let (data, size) = if let Some(data) = data {
(NonNull::from_ref(data), &Data::SIZE)
} else {
(NonNull::dangling(), &0)
};
DerefWrapper(Self {
data,
size: NonNull::from_ref(size),
})
}
#[track_caller]
pub fn from_mut<'a>(
buffer: &'a mut Data,
size: &'a mut u32,
) -> impl DerefMut<Target = Self> + 'a {
debug_assert!(
*size == 0 || *size == Data::SIZE,
"Invalid size {size} (self size {})",
Data::SIZE
);
DerefWrapper(Self {
data: NonNull::from_mut(buffer),
size: NonNull::from_mut(size),
})
}
#[track_caller]
pub fn from_uninit<'a>(
uninit: &'a mut MaybeUninit<Data>,
size: &'a mut u32,
) -> impl DerefMut<Target = Self> + 'a {
debug_assert_eq!(*size, 0, "Invalid size");
DerefWrapper(Self {
data: NonNull::from_mut(uninit).cast::<Data>(),
size: NonNull::from_mut(size),
})
}
#[inline(always)]
pub const fn get(&self) -> Option<&Data> {
if unsafe { self.size.read() } == Data::SIZE {
Some(unsafe { self.data.as_ref() })
} else {
None
}
}
#[inline(always)]
pub fn get_mut(&mut self) -> Option<&mut Data> {
if unsafe { self.size.read() } == Data::SIZE {
Some(unsafe { self.data.as_mut() })
} else {
None
}
}
#[inline(always)]
pub fn replace(&mut self, data: Data) -> &mut Data {
unsafe {
self.size.write(Data::SIZE);
}
unsafe {
self.data.write(data);
self.data.as_mut()
}
}
#[inline(always)]
pub fn remove(&mut self) {
unsafe {
self.size.write(0);
}
}
#[inline(always)]
pub fn get_mut_or_init_with<Init>(&mut self, init: Init) -> &mut Data
where
Init: FnOnce(&mut MaybeUninit<Data>) -> &mut Data,
{
if unsafe { self.size.read() } == Data::SIZE {
unsafe { self.data.as_mut() }
} else {
let data = init(unsafe { self.data.as_uninit_mut() });
unsafe {
self.size.write(Data::SIZE);
}
data
}
}
#[inline(always)]
pub unsafe fn assume_init(&mut self) -> &mut Data {
unsafe {
self.size.write(Data::SIZE);
}
unsafe { self.data.as_mut() }
}
}
impl<Data> MaybeData<Data>
where
Data: TrivialType + Default,
{
#[inline(always)]
pub fn get_mut_or_default(&mut self) -> &mut Data {
self.get_mut_or_init_with(|data| data.write(Data::default()))
}
}