zenoh_shm/api/buffer/
typed.rs

1//
2// Copyright (c) 2025 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::{
16    marker::PhantomData,
17    mem,
18    mem::MaybeUninit,
19    ops::{Deref, DerefMut},
20};
21
22use zenoh_result::{bail, ZResult};
23
24use crate::api::buffer::{
25    traits::{ResideInShm, ShmBuf, ShmBufIntoImmut, ShmBufMut, ShmBufUnsafeMut},
26    zshm::{zshm, ZShm},
27    zshmmut::{zshmmut, ZShmMut},
28};
29
30/// Wrapper for SHM buffer types that is used for safe typed access to SHM data
31pub struct Typed<T, Buf> {
32    buf: Buf,
33    _phantom: PhantomData<T>,
34}
35
36impl<T, Buf: Clone> Clone for Typed<T, Buf> {
37    fn clone(&self) -> Self {
38        Self {
39            buf: self.buf.clone(),
40            _phantom: PhantomData,
41        }
42    }
43}
44
45impl<T, Buf> Typed<T, Buf> {
46    /// Mark a buffer as typed.
47    ///
48    /// # Safety
49    ///
50    /// The buffer layout must be compatible with `T` layout, its bytes should be initialized and respect `T` invariants, unless `T` is [`MaybeUninit`].
51    pub unsafe fn new_unchecked(buf: Buf) -> Self {
52        Self {
53            buf,
54            _phantom: PhantomData,
55        }
56    }
57
58    /// Get the underlying SHM buffer
59    pub fn inner(this: &Self) -> &Buf {
60        &this.buf
61    }
62
63    /// Get the underlying SHM buffer
64    pub fn inner_mut(this: &mut Self) -> &mut Buf {
65        &mut this.buf
66    }
67
68    /// Convert into underlying SHM buffer
69    pub fn into_inner(this: Self) -> Buf {
70        this.buf
71    }
72}
73
74impl<T, Buf> Typed<MaybeUninit<T>, Buf> {
75    /// Mark a buffer as typed, checking its layout.
76    ///
77    pub fn new(buf: Buf) -> ZResult<Self>
78    where
79        Buf: AsRef<[u8]>,
80    {
81        let slice = buf.as_ref();
82        if slice.len() != mem::size_of::<T>() {
83            bail!(
84                "Slice length does not match type size: expected {}, got {}",
85                mem::size_of::<T>(),
86                slice.len()
87            );
88        }
89        if (slice.as_ptr() as usize) % mem::align_of::<T>() != 0 {
90            bail!(
91                "Slice alignment does not match type alignment: expected {}, got {}",
92                mem::align_of::<T>(),
93                1 << (slice.as_ptr() as usize).trailing_zeros()
94            );
95        }
96        // SAFETY: the layout has been checked, and type is `MaybeUninit`
97        Ok(unsafe { Self::new_unchecked(buf) })
98    }
99    /// Assumes the underlying data is initialized.
100    ///
101    /// # Safety
102    ///
103    /// `T` bytes must have been properly initialized.
104    pub unsafe fn assume_init(self) -> Typed<T, Buf> {
105        Typed {
106            buf: self.buf,
107            _phantom: PhantomData,
108        }
109    }
110
111    /// Initializes the underlying data.
112    pub fn initialize(mut self, value: T) -> Typed<T, Buf>
113    where
114        Buf: ShmBufMut<[u8]>,
115    {
116        // SAFETY: this is safe because we check transmute safety when constructing self
117        unsafe { self.buf.as_mut().as_mut_ptr().cast::<T>().write(value) };
118        // SAFETY: the data has been initialized
119        unsafe { self.assume_init() }
120    }
121}
122
123impl<T> From<Typed<T, ZShmMut>> for Typed<T, ZShm> {
124    fn from(value: Typed<T, ZShmMut>) -> Self {
125        Self {
126            buf: value.buf.into(),
127            _phantom: PhantomData,
128        }
129    }
130}
131
132impl<T> TryFrom<Typed<T, ZShm>> for Typed<T, ZShmMut> {
133    type Error = Typed<T, ZShm>;
134
135    fn try_from(value: Typed<T, ZShm>) -> Result<Self, Self::Error> {
136        Ok(Self {
137            buf: value.buf.try_into().map_err(|e| Typed::<T, ZShm> {
138                buf: e,
139                _phantom: PhantomData,
140            })?,
141            _phantom: PhantomData,
142        })
143    }
144}
145
146impl<'a, T> TryFrom<Typed<T, &'a zshm>> for Typed<T, &'a zshmmut> {
147    type Error = ();
148
149    fn try_from(value: Typed<T, &'a zshm>) -> Result<Self, Self::Error> {
150        Ok(Self {
151            buf: value.buf.try_into()?,
152            _phantom: PhantomData,
153        })
154    }
155}
156
157impl<'a, T> TryFrom<Typed<T, &'a mut zshm>> for Typed<T, &'a mut zshmmut> {
158    type Error = ();
159
160    fn try_from(value: Typed<T, &'a mut zshm>) -> Result<Self, Self::Error> {
161        Ok(Self {
162            buf: value.buf.try_into()?,
163            _phantom: PhantomData,
164        })
165    }
166}
167
168impl<'a, T> TryFrom<Typed<T, &'a mut ZShm>> for Typed<T, &'a mut zshmmut> {
169    type Error = ();
170
171    fn try_from(value: Typed<T, &'a mut ZShm>) -> Result<Self, Self::Error> {
172        Ok(Self {
173            buf: value.buf.try_into()?,
174            _phantom: PhantomData,
175        })
176    }
177}
178
179impl<T> From<Typed<T, &zshmmut>> for Typed<T, &zshm> {
180    fn from(value: Typed<T, &zshmmut>) -> Self {
181        Self {
182            buf: value.buf.into(),
183            _phantom: PhantomData,
184        }
185    }
186}
187
188impl<T> From<Typed<T, &mut zshmmut>> for Typed<T, &mut zshm> {
189    fn from(value: Typed<T, &mut zshmmut>) -> Self {
190        Self {
191            buf: value.buf.into(),
192            _phantom: PhantomData,
193        }
194    }
195}
196
197impl<T: ResideInShm, Buf: ShmBuf<[u8]>> Deref for Typed<T, Buf> {
198    type Target = T;
199
200    fn deref(&self) -> &Self::Target {
201        // SAFETY: this is safe because we check transmute safety when constructing self
202        unsafe { &*(self.buf.as_ref().as_ptr() as *const T) }
203    }
204}
205
206impl<T: ResideInShm, Buf: ShmBuf<[u8]>> AsRef<T> for Typed<T, Buf> {
207    fn as_ref(&self) -> &T {
208        self
209    }
210}
211
212impl<T: ResideInShm, Buf: ShmBufMut<[u8]>> DerefMut for Typed<T, Buf> {
213    fn deref_mut(&mut self) -> &mut Self::Target {
214        // SAFETY: this is safe because we check transmute safety when constructing self
215        unsafe { &mut *(self.buf.as_mut().as_mut_ptr() as *mut T) }
216    }
217}
218
219impl<T: ResideInShm, Buf: ShmBufMut<[u8]>> AsMut<T> for Typed<T, Buf> {
220    fn as_mut(&mut self) -> &mut T {
221        self
222    }
223}
224
225impl<T: ResideInShm, Buf: ShmBuf<[u8]>> ShmBuf<T> for Typed<T, Buf> {
226    fn is_valid(&self) -> bool {
227        self.buf.is_valid()
228    }
229}
230
231impl<T: ResideInShm, Buf: ShmBufMut<[u8]>> ShmBufMut<T> for Typed<T, Buf> {}
232
233impl<T: ResideInShm, Buf: ShmBufUnsafeMut<[u8]>> ShmBufUnsafeMut<T> for Typed<T, Buf> {
234    unsafe fn as_mut_unchecked(&mut self) -> &mut T {
235        &mut *(self.buf.as_mut_unchecked().as_mut_ptr() as *mut T)
236    }
237}
238
239impl<T: ResideInShm, Buf: ShmBufIntoImmut<[u8]>> ShmBufIntoImmut<T> for Typed<T, Buf> {
240    type ImmutBuf = Typed<T, Buf::ImmutBuf>;
241
242    fn into_immut(self) -> Self::ImmutBuf {
243        Typed {
244            buf: self.buf.into_immut(),
245            _phantom: PhantomData,
246        }
247    }
248}