iceoryx2_bb_container/vector/
static_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//! Relocatable shared-memory compatible vector with compile time fixed size
14//! capacity. It is memory-layout compatible to the C++ container in the
15//! iceoryx2-bb-container C++ library and can be used for zero-copy
16//! cross-language communication.
17//!
18//! # Example
19//!
20//! ```
21//! # extern crate iceoryx2_loggers;
22//!
23//! use iceoryx2_bb_container::vector::*;
24//!
25//! const CAPACITY: usize = 123;
26//! let mut my_vec = StaticVec::<usize, CAPACITY>::new();
27//!
28//! my_vec.push(123); // returns false, when capacity is exceeded
29//! ```
30
31use alloc::format;
32use core::{fmt::Debug, mem::MaybeUninit};
33use core::{
34    marker::PhantomData,
35    ops::{Deref, DerefMut},
36};
37
38use iceoryx2_bb_elementary_traits::{
39    placement_default::PlacementDefault, zero_copy_send::ZeroCopySend,
40};
41use iceoryx2_log::fail;
42use serde::{de::Visitor, Deserialize, Serialize};
43
44pub use crate::vector::Vector;
45use crate::vector::{internal, VectorModificationError};
46
47/// Relocatable shared-memory compatible vector with compile time fixed size
48/// capacity. It is memory-layout compatible to the C++ container in the
49/// iceoryx2-bb-container C++ library and can be used for zero-copy
50/// cross-language communication.
51///
52/// In contrast to the Rust [`alloc::vec::Vec`] it has a defined reverse drop order.
53#[repr(C)]
54pub struct StaticVec<T, const CAPACITY: usize> {
55    data: [MaybeUninit<T>; CAPACITY],
56    len: u64,
57}
58
59impl<T: Debug, const CAPACITY: usize> Debug for StaticVec<T, CAPACITY> {
60    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
61        write!(
62            f,
63            "StaticVec<{}, {}> {{ len: {}, content: [ ",
64            core::any::type_name::<T>(),
65            CAPACITY,
66            self.len,
67        )?;
68
69        if !self.is_empty() {
70            write!(f, "{:?}", self[0])?;
71        }
72
73        for idx in 1..self.len() {
74            write!(f, ", {:?}", self[idx])?;
75        }
76
77        write!(f, " ] }}")
78    }
79}
80
81unsafe impl<T: ZeroCopySend, const CAPACITY: usize> ZeroCopySend for StaticVec<T, CAPACITY> {}
82
83impl<T, const CAPACITY: usize> Drop for StaticVec<T, CAPACITY> {
84    fn drop(&mut self) {
85        self.clear();
86    }
87}
88
89impl<'de, T: Serialize + Deserialize<'de>, const CAPACITY: usize> Serialize
90    for StaticVec<T, CAPACITY>
91{
92    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
93    where
94        S: serde::Serializer,
95    {
96        self.as_slice().serialize(serializer)
97    }
98}
99
100struct StaticVecVisitor<T, const CAPACITY: usize> {
101    _value: PhantomData<T>,
102}
103
104impl<'de, T: Deserialize<'de>, const CAPACITY: usize> Visitor<'de>
105    for StaticVecVisitor<T, CAPACITY>
106{
107    type Value = StaticVec<T, CAPACITY>;
108
109    fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
110        let str = format!(
111            "an array of at most {} elements of type {}",
112            CAPACITY,
113            core::any::type_name::<T>()
114        );
115        formatter.write_str(&str)
116    }
117
118    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
119    where
120        A: serde::de::SeqAccess<'de>,
121    {
122        let mut new_vec = Self::Value::new();
123
124        while let Some(element) = seq.next_element()? {
125            if new_vec.push(element).is_err() {
126                return Err(<A::Error as serde::de::Error>::custom(format!(
127                    "the array can hold at most {CAPACITY} elements"
128                )));
129            }
130        }
131
132        Ok(new_vec)
133    }
134}
135
136impl<'de, T: Deserialize<'de>, const CAPACITY: usize> Deserialize<'de> for StaticVec<T, CAPACITY> {
137    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
138    where
139        D: serde::Deserializer<'de>,
140    {
141        deserializer.deserialize_seq(StaticVecVisitor::<T, CAPACITY> {
142            _value: PhantomData,
143        })
144    }
145}
146
147impl<T, const CAPACITY: usize> PlacementDefault for StaticVec<T, CAPACITY> {
148    unsafe fn placement_default(ptr: *mut Self) {
149        core::ptr::addr_of_mut!((*ptr).len).write(0);
150        // We do not have to initialize the `MaybeUninit` array at all, see:
151        // https://google.github.io/learn_unsafe_rust/advanced_unsafety/uninitialized.html
152        // core::ptr::addr_of_mut!((*ptr).data).write([const { MaybeUninit::uninit() }; CAPACITY]);
153    }
154}
155
156impl<T, const CAPACITY: usize> Default for StaticVec<T, CAPACITY> {
157    fn default() -> Self {
158        Self {
159            len: 0,
160            data: [const { MaybeUninit::uninit() }; CAPACITY],
161        }
162    }
163}
164
165impl<T, const CAPACITY: usize> Deref for StaticVec<T, CAPACITY> {
166    type Target = [T];
167
168    fn deref(&self) -> &Self::Target {
169        self.as_slice()
170    }
171}
172
173impl<T, const CAPACITY: usize> DerefMut for StaticVec<T, CAPACITY> {
174    fn deref_mut(&mut self) -> &mut Self::Target {
175        self.as_mut_slice()
176    }
177}
178
179impl<T: PartialEq, const CAPACITY: usize> PartialEq for StaticVec<T, CAPACITY> {
180    fn eq(&self, other: &Self) -> bool {
181        if self.len != other.len {
182            return false;
183        }
184
185        for i in 0..self.len() {
186            if other[i] != self[i] {
187                return false;
188            }
189        }
190
191        true
192    }
193}
194
195impl<T: Clone, const CAPACITY: usize> TryFrom<&[T]> for StaticVec<T, CAPACITY> {
196    type Error = VectorModificationError;
197    fn try_from(value: &[T]) -> Result<Self, Self::Error> {
198        if CAPACITY < value.len() {
199            let origin = format!(
200                "StaticVec::<{}, {}>::try_from()",
201                core::any::type_name::<T>(),
202                CAPACITY
203            );
204            fail!(from origin, with VectorModificationError::InsertWouldExceedCapacity,
205                "Failed to create the vector since the slice len {} is greater than the vectors capacity.",
206                value.len());
207        }
208
209        let mut new_self = Self::new();
210        unsafe { new_self.extend_from_slice_unchecked(value) };
211        Ok(new_self)
212    }
213}
214
215impl<T: Eq, const CAPACITY: usize> Eq for StaticVec<T, CAPACITY> {}
216
217impl<T: Clone, const CAPACITY: usize> Clone for StaticVec<T, CAPACITY> {
218    fn clone(&self) -> Self {
219        Self {
220            len: self.len,
221            data: {
222                let mut data = [const { MaybeUninit::uninit() }; CAPACITY];
223                for (idx, item) in data.iter_mut().enumerate().take(self.len()) {
224                    item.write(unsafe { self.data[idx].assume_init_ref() }.clone());
225                }
226                data
227            },
228        }
229    }
230}
231
232unsafe impl<T: Send, const CAPACITY: usize> Send for StaticVec<T, CAPACITY> {}
233
234impl<T, const CAPACITY: usize> StaticVec<T, CAPACITY> {
235    /// Creates a new vector.
236    pub fn new() -> Self {
237        Self::default()
238    }
239
240    /// Returns the capacity of the vector
241    pub const fn capacity() -> usize {
242        CAPACITY
243    }
244}
245
246impl<T, const CAPACITY: usize> internal::VectorView<T> for StaticVec<T, CAPACITY> {
247    fn data(&self) -> &[MaybeUninit<T>] {
248        &self.data
249    }
250
251    unsafe fn data_mut(&mut self) -> &mut [MaybeUninit<T>] {
252        &mut self.data
253    }
254
255    unsafe fn set_len(&mut self, len: u64) {
256        self.len = len
257    }
258}
259
260impl<T, const CAPACITY: usize> Vector<T> for StaticVec<T, CAPACITY> {
261    fn capacity(&self) -> usize {
262        CAPACITY
263    }
264
265    fn len(&self) -> usize {
266        self.len as usize
267    }
268}
269
270#[allow(missing_docs)]
271pub struct VectorMemoryLayoutMetrics {
272    pub vector_size: usize,
273    pub vector_alignment: usize,
274    pub size_data: usize,
275    pub offset_data: usize,
276    pub size_len: usize,
277    pub offset_len: usize,
278    pub len_is_unsigned: bool,
279}
280
281trait _VectorMemoryLayoutFieldLenInspection {
282    fn is_unsigned(&self) -> bool;
283}
284
285impl _VectorMemoryLayoutFieldLenInspection for u64 {
286    fn is_unsigned(&self) -> bool {
287        true
288    }
289}
290
291impl VectorMemoryLayoutMetrics {
292    #[allow(missing_docs)]
293    pub fn from_vector<T, const CAPACITY: usize>(v: &StaticVec<T, CAPACITY>) -> Self {
294        VectorMemoryLayoutMetrics {
295            vector_size: core::mem::size_of_val(v),
296            vector_alignment: core::mem::align_of_val(v),
297            size_data: core::mem::size_of_val(&v.data),
298            offset_data: core::mem::offset_of!(StaticVec<T,CAPACITY>, data),
299            size_len: core::mem::size_of_val(&v.len),
300            offset_len: core::mem::offset_of!(StaticVec<T, CAPACITY>, len),
301            len_is_unsigned: v.len.is_unsigned(),
302        }
303    }
304}