ps_mbuf/
lib.rs

1/// A memory buffer with associated metadata.
2///
3/// `Mbuf` is a fixed memory layout consisting of:
4/// 1. Metadata of type `M`
5/// 2. A `usize` length field
6/// 3. Data elements of type `D` stored directly after in memory
7///
8/// The buffer dereferences to `&[D]` via pointer arithmetic aligned to the data region.
9///
10/// **Important:** The data region must be allocated contiguously in memory immediately after this struct.
11/// Callers are responsible for upholding this invariant.
12#[repr(C)]
13pub struct Mbuf<'lt, M, D> {
14    metadata: M,
15    length: usize,
16    _marker: std::marker::PhantomData<&'lt D>,
17}
18
19impl<M: MbufValue, D: MbufValue> Mbuf<'_, M, D> {
20    /// Returns an immutable slice view of the buffer data.
21    pub fn to_slice(&self) -> &[D] {
22        self
23    }
24
25    /// Returns a mutable slice view of the buffer data.
26    pub fn to_slice_mut(&mut self) -> &mut [D] {
27        &mut *self
28    }
29
30    /// Returns a reference to the metadata.
31    pub const fn get_metadata(&self) -> &M {
32        &self.metadata
33    }
34
35    /// Sets the metadata and returns the previous value.
36    pub const fn set_metadata(&mut self, metadata: M) -> M {
37        std::mem::replace(&mut self.metadata, metadata)
38    }
39
40    /// Returns `true` if the buffer is empty.
41    pub const fn is_empty(&self) -> bool {
42        self.len() == 0
43    }
44
45    /// Returns the number of elements in the buffer.
46    pub const fn len(&self) -> usize {
47        self.length
48    }
49}
50
51impl<'lt, M: MbufValue, D: MbufValue> Mbuf<'lt, M, D> {
52    /// Interprets a pointer as an `Mbuf` with immutable access.
53    ///
54    /// # Safety
55    ///
56    /// - `pointer` must point to a valid, initialized `Mbuf<'lt, M, D>`.
57    /// - The `Mbuf` and its data must be valid for the lifetime `'lt`.
58    #[must_use]
59    pub const unsafe fn at_ptr(pointer: *const u8) -> &'lt Self {
60        &*pointer.cast::<Mbuf<'lt, M, D>>()
61    }
62
63    /// Interprets a pointer as an `Mbuf` with mutable access.
64    ///
65    /// # Safety
66    ///
67    /// - `pointer` must point to a valid, initialized `Mbuf<'lt, M, D>` in writable memory.
68    /// - The `Mbuf` and its data must be valid for the lifetime `'lt`.
69    pub unsafe fn at_ptr_mut(pointer: *mut u8) -> &'lt mut Self {
70        &mut *pointer.cast::<Mbuf<'lt, M, D>>()
71    }
72
73    /// Interprets a byte offset from a pointer as an `Mbuf` with immutable access.
74    ///
75    /// # Safety
76    ///
77    /// - `pointer.add(offset)` must point to a valid, initialized `Mbuf<'lt, M, D>`.
78    /// - The `Mbuf` and its data must be valid for the lifetime `'lt`.
79    #[must_use]
80    pub const unsafe fn at_offset(pointer: *const u8, offset: usize) -> &'lt Self {
81        &*(pointer.add(offset)).cast::<Mbuf<'lt, M, D>>()
82    }
83
84    /// Interprets a byte offset from a pointer as an `Mbuf` with mutable access.
85    ///
86    /// # Safety
87    ///
88    /// - `pointer.add(offset)` must point to a valid, initialized `Mbuf<'lt, M, D>` in writable memory.
89    /// - The `Mbuf` and its data must be valid for the lifetime `'lt`.
90    pub unsafe fn at_offset_mut(pointer: *mut u8, offset: usize) -> &'lt mut Self {
91        &mut *(pointer.add(offset)).cast::<Mbuf<'lt, M, D>>()
92    }
93
94    /// Initializes an `Mbuf` at a pointer without initializing data.
95    ///
96    /// Sets the metadata and length fields. **The caller must initialize the data region before access.**
97    ///
98    /// # Safety
99    ///
100    /// - `pointer` must point to writable memory large enough to hold `Mbuf<'lt, M, D>` plus `length` elements of type `D`.
101    /// - `pointer` must be aligned as an `Mbuf<'lt, M, D>`.
102    /// - The entire buffer region must be valid for the lifetime `'lt`.
103    pub unsafe fn init_at_ptr(pointer: *mut u8, metadata: M, length: usize) -> &'lt mut Self {
104        let mbuf = Mbuf::at_ptr_mut(pointer);
105
106        mbuf.metadata = metadata;
107        mbuf.length = length;
108
109        mbuf
110    }
111
112    /// Initializes an `Mbuf` at a byte offset from a pointer without initializing data.
113    ///
114    /// Sets the metadata and length fields. **The caller must initialize the data region before access.**
115    ///
116    /// # Safety
117    ///
118    /// - `pointer.add(offset)` must point to writable memory large enough to hold `Mbuf<'lt, M, D>` plus `length` elements of type `D`.
119    /// - `pointer.add(offset)` must be aligned as an `Mbuf<'lt, M, D>`.
120    /// - The entire buffer region must be valid for the lifetime `'lt`.
121    pub unsafe fn init_at_offset(
122        pointer: *mut u8,
123        offset: usize,
124        metadata: M,
125        length: usize,
126    ) -> &'lt mut Self {
127        Self::init_at_ptr(pointer.add(offset), metadata, length)
128    }
129}
130
131impl<'lt, M: MbufValue, D: Copy> Mbuf<'lt, M, D> {
132    /// Initializes an `Mbuf` at a pointer and copies data into it.
133    ///
134    /// # Safety
135    ///
136    /// - `pointer` must point to writable memory large enough to hold the `Mbuf` header plus `data.len()` elements of type `D`.
137    /// - `pointer` must be aligned as an `Mbuf<'lt, M, D>`.
138    /// - The entire buffer region must be valid for the lifetime `'lt`.
139    pub unsafe fn write_to_ptr(pointer: *mut u8, metadata: M, data: &[D]) -> &'lt Self {
140        Mbuf::write_to_ptr_mut(pointer, metadata, data)
141    }
142
143    /// Initializes a mutable `Mbuf` at a pointer and copies data into it.
144    ///
145    /// # Safety
146    ///
147    /// - `pointer` must point to writable memory large enough to hold the `Mbuf` header plus `data.len()` elements of type `D`.
148    /// - `pointer` must be aligned as an `Mbuf<'lt, M, D>`.
149    /// - The entire buffer region must be valid for the lifetime `'lt`.
150    pub unsafe fn write_to_ptr_mut(pointer: *mut u8, metadata: M, data: &[D]) -> &'lt mut Self {
151        let mbuf = Mbuf::init_at_ptr(pointer, metadata, data.len());
152
153        mbuf.copy_from_slice(data);
154
155        mbuf
156    }
157
158    /// Initializes an `Mbuf` at a byte offset from a pointer and copies data into it.
159    ///
160    /// # Safety
161    ///
162    /// - `pointer.add(offset)` must point to writable memory large enough to hold the `Mbuf` header plus `data.len()` elements of type `D`.
163    /// - `pointer.add(offset)` must be aligned as an `Mbuf<'lt, M, D>`.
164    /// - The entire buffer region must be valid for the lifetime `'lt`.
165    pub unsafe fn write_to_offset(
166        pointer: *mut u8,
167        offset: usize,
168        metadata: M,
169        data: &[D],
170    ) -> &'lt Self {
171        Mbuf::write_to_offset_mut(pointer, offset, metadata, data)
172    }
173
174    /// Initializes a mutable `Mbuf` at a byte offset from a pointer and copies data into it.
175    ///
176    /// # Safety
177    ///
178    /// - `pointer.add(offset)` must point to writable memory large enough to hold the `Mbuf` header plus `data.len()` elements of type `D`.
179    /// - `pointer.add(offset)` must be aligned as an `Mbuf<'lt, M, D>`.
180    /// - The entire buffer region must be valid for the lifetime `'lt`.
181    pub unsafe fn write_to_offset_mut(
182        pointer: *mut u8,
183        offset: usize,
184        metadata: M,
185        data: &[D],
186    ) -> &'lt mut Self {
187        Mbuf::write_to_ptr_mut(pointer.add(offset), metadata, data)
188    }
189}
190
191impl<M: MbufValue, D: MbufValue> AsRef<[D]> for Mbuf<'_, M, D> {
192    fn as_ref(&self) -> &[D] {
193        self
194    }
195}
196
197impl<M: MbufValue, D: MbufValue> AsMut<[D]> for Mbuf<'_, M, D> {
198    fn as_mut(&mut self) -> &mut [D] {
199        self
200    }
201}
202
203impl<M: MbufValue, D: MbufValue> std::ops::Deref for Mbuf<'_, M, D> {
204    type Target = [D];
205
206    fn deref(&self) -> &Self::Target {
207        let ptr: *const Self = self;
208        let address = ptr as usize + std::mem::size_of::<Self>();
209
210        unsafe { std::slice::from_raw_parts(align::<D>(address), self.length) }
211    }
212}
213
214impl<M: MbufValue, D: MbufValue> std::ops::DerefMut for Mbuf<'_, M, D> {
215    fn deref_mut(&mut self) -> &mut Self::Target {
216        let ptr: *const Self = self;
217        let address = ptr as usize + std::mem::size_of::<Self>();
218
219        unsafe { std::slice::from_raw_parts_mut(align::<D>(address).cast_mut(), self.length) }
220    }
221}
222
223/// Aligns an address up to the required alignment for type `T`.
224///
225/// Returns the aligned address as a const pointer. If already aligned, returns unchanged.
226const fn align<T>(address: usize) -> *const T {
227    let align_size = std::mem::align_of::<T>();
228    let remainder = address % align_size;
229
230    if remainder == 0 {
231        address as *const T
232    } else {
233        (address + align_size - remainder) as *const T
234    }
235}
236
237pub trait MbufValue {}
238
239impl<T> MbufValue for T where T: Copy {}
240
241impl<M, D> MbufValue for Mbuf<'_, M, D> {}