1use core::{mem, ops, ptr, slice};
2use super::*;
3
4#[repr(transparent)]
58pub struct DataView {
59 bytes: [u8],
60}
61
62impl DataView {
63 #[inline]
65 pub fn from<T: ?Sized + Pod>(v: &T) -> &DataView {
66 unsafe { mem::transmute(bytes(v)) }
67 }
68 #[inline]
70 pub fn from_mut<T: ?Sized + Pod>(v: &mut T) -> &mut DataView {
71 unsafe { mem::transmute(bytes_mut(v)) }
72 }
73}
74
75unsafe impl Pod for DataView {}
76
77impl AsRef<[u8]> for DataView {
78 #[inline]
79 fn as_ref(&self) -> &[u8] {
80 &self.bytes
81 }
82}
83impl AsMut<[u8]> for DataView {
84 #[inline]
85 fn as_mut(&mut self) -> &mut [u8] {
86 &mut self.bytes
87 }
88}
89
90impl DataView {
91 #[inline]
93 pub const fn len(&self) -> usize {
94 self.bytes.len()
95 }
96 #[inline]
98 pub const fn tail_len<T>(&self, offset: usize) -> usize {
99 (self.bytes.len() - offset) / mem::size_of::<T>()
100 }
101}
102
103impl DataView {
107 #[inline]
109 pub fn try_read<T: Pod>(&self, offset: usize) -> Option<T> {
110 let index = offset..offset + mem::size_of::<T>();
111 let bytes = self.bytes.get(index)?;
112 unsafe {
113 let src = bytes.as_ptr() as *const T;
114 Some(ptr::read_unaligned(src))
115 }
116 }
117 #[track_caller]
119 #[inline]
120 pub fn read<T: Pod>(&self, offset: usize) -> T {
121 match self.try_read(offset) {
122 Some(value) => value,
123 None => invalid_offset(),
124 }
125 }
126 #[inline]
128 pub unsafe fn read_unchecked<T: Pod>(&self, offset: usize) -> T {
129 let index = offset..offset + mem::size_of::<T>();
130 let bytes = self.bytes.get_unchecked(index);
131 let src = bytes.as_ptr() as *const T;
132 ptr::read_unaligned(src)
133 }
134}
135
136impl DataView {
140 #[inline]
142 pub fn try_read_into<T: ?Sized + Pod>(&self, offset: usize, dest: &mut T) -> Option<()> {
143 let index = offset..offset + mem::size_of_val(dest);
144 let bytes = self.bytes.get(index)?;
145 unsafe {
146 let src = bytes.as_ptr();
147 let dst = bytes_mut(dest).as_mut_ptr();
148 ptr::copy_nonoverlapping(src, dst, bytes.len());
149 Some(())
150 }
151 }
152 #[track_caller]
154 #[inline]
155 pub fn read_into<T: ?Sized + Pod>(&self, offset: usize, dest: &mut T) {
156 match self.try_read_into(offset, dest) {
157 Some(()) => (),
158 None => invalid_offset(),
159 }
160 }
161 #[inline]
163 pub unsafe fn read_into_unchecked<T: ?Sized + Pod>(&self, offset: usize, dest: &mut T) {
164 let index = offset..offset + mem::size_of_val(dest);
165 let bytes = self.bytes.get_unchecked(index);
166 let src = bytes.as_ptr();
167 let dst = bytes_mut(dest).as_mut_ptr();
168 ptr::copy_nonoverlapping(src, dst, bytes.len());
169 }
170}
171
172impl DataView {
176 #[inline]
178 pub fn try_get<T: Pod>(&self, offset: usize) -> Option<&T> {
179 let index = offset..offset + mem::size_of::<T>();
180 let bytes = self.bytes.get(index)?;
181 let unaligned_ptr = bytes.as_ptr() as *const T;
182 if !is_aligned(unaligned_ptr) {
183 return None;
184 }
185 unsafe {
186 Some(&*unaligned_ptr)
187 }
188 }
189 #[track_caller]
191 #[inline]
192 pub fn get<T: Pod>(&self, offset: usize) -> &T {
193 match self.try_get(offset) {
194 Some(value) => value,
195 None => invalid_offset(),
196 }
197 }
198 #[inline]
200 pub unsafe fn get_unchecked<T: Pod>(&self, offset: usize) -> &T {
201 let index = offset..offset + mem::size_of::<T>();
202 let bytes = self.bytes.get_unchecked(index);
203 &*(bytes.as_ptr() as *const T)
204 }
205}
206
207impl DataView {
211 #[inline]
213 pub fn try_get_mut<T: Pod>(&mut self, offset: usize) -> Option<&mut T> {
214 let index = offset..offset + mem::size_of::<T>();
215 let bytes = self.bytes.get_mut(index)?;
216 let unaligned_ptr = bytes.as_mut_ptr() as *mut T;
217 if !is_aligned(unaligned_ptr) {
218 return None;
219 }
220 unsafe {
221 Some(&mut *unaligned_ptr)
222 }
223 }
224 #[track_caller]
226 #[inline]
227 pub fn get_mut<T: Pod>(&mut self, offset: usize) -> &mut T {
228 match self.try_get_mut(offset) {
229 Some(value) => value,
230 None => invalid_offset(),
231 }
232 }
233 #[inline]
235 pub unsafe fn get_unchecked_mut<T: Pod>(&mut self, offset: usize) -> &mut T {
236 let index = offset..offset + mem::size_of::<T>();
237 let bytes = self.bytes.get_unchecked_mut(index);
238 &mut *(bytes.as_mut_ptr() as *mut T)
239 }
240}
241
242impl DataView {
246 #[inline]
248 pub fn try_slice<T: Pod>(&self, offset: usize, len: usize) -> Option<&[T]> {
249 let index = offset..offset + usize::checked_mul(len, mem::size_of::<T>())?;
250 let bytes = self.bytes.get(index)?;
251 let unaligned_ptr = bytes.as_ptr() as *const T;
252 if !is_aligned(unaligned_ptr) {
253 return None;
254 }
255 unsafe {
256 Some(slice::from_raw_parts(unaligned_ptr, len))
257 }
258 }
259 #[track_caller]
261 #[inline]
262 pub fn slice<T: Pod>(&self, offset: usize, len: usize) -> &[T] {
263 match self.try_slice(offset, len) {
264 Some(value) => value,
265 None => invalid_offset(),
266 }
267 }
268 #[inline]
270 pub unsafe fn slice_unchecked<T: Pod>(&self, offset: usize, len: usize) -> &[T] {
271 let index = offset..offset + len * mem::size_of::<T>();
272 let bytes = self.bytes.get_unchecked(index);
273 slice::from_raw_parts(bytes.as_ptr() as *const T, len)
274 }
275}
276
277impl DataView {
281 #[inline]
283 pub fn try_slice_mut<T: Pod>(&mut self, offset: usize, len: usize) -> Option<&mut [T]> {
284 let index = offset..offset + usize::checked_mul(len, mem::size_of::<T>())?;
285 let bytes = self.bytes.get_mut(index)?;
286 let unaligned_ptr = bytes.as_mut_ptr() as *mut T;
287 if !is_aligned(unaligned_ptr) {
288 return None;
289 }
290 unsafe {
291 Some(slice::from_raw_parts_mut(unaligned_ptr, len))
292 }
293 }
294 #[track_caller]
296 #[inline]
297 pub fn slice_mut<T: Pod>(&mut self, offset: usize, len: usize) -> &mut [T] {
298 match self.try_slice_mut(offset, len) {
299 Some(value) => value,
300 None => invalid_offset(),
301 }
302 }
303 #[inline]
305 pub unsafe fn slice_unchecked_mut<T: Pod>(&mut self, offset: usize, len: usize) -> &mut [T] {
306 let index = offset..offset + len * mem::size_of::<T>();
307 let bytes = self.bytes.get_unchecked_mut(index);
308 slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut T, len)
309 }
310}
311
312impl DataView {
316 #[inline]
318 pub fn try_write<T: ?Sized + Pod>(&mut self, offset: usize, value: &T) -> Option<()> {
319 let index = offset..offset + mem::size_of_val(value);
320 let bytes = self.bytes.get_mut(index)?;
321 bytes.copy_from_slice(crate::bytes(value));
322 Some(())
323 }
324 #[track_caller]
326 #[inline]
327 pub fn write<T: ?Sized + Pod>(&mut self, offset: usize, value: &T) {
328 match self.try_write(offset, value) {
329 Some(()) => (),
330 None => invalid_offset(),
331 }
332 }
333 #[inline]
335 pub unsafe fn write_unchecked<T: ?Sized + Pod>(&mut self, offset: usize, value: &T) {
336 let index = offset..offset + mem::size_of_val(value);
337 let bytes = self.bytes.get_unchecked_mut(index);
338 ptr::copy_nonoverlapping(crate::bytes(value).as_ptr(), bytes.as_mut_ptr(), bytes.len());
339 }
340}
341
342impl DataView {
345 #[inline]
347 pub fn index<R: ops::RangeBounds<usize>>(&self, range: R) -> Option<&DataView> {
348 let start = match range.start_bound() {
349 ops::Bound::Unbounded => 0,
350 ops::Bound::Included(&start) => start,
351 ops::Bound::Excluded(&start) => start + 1,
352 };
353 let end = match range.end_bound() {
354 ops::Bound::Unbounded => self.len(),
355 ops::Bound::Included(&end) => end + 1,
356 ops::Bound::Excluded(&end) => end,
357 };
358 let bytes = self.bytes.get(start..end)?;
359 Some(DataView::from(bytes))
360 }
361 #[inline]
363 pub fn index_mut<R: ops::RangeBounds<usize>>(&mut self, range: R) -> Option<&mut DataView> {
364 let start = match range.start_bound() {
365 ops::Bound::Unbounded => 0,
366 ops::Bound::Included(&start) => start,
367 ops::Bound::Excluded(&start) => start + 1,
368 };
369 let end = match range.end_bound() {
370 ops::Bound::Unbounded => self.len(),
371 ops::Bound::Included(&end) => end + 1,
372 ops::Bound::Excluded(&end) => end,
373 };
374 let bytes = self.bytes.get_mut(start..end)?;
375 Some(DataView::from_mut(bytes))
376 }
377}
378
379impl<R: ops::RangeBounds<usize>> ops::Index<R> for DataView {
382 type Output = DataView;
383 #[track_caller]
384 #[inline]
385 fn index(&self, range: R) -> &DataView {
386 match self.index(range) {
387 Some(value) => value,
388 None => invalid_offset(),
389 }
390 }
391}
392impl<R: ops::RangeBounds<usize>> ops::IndexMut<R> for DataView {
393 #[track_caller]
394 #[inline]
395 fn index_mut(&mut self, range: R) -> &mut DataView {
396 match self.index_mut(range) {
397 Some(value) => value,
398 None => invalid_offset(),
399 }
400 }
401}
402
403#[cold]
406#[track_caller]
407#[inline(never)]
408fn invalid_offset() -> ! {
409 panic!("invalid offset")
410}