zenoh_shm/api/provider/
memory_layout.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::{fmt::Display, marker::PhantomData, mem, num::NonZeroUsize};
16
17use crate::api::provider::types::{AllocAlignment, ZLayoutError};
18
19/// Memory layout representation: alignment and size aligned for this alignment
20#[zenoh_macros::unstable_doc]
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct MemoryLayout {
23    size: NonZeroUsize,
24    alignment: AllocAlignment,
25}
26
27impl From<&MemoryLayout> for MemoryLayout {
28    fn from(other: &MemoryLayout) -> Self {
29        *other
30    }
31}
32
33impl Display for MemoryLayout {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        f.write_fmt(format_args!(
36            "[size={},alignment={}]",
37            self.size, self.alignment
38        ))
39    }
40}
41
42impl MemoryLayout {
43    /// Try to create a new memory layout.
44    ///
45    /// # Errors
46    ///
47    /// This function will return an error if zero size have passed or if the provided size is not the multiply of the alignment.
48    #[zenoh_macros::unstable_doc]
49    pub fn new<T>(size: T, alignment: AllocAlignment) -> Result<Self, ZLayoutError>
50    where
51        T: TryInto<NonZeroUsize>,
52    {
53        let Ok(size) = size.try_into() else {
54            return Err(ZLayoutError::IncorrectLayoutArgs);
55        };
56
57        // size of a layout must be a multiple of its alignment!
58        match size.get() % alignment.get_alignment_value() {
59            0 => Ok(Self { size, alignment }),
60            _ => Err(ZLayoutError::IncorrectLayoutArgs),
61        }
62    }
63
64    /// #SAFETY: this is safe if size is a multiply of alignment
65    /// Note: not intended for public APIs as it is really very unsafe
66    const unsafe fn new_unchecked(size: NonZeroUsize, alignment: AllocAlignment) -> Self {
67        Self { size, alignment }
68    }
69
70    /// Creates a new `MemoryLayout` for type.
71    #[allow(path_statements)]
72    #[zenoh_macros::unstable_doc]
73    pub const fn for_type<T: Sized>() -> Self {
74        struct ZstCheck<T>(PhantomData<T>);
75        impl<T> ZstCheck<T> {
76            const NOT_ZST: () = assert!(mem::size_of::<T>() != 0, "`T` must not be a ZST");
77        }
78        ZstCheck::<T>::NOT_ZST;
79        // SAFETY: invariant checked above
80        let size = unsafe { NonZeroUsize::new_unchecked(mem::size_of::<T>()) };
81        let alignment = AllocAlignment::for_type::<T>();
82        unsafe { Self::new_unchecked(size, alignment) }
83    }
84
85    /// Creates a new `MemoryLayout` for value type.
86    #[zenoh_macros::unstable_doc]
87    pub const fn for_value<T: Sized>(_: &T) -> Self {
88        Self::for_type::<T>()
89    }
90
91    #[zenoh_macros::unstable_doc]
92    pub fn size(&self) -> NonZeroUsize {
93        self.size
94    }
95
96    #[zenoh_macros::unstable_doc]
97    pub fn alignment(&self) -> AllocAlignment {
98        self.alignment
99    }
100
101    /// Realign the layout for new alignment. The alignment must be >= of the existing one.
102    /// # Examples
103    ///
104    /// ```
105    /// use zenoh_shm::api::provider::types::AllocAlignment;
106    /// use zenoh_shm::api::provider::memory_layout::MemoryLayout;
107    ///
108    /// // 8 bytes with 4-byte alignment
109    /// let layout4b = MemoryLayout::new(8, AllocAlignment::new(2).unwrap()).unwrap();
110    ///
111    /// // Try to realign with 2-byte alignment
112    /// let layout2b = layout4b.extend(AllocAlignment::new(1).unwrap());
113    /// assert!(layout2b.is_err()); // fails because new alignment must be >= old
114    ///
115    /// // Try to realign with 8-byte alignment
116    /// let layout8b = layout4b.extend(AllocAlignment::new(3).unwrap());
117    /// assert!(layout8b.is_ok()); // ok
118    /// ```
119    #[zenoh_macros::unstable_doc]
120    pub fn extend(&self, new_alignment: AllocAlignment) -> Result<MemoryLayout, ZLayoutError> {
121        if new_alignment < self.alignment {
122            return Err(ZLayoutError::IncorrectLayoutArgs);
123        }
124        let new_size = new_alignment.align_size(self.size);
125        MemoryLayout::new(new_size, new_alignment)
126    }
127}
128
129impl TryFrom<NonZeroUsize> for MemoryLayout {
130    type Error = ZLayoutError;
131
132    fn try_from(value: NonZeroUsize) -> Result<Self, Self::Error> {
133        MemoryLayout::new(value, AllocAlignment::ALIGN_1_BYTE)
134    }
135}
136
137impl TryFrom<usize> for MemoryLayout {
138    type Error = ZLayoutError;
139
140    fn try_from(value: usize) -> Result<Self, Self::Error> {
141        MemoryLayout::new(value, AllocAlignment::ALIGN_1_BYTE)
142    }
143}
144
145impl TryFrom<(NonZeroUsize, AllocAlignment)> for MemoryLayout {
146    type Error = ZLayoutError;
147
148    fn try_from(value: (NonZeroUsize, AllocAlignment)) -> Result<Self, Self::Error> {
149        MemoryLayout::new(value.0, value.1)
150    }
151}
152
153impl TryFrom<(usize, AllocAlignment)> for MemoryLayout {
154    type Error = ZLayoutError;
155
156    fn try_from(value: (usize, AllocAlignment)) -> Result<Self, Self::Error> {
157        MemoryLayout::new(value.0, value.1)
158    }
159}
160
161/// A statically-known layout with type information.
162///
163/// Used in context of typed operations.
164///
165/// Statically-known layouts are always correct, zero-sized & zero-cost.
166#[zenoh_macros::unstable_doc]
167pub struct TypedLayout<T> {
168    _phantom: PhantomData<T>,
169}
170
171impl<T> Default for TypedLayout<T> {
172    fn default() -> Self {
173        Self::new()
174    }
175}
176
177impl<T> TypedLayout<T> {
178    /// Creates a new `TypedLayout` for type
179    #[zenoh_macros::unstable_doc]
180    pub fn new() -> Self {
181        Self {
182            _phantom: PhantomData,
183        }
184    }
185
186    /// Creates a new `TypedLayout` for value type
187    #[zenoh_macros::unstable_doc]
188    pub fn for_value(_: &T) -> Self {
189        Self::new()
190    }
191}
192
193impl<T> Clone for TypedLayout<T> {
194    fn clone(&self) -> Self {
195        *self
196    }
197}
198
199impl<T> Copy for TypedLayout<T> {}