use core::marker::PhantomData;
use core::mem::MaybeUninit;
use iceoryx2_bb_concurrency::atomic::{AtomicU8, Ordering};
use iceoryx2_bb_elementary_traits::{atomic_copy::AtomicCopy, zero_copy_send::ZeroCopySend};
use iceoryx2_log::fail;
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
pub enum ByteAtomicError {
SizesDoNotMatch,
}
#[repr(C)]
pub struct ByteAtomic<T: AtomicCopy, const SIZE: usize> {
data: [AtomicU8; SIZE],
_inner_type: PhantomData<T>,
}
unsafe impl<T: AtomicCopy + ZeroCopySend, const SIZE: usize> ZeroCopySend for ByteAtomic<T, SIZE> {}
impl<T: AtomicCopy, const SIZE: usize> ByteAtomic<T, SIZE> {
pub fn new(value: T) -> Result<Self, ByteAtomicError> {
if size_of::<T>() != SIZE {
fail!(from "ByteAtomic::new()", with ByteAtomicError::SizesDoNotMatch,
"size_of::<T>() and SIZE must be equal.");
}
let value_ptr = (&value as *const T) as *const u8;
let mut bytes = [0u8; SIZE];
value.__for_each_field(0, &mut |offset, size| {
for (i, byte) in bytes.iter_mut().enumerate().skip(offset).take(size) {
*byte = unsafe { *value_ptr.add(i) };
}
});
Ok(Self {
data: bytes.map(AtomicU8::new),
_inner_type: PhantomData,
})
}
pub unsafe fn read(&self) -> MaybeUninit<T> {
let mut data: MaybeUninit<T> = MaybeUninit::uninit();
let data_ptr = data.as_mut_ptr() as *mut u8;
for (i, item) in self.data.iter().enumerate() {
unsafe {
*data_ptr.add(i) = item.load(Ordering::Relaxed);
}
}
data
}
pub unsafe fn write(&self, value: T) {
let value_ptr = (&value as *const T) as *const u8;
value.__for_each_field(0, &mut |offset, size| {
for i in offset..offset + size {
self.data[i].store(unsafe { *value_ptr.add(i) }, Ordering::Relaxed);
}
});
}
}