use alloc::format;
use core::{
alloc::Layout,
ops::{Deref, DerefMut},
};
use core::{fmt::Debug, mem::MaybeUninit};
use iceoryx2_bb_elementary::{math::unaligned_mem_size, relocatable_ptr::*};
pub use iceoryx2_bb_elementary_traits::relocatable_container::RelocatableContainer;
use iceoryx2_bb_elementary_traits::zero_copy_send::ZeroCopySend;
use iceoryx2_log::{fail, fatal_panic};
pub use crate::vector::Vector;
use crate::vector::internal;
#[repr(C)]
pub struct RelocatableVec<T> {
data_ptr: RelocatablePointer<MaybeUninit<T>>,
capacity: u64,
len: u64,
}
impl<T> Drop for RelocatableVec<T> {
fn drop(&mut self) {
if self.data_ptr.is_initialized() {
self.clear()
}
}
}
unsafe impl<T: Send> Send for RelocatableVec<T> {}
unsafe impl<T: ZeroCopySend> ZeroCopySend for RelocatableVec<T> {}
impl<T: Debug> Debug for RelocatableVec<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(
f,
"RelocatableVec<{}> {{ capacity: {}, len: {}, content: [ ",
core::any::type_name::<T>(),
self.capacity,
self.len,
)?;
if !self.is_empty() {
write!(f, "{:?}", self[0])?;
}
for idx in 1..self.len() {
write!(f, ", {:?}", self[idx])?;
}
write!(f, " ] }}")
}
}
impl<T> Deref for RelocatableVec<T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
self.verify_init("deref()");
self.as_slice()
}
}
impl<T> DerefMut for RelocatableVec<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.verify_init("deref_mut()");
self.as_mut_slice()
}
}
impl<T: PartialEq> PartialEq for RelocatableVec<T> {
fn eq(&self, other: &Self) -> bool {
if other.len() != self.len() {
return false;
}
for i in 0..self.len() {
if other[i] != self[i] {
return false;
}
}
true
}
}
impl<T: Eq> Eq for RelocatableVec<T> {}
impl<T> RelocatableVec<T> {
#[inline(always)]
fn verify_init(&self, source: &str) {
debug_assert!(
self.data_ptr.is_initialized(),
"From: RelocatableVec<{}>::{}, Undefined behavior - the object was not initialized with 'init' before.",
core::any::type_name::<T>(),
source
);
}
pub const fn const_memory_size(capacity: usize) -> usize {
unaligned_mem_size::<T>(capacity)
}
}
impl<T> RelocatableContainer for RelocatableVec<T> {
unsafe fn new_uninit(capacity: usize) -> Self {
Self {
data_ptr: unsafe { RelocatablePointer::new_uninit() },
capacity: capacity as u64,
len: 0,
}
}
unsafe fn init<Allocator: iceoryx2_bb_elementary_traits::allocator::BaseAllocator>(
&mut self,
allocator: &Allocator,
) -> Result<(), iceoryx2_bb_elementary_traits::allocator::AllocationError> {
if self.data_ptr.is_initialized() {
let origin = format!("RelocatableVec<{}>::init()", core::any::type_name::<T>());
fatal_panic!(from origin,
"Memory already initialized. Initializing it twice may lead to undefined behavior.");
}
let ptr = match allocator.allocate(unsafe {
Layout::from_size_align_unchecked(
core::mem::size_of::<T>() * self.capacity as usize,
core::mem::align_of::<T>(),
)
}) {
Ok(ptr) => ptr,
Err(e) => {
let origin = format!("RelocatableVec<{}>::init()", core::any::type_name::<T>());
fail!(from origin, with e,
"Failed to initialize since the allocation of the data memory failed.");
}
};
unsafe {
self.data_ptr.init(ptr);
}
Ok(())
}
fn memory_size(capacity: usize) -> usize {
Self::const_memory_size(capacity)
}
}
impl<T> internal::VectorView<T> for RelocatableVec<T> {
fn data(&self) -> &[MaybeUninit<T>] {
self.verify_init("data()");
unsafe { core::slice::from_raw_parts(self.data_ptr.as_ptr(), self.capacity()) }
}
unsafe fn data_mut(&mut self) -> &mut [MaybeUninit<T>] {
self.verify_init("data_mut()");
unsafe { core::slice::from_raw_parts_mut(self.data_ptr.as_mut_ptr(), self.capacity()) }
}
unsafe fn set_len(&mut self, len: u64) {
self.len = len;
}
}
impl<T> Vector<T> for RelocatableVec<T> {
fn capacity(&self) -> usize {
self.capacity as usize
}
fn len(&self) -> usize {
self.len as usize
}
}