Skip to main content

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}