storage_ptr_slice/lib.rs
1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Safe wrappers for raw pointer byte slices.
6//!
7//! This crate provides [`PtrByteSlice`] and [`MutPtrByteSlice`], which are designed for use in
8//! scenarios involving cross-process shared memory (e.g., communication with driver processes or
9//! other untrusted components).
10//!
11//! ### Rationale
12//!
13//! In a multi-process system like Fuchsia, processes often share memory via VMOs (Virtual Memory
14//! Objects). If a process shares a memory region with another process, that other process (which
15//! may be compromised or untrusted) can modify the memory concurrently at any time.
16//!
17//! In Rust, creating a standard reference (`&[u8]` or `&mut [u8]`) over memory that can be
18//! modified concurrently by another party is **Undefined Behavior (UB)**. The Rust compiler
19//! assumes that the data behind a shared reference (`&T`) is immutable and cannot change
20//! unexpectedly, allowing it to perform optimizations that assume stability. If the memory changes
21//! concurrently, these assumptions are violated.
22//!
23//! To avoid UB, we must avoid creating standard Rust references to concurrently-modifiable shared
24//! memory. Instead, we must treat the shared memory as raw pointers.
25//!
26//! [`PtrByteSlice`] and [`MutPtrByteSlice`] wrap these raw pointers and provide a safe API to:
27//! 1. **Copy data out** of the shared region into private, allocator-managed memory (e.g., via
28//! `copy_to_slice` or `to_vec`). Once copied, the private data is safe from concurrent
29//! modification and can be safely represented as standard Rust slices.
30//! 2. **Perform structured access** (e.g., via `chunks` or `chunks_mut`) only when the underlying
31//! types guarantee that arbitrary byte patterns are valid (via `FromBytes`) and we accept that
32//! the values might change (though we must still be careful about Time-of-Check to Time-of-Use
33//! (TOCTOU) vulnerabilities).
34//!
35//! By removing direct access to the underlying slice (i.e., not providing `as_slice` or
36//! `as_mut_slice` methods), this crate enforces that helper components must copy data into trusted
37//! buffers before operating on it, ensuring both memory safety (no UB) and robustness against
38//! concurrent modification.
39//!
40//! This crate does nothing to prevent data races; responsibility for handling data races lies
41//! elsewhere.
42
43use std::marker::PhantomData;
44use zerocopy::FromBytes;
45
46/// A read-only view of a raw pointer byte slice, providing a safe API.
47#[derive(Debug, Copy, Clone)]
48pub struct PtrByteSlice<'a> {
49 slice: *const [u8],
50 _marker: PhantomData<&'a [u8]>,
51}
52
53impl<'a> PtrByteSlice<'a> {
54 /// Creates a new `PtrByteSlice` from a raw pointer to a byte slice.
55 ///
56 /// # Safety
57 ///
58 /// The caller must ensure that `slice` is valid for reads for the lifetime `'a`.
59 pub unsafe fn new(slice: *const [u8]) -> Self {
60 Self { slice, _marker: PhantomData }
61 }
62
63 /// Returns the length of the slice in bytes.
64 pub fn len(&self) -> usize {
65 self.slice.len()
66 }
67
68 /// Returns `true` if the slice has a length of 0.
69 pub fn is_empty(&self) -> bool {
70 self.len() == 0
71 }
72
73 /// Reads a copy of a value of type `T` from the start of the slice.
74 ///
75 /// The read is performed unaligned, so the slice does not need to be aligned to `T`.
76 pub fn read<T: Copy + FromBytes>(&self) -> Option<T> {
77 let size = std::mem::size_of::<T>();
78 if size > self.len() {
79 return None;
80 }
81 let ptr = self.slice as *const T;
82 // SAFETY: `self.slice` points to valid memory of `self.len()` bytes.
83 // We verified that `size` is within bounds.
84 // We use read_unaligned so alignment is not required.
85 unsafe { Some(std::ptr::read_unaligned(ptr)) }
86 }
87
88 /// Copies the contents of this slice into a safe Rust mutable slice.
89 ///
90 /// # Panics
91 ///
92 /// Panics if `dest` is smaller than `self.len()`.
93 pub fn copy_to_slice(&self, dest: &mut [u8]) {
94 assert!(dest.len() >= self.len());
95 // SAFETY:
96 // - `self.slice` is valid for reads of `self.len()` bytes (guaranteed by `Self::new`
97 // safety contract).
98 // - `dest` is valid for writes of `self.len()` bytes (ensured by the assert).
99 // - The memory regions do not overlap because `dest` is an exclusive Rust reference.
100 unsafe {
101 std::ptr::copy_nonoverlapping(self.slice as *const u8, dest.as_mut_ptr(), self.len());
102 }
103 }
104
105 /// Returns a subslice of this pointer slice.
106 ///
107 /// # Panics
108 ///
109 /// Panics if the range is out of bounds.
110 pub fn subslice(&self, range: std::ops::Range<usize>) -> Self {
111 assert!(range.start <= range.end);
112 assert!(range.end <= self.len());
113 // SAFETY:
114 // - `range` is within the bounds of `self.slice` (ensured by asserts).
115 // - The original `self.slice` is valid for reads for `'a`, so any subslice of it
116 // is also valid for reads for `'a`.
117 unsafe {
118 let new_ptr = (self.slice as *const u8).add(range.start);
119 let new_slice = std::ptr::slice_from_raw_parts(new_ptr, range.end - range.start);
120 Self::new(new_slice)
121 }
122 }
123
124 /// Splits the slice into two at the given index.
125 ///
126 /// # Panics
127 ///
128 /// Panics if `mid` is out of bounds.
129 pub fn split_at(self, mid: usize) -> (Self, Self) {
130 assert!(mid <= self.len());
131 // SAFETY:
132 // - `mid` is within the bounds of `self.slice` (ensured by assert).
133 // - The two subslices are valid for reads for `'a` as they are parts of the original
134 // valid slice.
135 unsafe {
136 let ptr = self.slice as *const u8;
137 (
138 Self::new(std::ptr::slice_from_raw_parts(ptr, mid)),
139 Self::new(std::ptr::slice_from_raw_parts(ptr.add(mid), self.len() - mid)),
140 )
141 }
142 }
143
144 /// Returns the raw pointer to the slice.
145 pub fn as_raw_slice_ptr(&self) -> *const [u8] {
146 self.slice
147 }
148
149 /// Returns a raw pointer to the start of the slice.
150 pub fn as_ptr(&self) -> *const u8 {
151 self.slice as *const u8
152 }
153
154 /// Allocates a new heap Vector and copies the contents into it.
155 /// Bypasses zero-initialization using raw pointer copies.
156 pub fn to_vec(&self) -> Vec<u8> {
157 let mut vec = Vec::with_capacity(self.len());
158 // SAFETY: The memory is guaranteed to be valid for reads up to `self.len()`
159 // for the lifetime of this pointer slice.
160 unsafe {
161 std::ptr::copy_nonoverlapping(self.slice as *const u8, vec.as_mut_ptr(), self.len());
162 vec.set_len(self.len());
163 }
164 vec
165 }
166
167 /// Appends the contents of this slice to the given vector, expanding its capacity if needed.
168 /// Bypasses zero-initialization using raw pointer copies.
169 pub fn append_to(&self, vec: &mut Vec<u8>) {
170 let old_len = vec.len();
171 let new_len = old_len + self.len();
172 vec.reserve(self.len());
173 // SAFETY:
174 // - We reserved enough capacity in `vec` to fit `self.len()` more bytes.
175 // - `dest_ptr` points to the unused capacity.
176 // - `self.slice` is valid for reads of `self.len()` bytes.
177 // - The source and destination do not overlap because `vec` is owned and allocated
178 // separately.
179 unsafe {
180 let dest_ptr = vec.as_mut_ptr().add(old_len);
181 std::ptr::copy_nonoverlapping(self.slice as *const u8, dest_ptr, self.len());
182 vec.set_len(new_len);
183 }
184 }
185
186 /// Returns an iterator over read-only chunks of type `T`.
187 ///
188 /// # Panics
189 ///
190 /// Panics if the slice is not aligned to `T` or if its length in bytes is not a multiple of
191 /// `size_of::<T>()`.
192 pub fn chunks<T: Copy + FromBytes>(&self) -> Chunks<'_, T> {
193 let size = std::mem::size_of::<T>();
194 let align = std::mem::align_of::<T>();
195 assert!(size > 0, "Chunk size must be greater than 0");
196 assert_eq!(self.slice as *const u8 as usize % align, 0, "Slice is not aligned to T");
197 assert_eq!(self.len() % size, 0, "Slice length is not a multiple of T size");
198
199 // SAFETY:
200 // - `self.slice` is aligned to `T` (ensured by assert).
201 // - The end pointer is calculated within the bounds of the original slice.
202 // - Pointer arithmetic within the same allocated object is safe.
203 let end = unsafe { (self.slice as *const T).add(self.len() / size) };
204 Chunks { ptr: self.slice as *const T, end, _marker: PhantomData }
205 }
206}
207
208/// A mutable view of a raw pointer byte slice, providing a safe API.
209#[derive(Debug)]
210pub struct MutPtrByteSlice<'a> {
211 slice: *mut [u8],
212 _marker: PhantomData<&'a mut [u8]>,
213}
214
215impl<'a> MutPtrByteSlice<'a> {
216 /// Creates a new `MutPtrByteSlice` from a raw mutable pointer to a byte slice.
217 ///
218 /// # Safety
219 ///
220 /// The caller must ensure that `slice` is valid for reads and writes for the lifetime `'a`.
221 pub unsafe fn new(slice: *mut [u8]) -> Self {
222 Self { slice, _marker: PhantomData }
223 }
224
225 /// Returns the length of the slice in bytes.
226 pub fn len(&self) -> usize {
227 self.slice.len()
228 }
229
230 /// Returns `true` if the slice has a length of 0.
231 pub fn is_empty(&self) -> bool {
232 self.len() == 0
233 }
234
235 /// Reads a copy of a value of type `T` from the start of the slice.
236 ///
237 /// The read is performed unaligned, so the slice does not need to be aligned to `T`.
238 pub fn read<T: Copy + FromBytes>(&self) -> Option<T> {
239 let size = std::mem::size_of::<T>();
240 if size > self.len() {
241 return None;
242 }
243 let ptr = self.slice as *const T;
244 // SAFETY: `self.slice` points to valid memory of `self.len()` bytes.
245 // We verified that `size` is within bounds.
246 // We use read_unaligned so alignment is not required.
247 unsafe { Some(std::ptr::read_unaligned(ptr)) }
248 }
249
250 /// Writes a value of type `T` to the start of the slice.
251 ///
252 /// The write is performed unaligned, so the slice does not need to be aligned to `T`.
253 pub fn write<T: Copy + FromBytes>(&mut self, val: T) -> Option<()> {
254 let size = std::mem::size_of::<T>();
255 if size > self.len() {
256 return None;
257 }
258 let ptr = self.slice as *mut T;
259 // SAFETY: `self.slice` points to valid memory of `self.len()` bytes.
260 // We verified that `size` is within bounds.
261 // We use write_unaligned so alignment is not required.
262 unsafe {
263 std::ptr::write_unaligned(ptr, val);
264 }
265 Some(())
266 }
267
268 /// Copies the contents of this slice into a safe Rust mutable slice.
269 ///
270 /// # Panics
271 ///
272 /// Panics if `dest` is smaller than `self.len()`.
273 pub fn copy_to_slice(&self, dest: &mut [u8]) {
274 assert!(dest.len() >= self.len());
275 // SAFETY:
276 // - `self.slice` is valid for reads of `self.len()` bytes (guaranteed by `Self::new`
277 // safety contract).
278 // - `dest` is valid for writes of `self.len()` bytes (ensured by the assert).
279 // - The memory regions do not overlap because `dest` is an exclusive Rust reference.
280 unsafe {
281 std::ptr::copy_nonoverlapping(self.slice as *mut u8, dest.as_mut_ptr(), self.len());
282 }
283 }
284
285 /// Copies the contents of another read-only pointer slice into this mutable slice.
286 ///
287 /// # Panics
288 ///
289 /// Panics if the lengths of the slices do not match.
290 pub fn copy_from_ptr_slice(&mut self, src: PtrByteSlice<'_>) {
291 assert_eq!(self.len(), src.len());
292 // SAFETY:
293 // - `self.slice` is valid for writes of `self.len()` bytes.
294 // - `src` is valid for reads of `src.len()` (which equals `self.len()`) bytes.
295 // - They do not overlap because `self` (mutable) and `src` (immutable) cannot alias
296 // under Rust's borrowing rules.
297 unsafe {
298 std::ptr::copy_nonoverlapping(src.as_ptr(), self.slice as *mut u8, self.len());
299 }
300 }
301
302 /// Copies the contents of a standard safe slice into this mutable slice.
303 ///
304 /// # Panics
305 ///
306 /// Panics if the lengths of the slices do not match.
307 pub fn copy_from_slice(&mut self, src: &[u8]) {
308 assert_eq!(self.len(), src.len());
309 // SAFETY:
310 // - `self.slice` is valid for writes of `self.len()` bytes.
311 // - `src` is valid for reads of `src.len()` bytes.
312 // - They do not overlap because `src` is an exclusive Rust reference.
313 unsafe {
314 std::ptr::copy_nonoverlapping(src.as_ptr(), self.slice as *mut u8, self.len());
315 }
316 }
317
318 /// Fills the slice with the given byte value.
319 pub fn fill(&mut self, val: u8) {
320 // SAFETY: `self.slice` is valid for writes of `self.len()` bytes.
321 unsafe {
322 std::ptr::write_bytes(self.slice as *mut u8, val, self.len());
323 }
324 }
325
326 /// Returns a read-only view of this slice.
327 pub fn as_ptr_slice(&self) -> PtrByteSlice<'_> {
328 // SAFETY: `self.slice` is valid for reads (since it is valid for writes) for `'a`.
329 unsafe { PtrByteSlice::new(self.slice as *const [u8]) }
330 }
331
332 /// Returns a mutable subslice of this pointer slice.
333 ///
334 /// # Panics
335 ///
336 /// Panics if the range is out of bounds.
337 pub fn subslice_mut(&mut self, range: std::ops::Range<usize>) -> Self {
338 assert!(range.start <= range.end);
339 assert!(range.end <= self.len());
340 // SAFETY:
341 // - `range` is within the bounds of `self.slice` (ensured by asserts).
342 // - The original `self.slice` is valid for reads and writes for `'a`, so any subslice of it
343 // is also valid for reads and writes for `'a`.
344 unsafe {
345 let new_ptr = (self.slice as *mut u8).add(range.start);
346 let new_slice = std::ptr::slice_from_raw_parts_mut(new_ptr, range.end - range.start);
347 Self::new(new_slice)
348 }
349 }
350
351 /// Splits the slice into two at the given index.
352 ///
353 /// # Panics
354 ///
355 /// Panics if `mid` is out of bounds.
356 pub fn split_at_mut(self, mid: usize) -> (Self, Self) {
357 assert!(mid <= self.len());
358 // SAFETY:
359 // - `mid` is within the bounds of `self.slice` (ensured by assert).
360 // - The two subslices are valid for reads and writes for `'a` as they are parts of the
361 // original valid slice.
362 // - They do not overlap.
363 unsafe {
364 let ptr = self.slice as *mut u8;
365 (
366 Self::new(std::ptr::slice_from_raw_parts_mut(ptr, mid)),
367 Self::new(std::ptr::slice_from_raw_parts_mut(ptr.add(mid), self.len() - mid)),
368 )
369 }
370 }
371
372 /// Returns the raw mutable pointer to the slice.
373 pub fn as_raw_mut_slice_ptr(&self) -> *mut [u8] {
374 self.slice
375 }
376
377 /// Returns a raw pointer to the start of the slice.
378 pub fn as_ptr(&self) -> *const u8 {
379 self.slice as *const u8
380 }
381
382 /// Returns a raw mutable pointer to the start of the slice.
383 pub fn as_mut_ptr(&self) -> *mut u8 {
384 self.slice as *mut u8
385 }
386
387 /// Reborrows the mutable slice with a shorter lifetime.
388 pub fn reborrow(&mut self) -> MutPtrByteSlice<'_> {
389 MutPtrByteSlice { slice: self.slice, _marker: std::marker::PhantomData }
390 }
391
392 /// Allocates a new heap Vector and copies the contents into it.
393 /// Bypasses zero-initialization using raw pointer copies.
394 pub fn to_vec(&self) -> Vec<u8> {
395 let mut vec = Vec::with_capacity(self.len());
396 // SAFETY: The memory is guaranteed to be valid for reads up to `self.len()`
397 // for the lifetime of this pointer slice.
398 unsafe {
399 std::ptr::copy_nonoverlapping(self.slice as *mut u8, vec.as_mut_ptr(), self.len());
400 vec.set_len(self.len());
401 }
402 vec
403 }
404
405 /// Appends the contents of this slice to the given vector, expanding its capacity if needed.
406 /// Bypasses zero-initialization using raw pointer copies.
407 pub fn append_to(&self, vec: &mut Vec<u8>) {
408 let old_len = vec.len();
409 let new_len = old_len + self.len();
410 vec.reserve(self.len());
411 // SAFETY:
412 // - We reserved enough capacity in `vec` to fit `self.len()` more bytes.
413 // - `dest_ptr` points to the unused capacity.
414 // - `self.slice` is valid for reads of `self.len()` bytes.
415 // - The source and destination do not overlap because `vec` is owned and allocated
416 // separately.
417 unsafe {
418 let dest_ptr = vec.as_mut_ptr().add(old_len);
419 std::ptr::copy_nonoverlapping(self.slice as *mut u8, dest_ptr, self.len());
420 vec.set_len(new_len);
421 }
422 }
423
424 /// Returns an iterator over mutable chunks of type `T`.
425 ///
426 /// # Panics
427 ///
428 /// Panics if the slice is not aligned to `T` or if its length in bytes is not a multiple of
429 /// `size_of::<T>()`.
430 pub fn chunks_mut<T: Copy + FromBytes>(&mut self) -> ChunksMut<'_, T> {
431 let size = std::mem::size_of::<T>();
432 let align = std::mem::align_of::<T>();
433 assert!(size > 0, "Chunk size must be greater than 0");
434 assert_eq!(self.slice as *mut u8 as usize % align, 0, "Slice is not aligned to T");
435 assert_eq!(self.len() % size, 0, "Slice length is not a multiple of T size");
436
437 // SAFETY:
438 // - `self.slice` is aligned to `T` (ensured by assert).
439 // - The end pointer is calculated within the bounds of the original slice.
440 // - Pointer arithmetic within the same allocated object is safe.
441 let end = unsafe { (self.slice as *mut T).add(self.len() / size) };
442 ChunksMut { ptr: self.slice as *mut T, end, _marker: PhantomData }
443 }
444}
445
446// SAFETY: `PtrByteSlice` is conceptually a read-only view of a byte slice (`&[u8]`).
447// It does not allow mutation and does not own the underlying memory.
448// It is safe to send it to another thread (`Send`) and share it among threads (`Sync`)
449// because the underlying memory is guaranteed to be valid for the lifetime `'a`.
450unsafe impl Send for PtrByteSlice<'_> {}
451// SAFETY: See comment above.
452unsafe impl Sync for PtrByteSlice<'_> {}
453// SAFETY: `MutPtrByteSlice` is conceptually a mutable view of a byte slice (`&mut [u8]`).
454// It enforces exclusive access because it does not implement `Clone` or `Copy`,
455// and all mutating methods require `&mut self` or ownership.
456// It is safe to send it to another thread (`Send`) because only one thread can possess it
457// at a time.
458unsafe impl Send for MutPtrByteSlice<'_> {}
459// SAFETY: `MutPtrByteSlice` is safe to share among threads (`Sync`) because it does not
460// permit safe concurrent mutation through a shared reference (`&self`).
461unsafe impl Sync for MutPtrByteSlice<'_> {}
462
463impl<'a> From<&'a [u8]> for PtrByteSlice<'a> {
464 fn from(slice: &'a [u8]) -> Self {
465 // SAFETY: A standard Rust reference is guaranteed to be valid for reads.
466 unsafe { Self::new(slice as *const [u8]) }
467 }
468}
469
470impl<'a> From<&'a Vec<u8>> for PtrByteSlice<'a> {
471 fn from(vec: &'a Vec<u8>) -> Self {
472 Self::from(vec.as_slice())
473 }
474}
475
476impl<'a> From<MutPtrByteSlice<'a>> for PtrByteSlice<'a> {
477 fn from(slice: MutPtrByteSlice<'a>) -> Self {
478 // SAFETY: MutPtrByteSlice guarantees the memory is valid for 'a.
479 // Since we consume the MutPtrByteSlice, we can safely return a PtrByteSlice with the same
480 // lifetime.
481 unsafe { Self::new(slice.slice as *const [u8]) }
482 }
483}
484
485impl<'a> From<&'a mut [u8]> for MutPtrByteSlice<'a> {
486 fn from(slice: &'a mut [u8]) -> Self {
487 // SAFETY: A standard Rust mutable reference is guaranteed to be valid and exclusive.
488 unsafe { Self::new(slice as *mut [u8]) }
489 }
490}
491
492impl<'a> From<&'a mut Vec<u8>> for MutPtrByteSlice<'a> {
493 fn from(vec: &'a mut Vec<u8>) -> Self {
494 Self::from(vec.as_mut_slice())
495 }
496}
497
498/// An iterator over read-only chunks of a pointer slice.
499pub struct Chunks<'a, T> {
500 ptr: *const T,
501 end: *const T,
502 _marker: PhantomData<&'a T>,
503}
504
505impl<'a, T: Copy + FromBytes> Iterator for Chunks<'a, T> {
506 type Item = Chunk<'a, T>;
507
508 fn next(&mut self) -> Option<Self::Item> {
509 if self.ptr == self.end {
510 None
511 } else {
512 let current = self.ptr;
513 // SAFETY: `self.ptr` is less than `self.end` (checked), so adding 1 is within the
514 // bounds of the allocation.
515 self.ptr = unsafe { self.ptr.add(1) };
516 Some(Chunk { ptr: current, _marker: PhantomData })
517 }
518 }
519}
520
521/// A read-only chunk of a pointer slice.
522pub struct Chunk<'a, T> {
523 ptr: *const T,
524 _marker: PhantomData<&'a T>,
525}
526
527impl<T: Copy + FromBytes> Chunk<'_, T> {
528 /// Reads the value from the chunk.
529 ///
530 /// Since alignment and validity were verified once when the iterator was created,
531 /// this access is safe and fast.
532 pub fn read(&self) -> T {
533 // SAFETY: The pointer is guaranteed to be valid and aligned.
534 unsafe { std::ptr::read(self.ptr) }
535 }
536}
537
538/// An iterator over mutable chunks of a pointer slice.
539pub struct ChunksMut<'a, T> {
540 ptr: *mut T,
541 end: *mut T,
542 _marker: PhantomData<&'a mut T>,
543}
544
545impl<'a, T: Copy + FromBytes> Iterator for ChunksMut<'a, T> {
546 type Item = ChunkMut<'a, T>;
547
548 fn next(&mut self) -> Option<Self::Item> {
549 if self.ptr == self.end {
550 None
551 } else {
552 let current = self.ptr;
553 // SAFETY: `self.ptr` is less than `self.end` (checked), so adding 1 is within the
554 // bounds of the allocation.
555 self.ptr = unsafe { self.ptr.add(1) };
556 Some(ChunkMut { ptr: current, _marker: PhantomData })
557 }
558 }
559}
560
561/// A mutable chunk of a pointer slice.
562pub struct ChunkMut<'a, T> {
563 ptr: *mut T,
564 _marker: PhantomData<&'a mut T>,
565}
566
567impl<T: Copy + FromBytes> ChunkMut<'_, T> {
568 /// Reads the value from the chunk.
569 ///
570 /// Since alignment and validity were verified once when the iterator was created,
571 /// this access is safe and fast.
572 pub fn read(&self) -> T {
573 // SAFETY: The pointer is guaranteed to be valid and aligned.
574 unsafe { std::ptr::read(self.ptr) }
575 }
576
577 /// Writes a value to the chunk.
578 ///
579 /// Since alignment and validity were verified once when the iterator was created,
580 /// this access is safe and fast.
581 pub fn write(&self, val: T) {
582 // SAFETY: The pointer is guaranteed to be valid and aligned.
583 unsafe { std::ptr::write(self.ptr, val) }
584 }
585}
586
587impl std::io::Read for PtrByteSlice<'_> {
588 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
589 let remaining = self.len();
590 if remaining == 0 {
591 return Ok(0);
592 }
593 let to_read = std::cmp::min(remaining, buf.len());
594 let (a, b) = self.split_at(to_read);
595 a.copy_to_slice(&mut buf[..to_read]);
596 *self = b;
597 Ok(to_read)
598 }
599
600 fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
601 if buf.len() > self.len() {
602 return Err(std::io::Error::new(
603 std::io::ErrorKind::UnexpectedEof,
604 "failed to fill whole buffer",
605 ));
606 }
607 let (a, b) = self.split_at(buf.len());
608 a.copy_to_slice(buf);
609 *self = b;
610 Ok(())
611 }
612
613 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
614 let len = self.len();
615 self.append_to(buf);
616 *self = self.subslice(len..len);
617 Ok(len)
618 }
619}
620
621#[cfg(test)]
622mod tests {
623 use super::*;
624 use std::io::Read;
625 use zerocopy::IntoBytes;
626
627 #[derive(Copy, Clone, Debug, FromBytes, IntoBytes)]
628 #[repr(C, align(4))]
629 struct Aligned4(u32);
630
631 #[test]
632 fn test_chunks_success() {
633 let bytes = [0u8; 16];
634 let slice = PtrByteSlice::from(&bytes[..]);
635 let chunks = slice.chunks::<Aligned4>();
636 assert_eq!(chunks.count(), 4);
637 }
638
639 #[test]
640 #[should_panic]
641 fn test_chunks_unaligned_panic() {
642 #[repr(C, align(4))]
643 struct AligningBuffer {
644 buffer: [u8; 17],
645 }
646 let aligned = AligningBuffer { buffer: [0u8; 17] };
647 let slice = PtrByteSlice::from(&aligned.buffer[1..17]);
648 let _ = slice.chunks::<Aligned4>();
649 }
650
651 #[test]
652 #[should_panic]
653 fn test_chunks_missized_panic() {
654 let bytes = [0u8; 15];
655 let slice = PtrByteSlice::from(&bytes[..]);
656 let _ = slice.chunks::<Aligned4>();
657 }
658
659 #[test]
660 fn test_chunks_mut_success() {
661 let mut bytes = [0u8; 16];
662 let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
663 let chunks = slice.chunks_mut::<Aligned4>();
664 assert_eq!(chunks.count(), 4);
665 }
666
667 #[test]
668 #[should_panic]
669 fn test_chunks_mut_unaligned_panic() {
670 #[repr(C, align(4))]
671 struct AligningBuffer {
672 buffer: [u8; 17],
673 }
674 let mut aligned = AligningBuffer { buffer: [0u8; 17] };
675 let mut slice = MutPtrByteSlice::from(&mut aligned.buffer[1..17]);
676 let _ = slice.chunks_mut::<Aligned4>();
677 }
678
679 #[test]
680 #[should_panic]
681 fn test_chunks_mut_missized_panic() {
682 let mut bytes = [0u8; 15];
683 let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
684 let _ = slice.chunks_mut::<Aligned4>();
685 }
686
687 #[test]
688 fn test_reader() {
689 let bytes = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10];
690 let mut slice = PtrByteSlice::from(&bytes[..]);
691 let mut buf = [0u8; 4];
692 assert_eq!(Read::read(&mut slice, &mut buf).unwrap(), 4);
693 assert_eq!(buf, [1, 2, 3, 4]);
694 assert_eq!(slice.len(), 6);
695 let mut rest = Vec::new();
696 assert_eq!(slice.read_to_end(&mut rest).unwrap(), 6);
697 assert_eq!(rest, [5, 6, 7, 8, 9, 10]);
698 assert_eq!(slice.len(), 0);
699 }
700
701 #[test]
702 fn test_read_success() {
703 let bytes = [1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8];
704 let slice = PtrByteSlice::from(&bytes[..]);
705
706 let val = slice.read::<Aligned4>().unwrap();
707 // We use from_ne_bytes to be independent of endianness for the raw bytes comparison,
708 // but Aligned4 is just a wrapper around u32.
709 assert_eq!(val.0, u32::from_ne_bytes([1, 2, 3, 4]));
710
711 // Unaligned read
712 let sub = slice.subslice(1..8);
713 let val_unaligned = sub.read::<Aligned4>().unwrap();
714 assert_eq!(val_unaligned.0, u32::from_ne_bytes([2, 3, 4, 5]));
715 }
716
717 #[test]
718 fn test_read_bounds_failure() {
719 let bytes = [1u8, 2u8, 3u8];
720 let slice = PtrByteSlice::from(&bytes[..]);
721 assert!(slice.read::<Aligned4>().is_none());
722 }
723
724 #[test]
725 fn test_mut_read_write_success() {
726 let mut bytes = [0u8; 8];
727 let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
728
729 // Write aligned
730 slice.write(Aligned4(0x12345678)).unwrap();
731 assert_eq!(slice.read::<Aligned4>().unwrap().0, 0x12345678);
732
733 // Write unaligned
734 let mut sub = slice.subslice_mut(1..8);
735 sub.write(Aligned4(0xabcdef01)).unwrap();
736 assert_eq!(sub.read::<Aligned4>().unwrap().0, 0xabcdef01);
737 }
738
739 #[test]
740 fn test_mut_write_bounds_failure() {
741 let mut bytes = [0u8; 3];
742 let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
743 assert!(slice.write(Aligned4(0)).is_none());
744 }
745}