ptr_utils/unaligned/
read.rs

1//! Unaligned read operations for pointer types.
2
3/// Trait providing convenient unaligned read operations for pointer types.
4///
5/// This trait eliminates the need for explicit casts when reading from
6/// typed pointers (e.g., `*const u32`, `*mut u16`) by providing methods that handle
7/// the casting internally.
8pub trait UnalignedRead {
9    // Unsigned integer types
10
11    /// Reads a [`u8`] value from the pointer at the given byte offset.
12    ///
13    /// # Safety
14    /// - The pointer plus byte offset must be valid for reading 1 byte
15    /// - The caller must ensure the pointer remains valid for the duration of the read
16    unsafe fn read_u8_at(self, byte_offset: usize) -> u8;
17
18    /// Reads a [`u16`] value from the pointer at the given byte offset.
19    ///
20    /// # Safety
21    /// - The pointer plus byte offset must be valid for reading 2 bytes
22    /// - The caller must ensure the pointer remains valid for the duration of the read
23    /// - No alignment requirements - this performs unaligned reads
24    unsafe fn read_u16_at(self, byte_offset: usize) -> u16;
25
26    /// Reads a [`u32`] value from the pointer at the given byte offset.
27    ///
28    /// # Safety
29    /// - The pointer plus byte offset must be valid for reading 4 bytes
30    /// - The caller must ensure the pointer remains valid for the duration of the read
31    /// - No alignment requirements - this performs unaligned reads
32    unsafe fn read_u32_at(self, byte_offset: usize) -> u32;
33
34    /// Reads a [`u64`] value from the pointer at the given byte offset.
35    ///
36    /// # Safety
37    /// - The pointer plus byte offset must be valid for reading 8 bytes
38    /// - The caller must ensure the pointer remains valid for the duration of the read
39    /// - No alignment requirements - this performs unaligned reads
40    unsafe fn read_u64_at(self, byte_offset: usize) -> u64;
41
42    /// Reads a [`u128`] value from the pointer at the given byte offset.
43    ///
44    /// # Safety
45    /// - The pointer plus byte offset must be valid for reading 16 bytes
46    /// - The caller must ensure the pointer remains valid for the duration of the read
47    /// - No alignment requirements - this performs unaligned reads
48    unsafe fn read_u128_at(self, byte_offset: usize) -> u128;
49
50    /// Reads a [`usize`] value from the pointer at the given byte offset.
51    ///
52    /// # Safety
53    /// - The pointer plus byte offset must be valid for reading [`size_of::<usize>()`] bytes
54    /// - The caller must ensure the pointer remains valid for the duration of the read
55    /// - No alignment requirements - this performs unaligned reads
56    unsafe fn read_usize_at(self, byte_offset: usize) -> usize;
57
58    // Signed integer types
59
60    /// Reads an [`i8`] value from the pointer at the given byte offset.
61    ///
62    /// # Safety
63    /// - The pointer plus byte offset must be valid for reading 1 byte
64    /// - The caller must ensure the pointer remains valid for the duration of the read
65    unsafe fn read_i8_at(self, byte_offset: usize) -> i8;
66
67    /// Reads an [`i16`] value from the pointer at the given byte offset.
68    ///
69    /// # Safety
70    /// - The pointer plus byte offset must be valid for reading 2 bytes
71    /// - The caller must ensure the pointer remains valid for the duration of the read
72    /// - No alignment requirements - this performs unaligned reads
73    unsafe fn read_i16_at(self, byte_offset: usize) -> i16;
74
75    /// Reads an [`i32`] value from the pointer at the given byte offset.
76    ///
77    /// # Safety
78    /// - The pointer plus byte offset must be valid for reading 4 bytes
79    /// - The caller must ensure the pointer remains valid for the duration of the read
80    /// - No alignment requirements - this performs unaligned reads
81    unsafe fn read_i32_at(self, byte_offset: usize) -> i32;
82
83    /// Reads an [`i64`] value from the pointer at the given byte offset.
84    ///
85    /// # Safety
86    /// - The pointer plus byte offset must be valid for reading 8 bytes
87    /// - The caller must ensure the pointer remains valid for the duration of the read
88    /// - No alignment requirements - this performs unaligned reads
89    unsafe fn read_i64_at(self, byte_offset: usize) -> i64;
90
91    /// Reads an [`i128`] value from the pointer at the given byte offset.
92    ///
93    /// # Safety
94    /// - The pointer plus byte offset must be valid for reading 16 bytes
95    /// - The caller must ensure the pointer remains valid for the duration of the read
96    /// - No alignment requirements - this performs unaligned reads
97    unsafe fn read_i128_at(self, byte_offset: usize) -> i128;
98
99    /// Reads an [`isize`] value from the pointer at the given byte offset.
100    ///
101    /// # Safety
102    /// - The pointer plus byte offset must be valid for reading [`size_of::<isize>()`] bytes
103    /// - The caller must ensure the pointer remains valid for the duration of the read
104    /// - No alignment requirements - this performs unaligned reads
105    unsafe fn read_isize_at(self, byte_offset: usize) -> isize;
106
107    // Floating point types
108
109    /// Reads an [`f32`] value from the pointer at the given byte offset.
110    ///
111    /// # Safety
112    /// - The pointer plus byte offset must be valid for reading 4 bytes
113    /// - The caller must ensure the pointer remains valid for the duration of the read
114    /// - No alignment requirements - this performs unaligned reads
115    unsafe fn read_f32_at(self, byte_offset: usize) -> f32;
116
117    /// Reads an [`f64`] value from the pointer at the given byte offset.
118    ///
119    /// # Safety
120    /// - The pointer plus byte offset must be valid for reading 8 bytes
121    /// - The caller must ensure the pointer remains valid for the duration of the read
122    /// - No alignment requirements - this performs unaligned reads
123    unsafe fn read_f64_at(self, byte_offset: usize) -> f64;
124
125    // Boolean type
126
127    /// Reads a [`bool`] value from the pointer at the given byte offset.
128    ///
129    /// # Safety
130    /// - The pointer plus byte offset must be valid for reading 1 byte
131    /// - The caller must ensure the pointer remains valid for the duration of the read
132    /// - The byte value must represent a valid [`bool`] (0 or 1)
133    unsafe fn read_bool_at(self, byte_offset: usize) -> bool;
134}
135
136// Implementations for const pointers
137impl<T> UnalignedRead for *const T {
138    #[inline(always)]
139    unsafe fn read_u8_at(self, byte_offset: usize) -> u8 {
140        (self as *const u8).add(byte_offset).read_unaligned()
141    }
142
143    #[inline(always)]
144    unsafe fn read_u16_at(self, byte_offset: usize) -> u16 {
145        ((self as *const u8).add(byte_offset) as *const u16).read_unaligned()
146    }
147
148    #[inline(always)]
149    unsafe fn read_u32_at(self, byte_offset: usize) -> u32 {
150        ((self as *const u8).add(byte_offset) as *const u32).read_unaligned()
151    }
152
153    #[inline(always)]
154    unsafe fn read_u64_at(self, byte_offset: usize) -> u64 {
155        ((self as *const u8).add(byte_offset) as *const u64).read_unaligned()
156    }
157
158    #[inline(always)]
159    unsafe fn read_u128_at(self, byte_offset: usize) -> u128 {
160        ((self as *const u8).add(byte_offset) as *const u128).read_unaligned()
161    }
162
163    #[inline(always)]
164    unsafe fn read_usize_at(self, byte_offset: usize) -> usize {
165        ((self as *const u8).add(byte_offset) as *const usize).read_unaligned()
166    }
167
168    #[inline(always)]
169    unsafe fn read_i8_at(self, byte_offset: usize) -> i8 {
170        ((self as *const u8).add(byte_offset) as *const i8).read_unaligned()
171    }
172
173    #[inline(always)]
174    unsafe fn read_i16_at(self, byte_offset: usize) -> i16 {
175        ((self as *const u8).add(byte_offset) as *const i16).read_unaligned()
176    }
177
178    #[inline(always)]
179    unsafe fn read_i32_at(self, byte_offset: usize) -> i32 {
180        ((self as *const u8).add(byte_offset) as *const i32).read_unaligned()
181    }
182
183    #[inline(always)]
184    unsafe fn read_i64_at(self, byte_offset: usize) -> i64 {
185        ((self as *const u8).add(byte_offset) as *const i64).read_unaligned()
186    }
187
188    #[inline(always)]
189    unsafe fn read_i128_at(self, byte_offset: usize) -> i128 {
190        ((self as *const u8).add(byte_offset) as *const i128).read_unaligned()
191    }
192
193    #[inline(always)]
194    unsafe fn read_isize_at(self, byte_offset: usize) -> isize {
195        ((self as *const u8).add(byte_offset) as *const isize).read_unaligned()
196    }
197
198    #[inline(always)]
199    unsafe fn read_f32_at(self, byte_offset: usize) -> f32 {
200        ((self as *const u8).add(byte_offset) as *const f32).read_unaligned()
201    }
202
203    #[inline(always)]
204    unsafe fn read_f64_at(self, byte_offset: usize) -> f64 {
205        ((self as *const u8).add(byte_offset) as *const f64).read_unaligned()
206    }
207
208    #[inline(always)]
209    unsafe fn read_bool_at(self, byte_offset: usize) -> bool {
210        ((self as *const u8).add(byte_offset) as *const bool).read_unaligned()
211    }
212}
213
214// Implementations for mutable pointers (read operations)
215impl<T> UnalignedRead for *mut T {
216    #[inline(always)]
217    unsafe fn read_u8_at(self, byte_offset: usize) -> u8 {
218        (self as *const u8).add(byte_offset).read_unaligned()
219    }
220
221    #[inline(always)]
222    unsafe fn read_u16_at(self, byte_offset: usize) -> u16 {
223        ((self as *const u8).add(byte_offset) as *const u16).read_unaligned()
224    }
225
226    #[inline(always)]
227    unsafe fn read_u32_at(self, byte_offset: usize) -> u32 {
228        ((self as *const u8).add(byte_offset) as *const u32).read_unaligned()
229    }
230
231    #[inline(always)]
232    unsafe fn read_u64_at(self, byte_offset: usize) -> u64 {
233        ((self as *const u8).add(byte_offset) as *const u64).read_unaligned()
234    }
235
236    #[inline(always)]
237    unsafe fn read_u128_at(self, byte_offset: usize) -> u128 {
238        ((self as *const u8).add(byte_offset) as *const u128).read_unaligned()
239    }
240
241    #[inline(always)]
242    unsafe fn read_usize_at(self, byte_offset: usize) -> usize {
243        ((self as *const u8).add(byte_offset) as *const usize).read_unaligned()
244    }
245
246    #[inline(always)]
247    unsafe fn read_i8_at(self, byte_offset: usize) -> i8 {
248        ((self as *const u8).add(byte_offset) as *const i8).read_unaligned()
249    }
250
251    #[inline(always)]
252    unsafe fn read_i16_at(self, byte_offset: usize) -> i16 {
253        ((self as *const u8).add(byte_offset) as *const i16).read_unaligned()
254    }
255
256    #[inline(always)]
257    unsafe fn read_i32_at(self, byte_offset: usize) -> i32 {
258        ((self as *const u8).add(byte_offset) as *const i32).read_unaligned()
259    }
260
261    #[inline(always)]
262    unsafe fn read_i64_at(self, byte_offset: usize) -> i64 {
263        ((self as *const u8).add(byte_offset) as *const i64).read_unaligned()
264    }
265
266    #[inline(always)]
267    unsafe fn read_i128_at(self, byte_offset: usize) -> i128 {
268        ((self as *const u8).add(byte_offset) as *const i128).read_unaligned()
269    }
270
271    #[inline(always)]
272    unsafe fn read_isize_at(self, byte_offset: usize) -> isize {
273        ((self as *const u8).add(byte_offset) as *const isize).read_unaligned()
274    }
275
276    #[inline(always)]
277    unsafe fn read_f32_at(self, byte_offset: usize) -> f32 {
278        ((self as *const u8).add(byte_offset) as *const f32).read_unaligned()
279    }
280
281    #[inline(always)]
282    unsafe fn read_f64_at(self, byte_offset: usize) -> f64 {
283        ((self as *const u8).add(byte_offset) as *const f64).read_unaligned()
284    }
285
286    #[inline(always)]
287    unsafe fn read_bool_at(self, byte_offset: usize) -> bool {
288        ((self as *const u8).add(byte_offset) as *const bool).read_unaligned()
289    }
290}