zenoh_shm/posix_shm/
array.rs

1//
2// Copyright (c) 2023 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>
13//
14
15use std::{marker::PhantomData, mem::size_of, num::NonZeroUsize};
16
17use num_traits::{AsPrimitive, PrimInt, Unsigned};
18use stabby::IStable;
19use zenoh_result::{bail, ZResult};
20
21use super::segment::Segment;
22use crate::shm;
23
24/// An SHM segment that is intended to be an array of elements of some certain type
25#[derive(Debug)]
26pub struct ArrayInSHM<ID, Elem, ElemIndex>
27where
28    rand::distributions::Standard: rand::distributions::Distribution<ID>,
29    ID: shm::SegmentID,
30{
31    inner: Segment<ID>,
32    _phantom: PhantomData<(Elem, ElemIndex)>,
33}
34
35unsafe impl<ID, Elem: Sync, ElemIndex> Sync for ArrayInSHM<ID, Elem, ElemIndex>
36where
37    rand::distributions::Standard: rand::distributions::Distribution<ID>,
38    ID: shm::SegmentID,
39{
40}
41unsafe impl<ID, Elem: Send, ElemIndex> Send for ArrayInSHM<ID, Elem, ElemIndex>
42where
43    rand::distributions::Standard: rand::distributions::Distribution<ID>,
44    ID: shm::SegmentID,
45{
46}
47
48impl<ID, Elem, ElemIndex> ArrayInSHM<ID, Elem, ElemIndex>
49where
50    rand::distributions::Standard: rand::distributions::Distribution<ID>,
51    ID: shm::SegmentID,
52    ElemIndex: Unsigned + PrimInt + 'static + AsPrimitive<usize>,
53    Elem: IStable<ContainsIndirections = stabby::abi::B0>,
54    isize: AsPrimitive<ElemIndex>,
55{
56    // Perform compile time check that Elem is not a ZST in such a way `elem_count` can not panic.
57    const _S: () = if size_of::<Elem>() == 0 {
58        panic!("Elem is a ZST. ZSTs are not allowed as ArrayInSHM generic");
59    };
60
61    pub fn create(elem_count: NonZeroUsize) -> ZResult<Self> {
62        let max: usize = ElemIndex::max_value().as_();
63        if elem_count.get() - 1 > max {
64            bail!("Unable to create SHM array segment of {elem_count} elements: out of range for ElemIndex!")
65        }
66
67        let alloc_size = NonZeroUsize::try_from(elem_count.get() * size_of::<Elem>())?;
68        let inner = Segment::create(alloc_size)?;
69        Ok(Self {
70            inner,
71            _phantom: PhantomData,
72        })
73    }
74
75    pub fn open(id: ID) -> ZResult<Self> {
76        let inner = Segment::open(id)?;
77        Ok(Self {
78            inner,
79            _phantom: PhantomData,
80        })
81    }
82
83    pub fn id(&self) -> ID {
84        self.inner.id()
85    }
86
87    pub fn elem_count(&self) -> NonZeroUsize {
88        let max: usize = ElemIndex::max_value().as_();
89        let actual = self.inner.len().get() / size_of::<Elem>();
90        unsafe { NonZeroUsize::new_unchecked(std::cmp::min(max.saturating_add(1), actual)) }
91    }
92
93    /// # Safety
94    /// Retrieves const element by it's index. This is safe if the index doesn't go out of underlying array.
95    /// Additional assert to check the index validity is added for "test" feature
96    pub unsafe fn elem(&self, index: ElemIndex) -> *const Elem {
97        #[cfg(feature = "test")]
98        assert!(self.inner.len().get() > index.as_() * size_of::<Elem>());
99        (self.inner.as_ptr() as *const Elem).add(index.as_())
100    }
101
102    /// # Safety
103    /// Retrieves mut element by it's index. This is safe if the index doesn't go out of underlying array.
104    /// Additional assert to check the index validity is added for "test" feature
105    pub unsafe fn elem_mut(&self, index: ElemIndex) -> *mut Elem {
106        #[cfg(feature = "test")]
107        assert!(self.inner.len().get() > index.as_() * size_of::<Elem>());
108        (self.inner.as_ptr() as *mut Elem).add(index.as_())
109    }
110
111    /// # Safety
112    /// Calculates element's index. This is safe if the element belongs to underlying array.
113    /// Additional assert is added for "test" feature
114    pub unsafe fn index(&self, elem: *const Elem) -> ElemIndex {
115        let index = elem.offset_from(self.inner.as_ptr() as *const Elem);
116        #[cfg(feature = "test")]
117        {
118            assert!(index >= 0);
119            assert!(self.inner.len().get() > index as usize * size_of::<Elem>());
120        }
121        index.as_()
122    }
123}