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> {}