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}