iceoryx2_bb_container/vector/
relocatable_vec.rs

1// Copyright (c) 2025 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13//! Contains the [`RelocatableVec`], a
14//! run-time fixed size vector that is shared memory compatible
15//!
16//! # Expert Examples
17//!
18//! ## Create [`RelocatableVec`] inside constructs which provides memory
19//!
20//! ```
21//! use iceoryx2_bb_container::vector::*;
22//! use iceoryx2_bb_elementary::math::align_to;
23//! use iceoryx2_bb_elementary::bump_allocator::BumpAllocator;
24//! use core::mem::MaybeUninit;
25//!
26//! const VEC_CAPACITY:usize = 12;
27//! struct MyConstruct {
28//!     vec: RelocatableVec<u128>,
29//!     vec_memory: [MaybeUninit<u128>; VEC_CAPACITY],
30//! }
31//!
32//! impl MyConstruct {
33//!     pub fn new() -> Self {
34//!         let mut new_self = Self {
35//!             vec: unsafe { RelocatableVec::new_uninit(VEC_CAPACITY) },
36//!             vec_memory: core::array::from_fn(|_| MaybeUninit::uninit()),
37//!         };
38//!
39//!         let allocator = BumpAllocator::new(new_self.vec_memory.as_mut_ptr().cast());
40//!         unsafe {
41//!             new_self.vec.init(&allocator).expect("Enough memory provided.")
42//!         };
43//!         new_self
44//!     }
45//! }
46//! ```
47//!
48//! ## Create [`RelocatableVec`] with allocator
49//!
50//! ```
51//! # extern crate iceoryx2_loggers;
52//! use iceoryx2_bb_container::vector::*;
53//! use iceoryx2_bb_elementary::bump_allocator::BumpAllocator;
54//! use core::ptr::NonNull;
55//!
56//! const VEC_CAPACITY:usize = 12;
57//! const MEM_SIZE: usize = RelocatableVec::<u128>::const_memory_size(VEC_CAPACITY);
58//! let mut memory = [0u8; MEM_SIZE];
59//!
60//! let bump_allocator = BumpAllocator::new(memory.as_mut_ptr());
61//!
62//! let mut vec = unsafe { RelocatableVec::<u128>::new_uninit(VEC_CAPACITY) };
63//! unsafe { vec.init(&bump_allocator).expect("vec init failed") };
64//! ```
65
66use alloc::format;
67use core::{
68    alloc::Layout,
69    ops::{Deref, DerefMut},
70};
71use core::{fmt::Debug, mem::MaybeUninit};
72
73use iceoryx2_bb_elementary::{math::unaligned_mem_size, relocatable_ptr::*};
74pub use iceoryx2_bb_elementary_traits::relocatable_container::RelocatableContainer;
75use iceoryx2_bb_elementary_traits::zero_copy_send::ZeroCopySend;
76use iceoryx2_log::{fail, fatal_panic};
77
78use crate::vector::internal;
79pub use crate::vector::Vector;
80
81/// **Non-movable** relocatable shared-memory compatible vector with runtime fixed size capacity.
82#[repr(C)]
83pub struct RelocatableVec<T> {
84    data_ptr: RelocatablePointer<MaybeUninit<T>>,
85    capacity: u64,
86    len: u64,
87}
88
89impl<T> Drop for RelocatableVec<T> {
90    fn drop(&mut self) {
91        if self.data_ptr.is_initialized() {
92            self.clear()
93        }
94    }
95}
96
97unsafe impl<T: Send> Send for RelocatableVec<T> {}
98
99unsafe impl<T: ZeroCopySend> ZeroCopySend for RelocatableVec<T> {}
100
101impl<T: Debug> Debug for RelocatableVec<T> {
102    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
103        write!(
104            f,
105            "RelocatableVec<{}> {{ capacity: {}, len: {}, content: [ ",
106            core::any::type_name::<T>(),
107            self.capacity,
108            self.len,
109        )?;
110
111        if !self.is_empty() {
112            write!(f, "{:?}", self[0])?;
113        }
114
115        for idx in 1..self.len() {
116            write!(f, ", {:?}", self[idx])?;
117        }
118
119        write!(f, " ] }}")
120    }
121}
122
123impl<T> Deref for RelocatableVec<T> {
124    type Target = [T];
125
126    fn deref(&self) -> &Self::Target {
127        self.verify_init("deref()");
128        self.as_slice()
129    }
130}
131
132impl<T> DerefMut for RelocatableVec<T> {
133    fn deref_mut(&mut self) -> &mut Self::Target {
134        self.verify_init("deref_mut()");
135        self.as_mut_slice()
136    }
137}
138
139impl<T: PartialEq> PartialEq for RelocatableVec<T> {
140    fn eq(&self, other: &Self) -> bool {
141        if other.len() != self.len() {
142            return false;
143        }
144
145        for i in 0..self.len() {
146            if other[i] != self[i] {
147                return false;
148            }
149        }
150
151        true
152    }
153}
154
155impl<T: Eq> Eq for RelocatableVec<T> {}
156
157impl<T> RelocatableVec<T> {
158    #[inline(always)]
159    fn verify_init(&self, source: &str) {
160        debug_assert!(
161                self.data_ptr.is_initialized(),
162                "From: RelocatableVec<{}>::{}, Undefined behavior - the object was not initialized with 'init' before.",
163                core::any::type_name::<T>(), source
164            );
165    }
166
167    /// Returns the required memory size for a vec with a specified capacity
168    pub const fn const_memory_size(capacity: usize) -> usize {
169        unaligned_mem_size::<T>(capacity)
170    }
171}
172
173impl<T> RelocatableContainer for RelocatableVec<T> {
174    unsafe fn new_uninit(capacity: usize) -> Self {
175        Self {
176            data_ptr: RelocatablePointer::new_uninit(),
177            capacity: capacity as u64,
178            len: 0,
179        }
180    }
181
182    unsafe fn init<Allocator: iceoryx2_bb_elementary_traits::allocator::BaseAllocator>(
183        &mut self,
184        allocator: &Allocator,
185    ) -> Result<(), iceoryx2_bb_elementary_traits::allocator::AllocationError> {
186        if self.data_ptr.is_initialized() {
187            let origin = format!("RelocatableVec<{}>::init()", core::any::type_name::<T>());
188            fatal_panic!(from origin,
189                "Memory already initialized. Initializing it twice may lead to undefined behavior.");
190        }
191
192        let ptr = match allocator.allocate(Layout::from_size_align_unchecked(
193            core::mem::size_of::<T>() * self.capacity as usize,
194            core::mem::align_of::<T>(),
195        )) {
196            Ok(ptr) => ptr,
197            Err(e) => {
198                let origin = format!("RelocatableVec<{}>::init()", core::any::type_name::<T>());
199                fail!(from origin, with e,
200                    "Failed to initialize since the allocation of the data memory failed.");
201            }
202        };
203
204        self.data_ptr.init(ptr);
205
206        Ok(())
207    }
208
209    fn memory_size(capacity: usize) -> usize {
210        Self::const_memory_size(capacity)
211    }
212}
213
214impl<T> internal::VectorView<T> for RelocatableVec<T> {
215    fn data(&self) -> &[MaybeUninit<T>] {
216        self.verify_init("data()");
217        unsafe { core::slice::from_raw_parts(self.data_ptr.as_ptr(), self.capacity()) }
218    }
219
220    unsafe fn data_mut(&mut self) -> &mut [MaybeUninit<T>] {
221        self.verify_init("data_mut()");
222        core::slice::from_raw_parts_mut(self.data_ptr.as_mut_ptr(), self.capacity())
223    }
224
225    unsafe fn set_len(&mut self, len: u64) {
226        self.len = len;
227    }
228}
229
230impl<T> Vector<T> for RelocatableVec<T> {
231    fn capacity(&self) -> usize {
232        self.capacity as usize
233    }
234
235    fn len(&self) -> usize {
236        self.len as usize
237    }
238}