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 `iter_as` or `iter_as_mut`) only when the
31//!     underlying types guarantee that arbitrary byte patterns are valid (via `FromBytes`) and we
32//!     accept that the values might change (though we must still be careful about Time-of-Check to
33//!     Time-of-Use (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 typed elements `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 iter_as<T: Copy + FromBytes>(&self) -> IterAs<'_, 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        IterAs { ptr: self.slice as *const T, end, _marker: PhantomData }
205    }
206
207    /// Returns an iterator over byte chunks of up to `chunk_size` bytes.
208    ///
209    /// # Panics
210    ///
211    /// Panics if `chunk_size` is 0.
212    pub fn chunks(&self, chunk_size: usize) -> Chunks<'a> {
213        assert!(chunk_size > 0, "chunk_size must be > 0");
214        Chunks { slice: *self, chunk_size, offset: 0 }
215    }
216}
217
218/// A mutable view of a raw pointer byte slice, providing a safe API.
219#[derive(Debug)]
220pub struct MutPtrByteSlice<'a> {
221    slice: *mut [u8],
222    _marker: PhantomData<&'a mut [u8]>,
223}
224
225impl<'a> MutPtrByteSlice<'a> {
226    /// Creates a new `MutPtrByteSlice` from a raw mutable pointer to a byte slice.
227    ///
228    /// # Safety
229    ///
230    /// The caller must ensure that `slice` is valid for reads and writes for the lifetime `'a`.
231    pub unsafe fn new(slice: *mut [u8]) -> Self {
232        Self { slice, _marker: PhantomData }
233    }
234
235    /// Returns the length of the slice in bytes.
236    pub fn len(&self) -> usize {
237        self.slice.len()
238    }
239
240    /// Returns `true` if the slice has a length of 0.
241    pub fn is_empty(&self) -> bool {
242        self.len() == 0
243    }
244
245    /// Reads a copy of a value of type `T` from the start of the slice.
246    ///
247    /// The read is performed unaligned, so the slice does not need to be aligned to `T`.
248    pub fn read<T: Copy + FromBytes>(&self) -> Option<T> {
249        let size = std::mem::size_of::<T>();
250        if size > self.len() {
251            return None;
252        }
253        let ptr = self.slice as *const T;
254        // SAFETY: `self.slice` points to valid memory of `self.len()` bytes.
255        // We verified that `size` is within bounds.
256        // We use read_unaligned so alignment is not required.
257        unsafe { Some(std::ptr::read_unaligned(ptr)) }
258    }
259
260    /// Writes a value of type `T` to the start of the slice.
261    ///
262    /// The write is performed unaligned, so the slice does not need to be aligned to `T`.
263    pub fn write<T: Copy + FromBytes>(&mut self, val: T) -> Option<()> {
264        let size = std::mem::size_of::<T>();
265        if size > self.len() {
266            return None;
267        }
268        let ptr = self.slice as *mut T;
269        // SAFETY: `self.slice` points to valid memory of `self.len()` bytes.
270        // We verified that `size` is within bounds.
271        // We use write_unaligned so alignment is not required.
272        unsafe {
273            std::ptr::write_unaligned(ptr, val);
274        }
275        Some(())
276    }
277
278    /// Copies the contents of this slice into a safe Rust mutable slice.
279    ///
280    /// # Panics
281    ///
282    /// Panics if `dest` is smaller than `self.len()`.
283    pub fn copy_to_slice(&self, dest: &mut [u8]) {
284        assert!(dest.len() >= self.len());
285        // SAFETY:
286        // - `self.slice` is valid for reads of `self.len()` bytes (guaranteed by `Self::new`
287        //   safety contract).
288        // - `dest` is valid for writes of `self.len()` bytes (ensured by the assert).
289        // - The memory regions do not overlap because `dest` is an exclusive Rust reference.
290        unsafe {
291            std::ptr::copy_nonoverlapping(self.slice as *mut u8, dest.as_mut_ptr(), self.len());
292        }
293    }
294
295    /// Copies the contents of another read-only pointer slice into this mutable slice.
296    ///
297    /// # Panics
298    ///
299    /// Panics if the lengths of the slices do not match.
300    pub fn copy_from_ptr_slice(&mut self, src: PtrByteSlice<'_>) {
301        assert_eq!(self.len(), src.len());
302        // SAFETY:
303        // - `self.slice` is valid for writes of `self.len()` bytes.
304        // - `src` is valid for reads of `src.len()` (which equals `self.len()`) bytes.
305        // - They do not overlap because `self` (mutable) and `src` (immutable) cannot alias
306        //   under Rust's borrowing rules.
307        unsafe {
308            std::ptr::copy_nonoverlapping(src.as_ptr(), self.slice as *mut u8, self.len());
309        }
310    }
311
312    /// Copies the contents of a standard safe slice into this mutable slice.
313    ///
314    /// # Panics
315    ///
316    /// Panics if the lengths of the slices do not match.
317    pub fn copy_from_slice(&mut self, src: &[u8]) {
318        assert_eq!(self.len(), src.len());
319        // SAFETY:
320        // - `self.slice` is valid for writes of `self.len()` bytes.
321        // - `src` is valid for reads of `src.len()` bytes.
322        // - They do not overlap because `src` is an exclusive Rust reference.
323        unsafe {
324            std::ptr::copy_nonoverlapping(src.as_ptr(), self.slice as *mut u8, self.len());
325        }
326    }
327
328    /// Fills the slice with the given byte value.
329    pub fn fill(&mut self, val: u8) {
330        // SAFETY: `self.slice` is valid for writes of `self.len()` bytes.
331        unsafe {
332            std::ptr::write_bytes(self.slice as *mut u8, val, self.len());
333        }
334    }
335
336    /// Returns a read-only view of this slice.
337    pub fn as_ptr_slice(&self) -> PtrByteSlice<'_> {
338        // SAFETY: `self.slice` is valid for reads (since it is valid for writes) for `'a`.
339        unsafe { PtrByteSlice::new(self.slice as *const [u8]) }
340    }
341
342    /// Returns a mutable subslice of this pointer slice.
343    ///
344    /// # Panics
345    ///
346    /// Panics if the range is out of bounds.
347    pub fn subslice_mut(&mut self, range: std::ops::Range<usize>) -> Self {
348        assert!(range.start <= range.end);
349        assert!(range.end <= self.len());
350        // SAFETY:
351        // - `range` is within the bounds of `self.slice` (ensured by asserts).
352        // - The original `self.slice` is valid for reads and writes for `'a`, so any subslice of it
353        //   is also valid for reads and writes for `'a`.
354        unsafe {
355            let new_ptr = (self.slice as *mut u8).add(range.start);
356            let new_slice = std::ptr::slice_from_raw_parts_mut(new_ptr, range.end - range.start);
357            Self::new(new_slice)
358        }
359    }
360
361    /// Splits the slice into two at the given index.
362    ///
363    /// # Panics
364    ///
365    /// Panics if `mid` is out of bounds.
366    pub fn split_at_mut(self, mid: usize) -> (Self, Self) {
367        assert!(mid <= self.len());
368        // SAFETY:
369        // - `mid` is within the bounds of `self.slice` (ensured by assert).
370        // - The two subslices are valid for reads and writes for `'a` as they are parts of the
371        //   original valid slice.
372        // - They do not overlap.
373        unsafe {
374            let ptr = self.slice as *mut u8;
375            (
376                Self::new(std::ptr::slice_from_raw_parts_mut(ptr, mid)),
377                Self::new(std::ptr::slice_from_raw_parts_mut(ptr.add(mid), self.len() - mid)),
378            )
379        }
380    }
381
382    /// Returns the raw mutable pointer to the slice.
383    pub fn as_raw_mut_slice_ptr(&self) -> *mut [u8] {
384        self.slice
385    }
386
387    /// Returns a raw pointer to the start of the slice.
388    pub fn as_ptr(&self) -> *const u8 {
389        self.slice as *const u8
390    }
391
392    /// Returns a raw mutable pointer to the start of the slice.
393    pub fn as_mut_ptr(&self) -> *mut u8 {
394        self.slice as *mut u8
395    }
396
397    /// Reborrows the mutable slice with a shorter lifetime.
398    pub fn reborrow(&mut self) -> MutPtrByteSlice<'_> {
399        MutPtrByteSlice { slice: self.slice, _marker: std::marker::PhantomData }
400    }
401
402    /// Allocates a new heap Vector and copies the contents into it.
403    /// Bypasses zero-initialization using raw pointer copies.
404    pub fn to_vec(&self) -> Vec<u8> {
405        let mut vec = Vec::with_capacity(self.len());
406        // SAFETY: The memory is guaranteed to be valid for reads up to `self.len()`
407        // for the lifetime of this pointer slice.
408        unsafe {
409            std::ptr::copy_nonoverlapping(self.slice as *mut u8, vec.as_mut_ptr(), self.len());
410            vec.set_len(self.len());
411        }
412        vec
413    }
414
415    /// Appends the contents of this slice to the given vector, expanding its capacity if needed.
416    /// Bypasses zero-initialization using raw pointer copies.
417    pub fn append_to(&self, vec: &mut Vec<u8>) {
418        let old_len = vec.len();
419        let new_len = old_len + self.len();
420        vec.reserve(self.len());
421        // SAFETY:
422        // - We reserved enough capacity in `vec` to fit `self.len()` more bytes.
423        // - `dest_ptr` points to the unused capacity.
424        // - `self.slice` is valid for reads of `self.len()` bytes.
425        // - The source and destination do not overlap because `vec` is owned and allocated
426        //   separately.
427        unsafe {
428            let dest_ptr = vec.as_mut_ptr().add(old_len);
429            std::ptr::copy_nonoverlapping(self.slice as *mut u8, dest_ptr, self.len());
430            vec.set_len(new_len);
431        }
432    }
433
434    /// Returns an iterator over mutable typed elements `T`.
435    ///
436    /// # Panics
437    ///
438    /// Panics if the slice is not aligned to `T` or if its length in bytes is not a multiple of
439    /// `size_of::<T>()`.
440    pub fn iter_as_mut<T: Copy + FromBytes>(&mut self) -> IterAsMut<'_, T> {
441        let size = std::mem::size_of::<T>();
442        let align = std::mem::align_of::<T>();
443        assert!(size > 0, "Chunk size must be greater than 0");
444        assert_eq!(self.slice as *mut u8 as usize % align, 0, "Slice is not aligned to T");
445        assert_eq!(self.len() % size, 0, "Slice length is not a multiple of T size");
446
447        // SAFETY:
448        // - `self.slice` is aligned to `T` (ensured by assert).
449        // - The end pointer is calculated within the bounds of the original slice.
450        // - Pointer arithmetic within the same allocated object is safe.
451        let end = unsafe { (self.slice as *mut T).add(self.len() / size) };
452        IterAsMut { ptr: self.slice as *mut T, end, _marker: PhantomData }
453    }
454
455    /// Returns an iterator over mutable byte chunks of up to `chunk_size` bytes.
456    ///
457    /// # Panics
458    ///
459    /// Panics if `chunk_size` is 0.
460    pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_> {
461        assert!(chunk_size > 0, "chunk_size must be > 0");
462        ChunksMut { slice: self.reborrow(), chunk_size, offset: 0 }
463    }
464
465    /// Consumes this slice and returns an iterator over mutable byte chunks of up to
466    /// `chunk_size` bytes.
467    ///
468    /// # Panics
469    ///
470    /// Panics if `chunk_size` is 0.
471    pub fn into_chunks_mut(self, chunk_size: usize) -> ChunksMut<'a> {
472        assert!(chunk_size > 0, "chunk_size must be > 0");
473        ChunksMut { slice: self, chunk_size, offset: 0 }
474    }
475
476    /// Returns an `io::Write` adapter for this slice.
477    pub fn writer(self) -> Writer<'a> {
478        Writer::new(self)
479    }
480}
481
482/// An `io::Write` adapter for `MutPtrByteSlice`.
483#[derive(Debug)]
484pub struct Writer<'a> {
485    slice: MutPtrByteSlice<'a>,
486    pos: usize,
487}
488
489impl<'a> Writer<'a> {
490    /// Creates a new writer from a `MutPtrByteSlice`.
491    pub fn new(slice: MutPtrByteSlice<'a>) -> Self {
492        Self { slice, pos: 0 }
493    }
494
495    /// Returns the number of bytes written so far (the current position of the writer).
496    pub fn position(&self) -> usize {
497        self.pos
498    }
499
500    /// Returns the remaining unwritten subslice of the buffer.
501    pub fn remaining(&mut self) -> MutPtrByteSlice<'_> {
502        let len = self.slice.len();
503        self.slice.reborrow().subslice_mut(self.pos..len)
504    }
505
506    /// Consumes the writer and returns the subslice containing the data written so far.
507    pub fn into_written(mut self) -> MutPtrByteSlice<'a> {
508        let pos = self.pos;
509        self.slice.subslice_mut(0..pos)
510    }
511}
512
513impl std::io::Write for Writer<'_> {
514    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
515        let remaining = self.slice.len() - self.pos;
516        if remaining == 0 {
517            return Ok(0);
518        }
519        let to_write = std::cmp::min(remaining, buf.len());
520        self.slice
521            .reborrow()
522            .subslice_mut(self.pos..self.pos + to_write)
523            .copy_from_slice(&buf[..to_write]);
524        self.pos += to_write;
525        Ok(to_write)
526    }
527
528    fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
529        if buf.len() > self.slice.len() - self.pos {
530            return Err(std::io::Error::new(
531                std::io::ErrorKind::WriteZero,
532                "failed to write whole buffer",
533            ));
534        }
535        self.slice.reborrow().subslice_mut(self.pos..self.pos + buf.len()).copy_from_slice(buf);
536        self.pos += buf.len();
537        Ok(())
538    }
539
540    fn flush(&mut self) -> std::io::Result<()> {
541        Ok(())
542    }
543}
544
545// SAFETY: `PtrByteSlice` is conceptually a read-only view of a byte slice (`&[u8]`).
546// It does not allow mutation and does not own the underlying memory.
547// It is safe to send it to another thread (`Send`) and share it among threads (`Sync`)
548// because the underlying memory is guaranteed to be valid for the lifetime `'a`.
549unsafe impl Send for PtrByteSlice<'_> {}
550// SAFETY: See comment above.
551unsafe impl Sync for PtrByteSlice<'_> {}
552// SAFETY: `MutPtrByteSlice` is conceptually a mutable view of a byte slice (`&mut [u8]`).
553// It enforces exclusive access because it does not implement `Clone` or `Copy`,
554// and all mutating methods require `&mut self` or ownership.
555// It is safe to send it to another thread (`Send`) because only one thread can possess it
556// at a time.
557unsafe impl Send for MutPtrByteSlice<'_> {}
558// SAFETY: `MutPtrByteSlice` is safe to share among threads (`Sync`) because it does not
559// permit safe concurrent mutation through a shared reference (`&self`).
560unsafe impl Sync for MutPtrByteSlice<'_> {}
561
562impl<'a> From<&'a [u8]> for PtrByteSlice<'a> {
563    fn from(slice: &'a [u8]) -> Self {
564        // SAFETY: A standard Rust reference is guaranteed to be valid for reads.
565        unsafe { Self::new(slice as *const [u8]) }
566    }
567}
568
569impl<'a> From<&'a Vec<u8>> for PtrByteSlice<'a> {
570    fn from(vec: &'a Vec<u8>) -> Self {
571        Self::from(vec.as_slice())
572    }
573}
574
575impl<'a> From<MutPtrByteSlice<'a>> for PtrByteSlice<'a> {
576    fn from(slice: MutPtrByteSlice<'a>) -> Self {
577        // SAFETY: MutPtrByteSlice guarantees the memory is valid for 'a.
578        // Since we consume the MutPtrByteSlice, we can safely return a PtrByteSlice with the same
579        // lifetime.
580        unsafe { Self::new(slice.slice as *const [u8]) }
581    }
582}
583
584impl<'a> From<&'a mut [u8]> for MutPtrByteSlice<'a> {
585    fn from(slice: &'a mut [u8]) -> Self {
586        // SAFETY: A standard Rust mutable reference is guaranteed to be valid and exclusive.
587        unsafe { Self::new(slice as *mut [u8]) }
588    }
589}
590
591impl<'a> From<&'a mut Vec<u8>> for MutPtrByteSlice<'a> {
592    fn from(vec: &'a mut Vec<u8>) -> Self {
593        Self::from(vec.as_mut_slice())
594    }
595}
596
597/// An iterator over read-only typed elements of a pointer slice.
598pub struct IterAs<'a, T> {
599    ptr: *const T,
600    end: *const T,
601    _marker: PhantomData<&'a T>,
602}
603
604impl<'a, T: Copy + FromBytes> Iterator for IterAs<'a, T> {
605    type Item = T;
606
607    fn next(&mut self) -> Option<Self::Item> {
608        if self.ptr == self.end {
609            None
610        } else {
611            let current = self.ptr;
612            // SAFETY: `self.ptr` is less than `self.end` (checked), so adding 1 is within the
613            // bounds of the allocation.
614            self.ptr = unsafe { self.ptr.add(1) };
615            // SAFETY: The pointer is guaranteed to be valid and aligned for `T` since alignment
616            // was verified when the iterator was created.
617            Some(unsafe { std::ptr::read(current) })
618        }
619    }
620
621    fn size_hint(&self) -> (usize, Option<usize>) {
622        let len = unsafe { self.end.offset_from(self.ptr) as usize };
623        (len, Some(len))
624    }
625}
626
627impl<T: Copy + FromBytes> ExactSizeIterator for IterAs<'_, T> {}
628
629/// An iterator over mutable typed elements of a pointer slice.
630pub struct IterAsMut<'a, T> {
631    ptr: *mut T,
632    end: *mut T,
633    _marker: PhantomData<&'a mut T>,
634}
635
636impl<'a, T: Copy + FromBytes> Iterator for IterAsMut<'a, T> {
637    type Item = ElemMut<'a, T>;
638
639    fn next(&mut self) -> Option<Self::Item> {
640        if self.ptr == self.end {
641            None
642        } else {
643            let current = self.ptr;
644            // SAFETY: `self.ptr` is less than `self.end` (checked), so adding 1 is within the
645            // bounds of the allocation.
646            self.ptr = unsafe { self.ptr.add(1) };
647            Some(ElemMut { ptr: current, _marker: PhantomData })
648        }
649    }
650
651    fn size_hint(&self) -> (usize, Option<usize>) {
652        let len = unsafe { self.end.offset_from(self.ptr) as usize };
653        (len, Some(len))
654    }
655}
656
657impl<T: Copy + FromBytes> ExactSizeIterator for IterAsMut<'_, T> {}
658
659/// A mutable typed element of a pointer slice.
660pub struct ElemMut<'a, T> {
661    ptr: *mut T,
662    _marker: PhantomData<&'a mut T>,
663}
664
665impl<T> ElemMut<'_, T> {
666    /// Returns the raw pointer to the element.
667    pub fn as_ptr(&self) -> *mut T {
668        self.ptr
669    }
670}
671
672impl<T: Copy + FromBytes> ElemMut<'_, T> {
673    /// Reads the value from the element.
674    ///
675    /// Since alignment and validity were verified once when the iterator was created,
676    /// this access is safe and fast.
677    pub fn read(&self) -> T {
678        // SAFETY: The pointer is guaranteed to be valid and aligned.
679        unsafe { std::ptr::read(self.ptr) }
680    }
681
682    /// Writes a value to the element.
683    ///
684    /// Since alignment and validity were verified once when the iterator was created,
685    /// this access is safe and fast.
686    pub fn write(&self, val: T) {
687        // SAFETY: The pointer is guaranteed to be valid and aligned.
688        unsafe { std::ptr::write(self.ptr, val) }
689    }
690}
691
692/// An iterator over read-only byte chunks of a pointer slice.
693#[derive(Debug)]
694pub struct Chunks<'a> {
695    slice: PtrByteSlice<'a>,
696    chunk_size: usize,
697    offset: usize,
698}
699
700impl<'a> Iterator for Chunks<'a> {
701    type Item = PtrByteSlice<'a>;
702
703    fn next(&mut self) -> Option<Self::Item> {
704        if self.offset >= self.slice.len() {
705            None
706        } else {
707            let len = std::cmp::min(self.chunk_size, self.slice.len() - self.offset);
708            let chunk = self.slice.subslice(self.offset..self.offset + len);
709            self.offset += len;
710            Some(chunk)
711        }
712    }
713
714    fn size_hint(&self) -> (usize, Option<usize>) {
715        let len = self.len();
716        (len, Some(len))
717    }
718}
719
720impl ExactSizeIterator for Chunks<'_> {
721    fn len(&self) -> usize {
722        let remaining = self.slice.len().saturating_sub(self.offset);
723        remaining.div_ceil(self.chunk_size)
724    }
725}
726
727impl std::iter::FusedIterator for Chunks<'_> {}
728
729/// An iterator over mutable byte chunks of a pointer slice.
730#[derive(Debug)]
731pub struct ChunksMut<'a> {
732    slice: MutPtrByteSlice<'a>,
733    chunk_size: usize,
734    offset: usize,
735}
736
737impl<'a> Iterator for ChunksMut<'a> {
738    type Item = MutPtrByteSlice<'a>;
739
740    fn next(&mut self) -> Option<Self::Item> {
741        if self.offset >= self.slice.len() {
742            None
743        } else {
744            let len = std::cmp::min(self.chunk_size, self.slice.len() - self.offset);
745            let chunk = self.slice.subslice_mut(self.offset..self.offset + len);
746            self.offset += len;
747            Some(chunk)
748        }
749    }
750
751    fn size_hint(&self) -> (usize, Option<usize>) {
752        let len = self.len();
753        (len, Some(len))
754    }
755}
756
757impl ExactSizeIterator for ChunksMut<'_> {
758    fn len(&self) -> usize {
759        let remaining = self.slice.len().saturating_sub(self.offset);
760        if remaining == 0 { 0 } else { remaining.div_ceil(self.chunk_size) }
761    }
762}
763
764impl std::iter::FusedIterator for ChunksMut<'_> {}
765
766impl std::io::Read for PtrByteSlice<'_> {
767    fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
768        let remaining = self.len();
769        if remaining == 0 {
770            return Ok(0);
771        }
772        let to_read = std::cmp::min(remaining, buf.len());
773        let (a, b) = self.split_at(to_read);
774        a.copy_to_slice(&mut buf[..to_read]);
775        *self = b;
776        Ok(to_read)
777    }
778
779    fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
780        if buf.len() > self.len() {
781            return Err(std::io::Error::new(
782                std::io::ErrorKind::UnexpectedEof,
783                "failed to fill whole buffer",
784            ));
785        }
786        let (a, b) = self.split_at(buf.len());
787        a.copy_to_slice(buf);
788        *self = b;
789        Ok(())
790    }
791
792    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> std::io::Result<usize> {
793        let len = self.len();
794        self.append_to(buf);
795        *self = self.subslice(len..len);
796        Ok(len)
797    }
798}
799
800#[cfg(test)]
801mod tests {
802    use super::*;
803    use std::io::{Read, Write};
804    use zerocopy::IntoBytes;
805
806    #[derive(Copy, Clone, Debug, FromBytes, IntoBytes)]
807    #[repr(C, align(4))]
808    struct Aligned4(u32);
809
810    #[test]
811    fn test_iter_as_success() {
812        let bytes = [0u8; 16];
813        let slice = PtrByteSlice::from(&bytes[..]);
814        let elems = slice.iter_as::<Aligned4>();
815        assert_eq!(elems.count(), 4);
816    }
817
818    #[test]
819    #[should_panic(expected = "Slice is not aligned to T")]
820    fn test_iter_as_unaligned_panic() {
821        #[repr(C, align(4))]
822        struct AligningBuffer {
823            buffer: [u8; 17],
824        }
825        let aligned = AligningBuffer { buffer: [0u8; 17] };
826        let slice = PtrByteSlice::from(&aligned.buffer[1..17]);
827        let _ = slice.iter_as::<Aligned4>();
828    }
829
830    #[test]
831    #[should_panic]
832    fn test_iter_as_missized_panic() {
833        let bytes = [0u8; 15];
834        let slice = PtrByteSlice::from(&bytes[..]);
835        let _ = slice.iter_as::<Aligned4>();
836    }
837
838    #[test]
839    fn test_iter_as_mut_success() {
840        let mut bytes = [0u8; 16];
841        let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
842        let elems = slice.iter_as_mut::<Aligned4>();
843        assert_eq!(elems.count(), 4);
844    }
845
846    #[test]
847    #[should_panic(expected = "Slice is not aligned to T")]
848    fn test_iter_as_mut_unaligned_panic() {
849        #[repr(C, align(4))]
850        struct AligningBuffer {
851            buffer: [u8; 17],
852        }
853        let mut aligned = AligningBuffer { buffer: [0u8; 17] };
854        let mut slice = MutPtrByteSlice::from(&mut aligned.buffer[1..17]);
855        let _ = slice.iter_as_mut::<Aligned4>();
856    }
857
858    #[test]
859    #[should_panic]
860    fn test_iter_as_mut_missized_panic() {
861        let mut bytes = [0u8; 15];
862        let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
863        let _ = slice.iter_as_mut::<Aligned4>();
864    }
865
866    #[test]
867    fn test_byte_chunks() {
868        let bytes = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10];
869        let slice = PtrByteSlice::from(&bytes[..]);
870        let chunks: Vec<_> = slice.chunks(4).map(|c| c.to_vec()).collect();
871        assert_eq!(chunks, vec![vec![1, 2, 3, 4], vec![5, 6, 7, 8], vec![9, 10]]);
872    }
873
874    #[test]
875    fn test_byte_chunks_mut() {
876        let mut bytes = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10];
877        let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
878        for mut chunk in slice.chunks_mut(4) {
879            chunk.fill(0);
880        }
881        assert_eq!(bytes, [0u8; 10]);
882    }
883
884    #[test]
885    fn test_reader() {
886        let bytes = [1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10];
887        let mut slice = PtrByteSlice::from(&bytes[..]);
888        let mut buf = [0u8; 4];
889        assert_eq!(Read::read(&mut slice, &mut buf).unwrap(), 4);
890        assert_eq!(buf, [1, 2, 3, 4]);
891        assert_eq!(slice.len(), 6);
892        let mut rest = Vec::new();
893        assert_eq!(slice.read_to_end(&mut rest).unwrap(), 6);
894        assert_eq!(rest, [5, 6, 7, 8, 9, 10]);
895        assert_eq!(slice.len(), 0);
896    }
897
898    #[test]
899    fn test_read_success() {
900        let bytes = [1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8];
901        let slice = PtrByteSlice::from(&bytes[..]);
902
903        let val = slice.read::<Aligned4>().unwrap();
904        // We use from_ne_bytes to be independent of endianness for the raw bytes comparison,
905        // but Aligned4 is just a wrapper around u32.
906        assert_eq!(val.0, u32::from_ne_bytes([1, 2, 3, 4]));
907
908        // Unaligned read
909        let sub = slice.subslice(1..8);
910        let val_unaligned = sub.read::<Aligned4>().unwrap();
911        assert_eq!(val_unaligned.0, u32::from_ne_bytes([2, 3, 4, 5]));
912    }
913
914    #[test]
915    fn test_read_bounds_failure() {
916        let bytes = [1u8, 2u8, 3u8];
917        let slice = PtrByteSlice::from(&bytes[..]);
918        assert!(slice.read::<Aligned4>().is_none());
919    }
920
921    #[test]
922    fn test_mut_read_write_success() {
923        let mut bytes = [0u8; 8];
924        let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
925
926        // Write aligned
927        slice.write(Aligned4(0x12345678)).unwrap();
928        assert_eq!(slice.read::<Aligned4>().unwrap().0, 0x12345678);
929
930        // Write unaligned
931        let mut sub = slice.subslice_mut(1..8);
932        sub.write(Aligned4(0xabcdef01)).unwrap();
933        assert_eq!(sub.read::<Aligned4>().unwrap().0, 0xabcdef01);
934    }
935
936    #[test]
937    fn test_mut_write_bounds_failure() {
938        let mut bytes = [0u8; 3];
939        let mut slice = MutPtrByteSlice::from(&mut bytes[..]);
940        assert!(slice.write(Aligned4(0)).is_none());
941    }
942
943    #[test]
944    fn test_writer() {
945        let mut bytes = [0u8; 16];
946        let slice = MutPtrByteSlice::from(&mut bytes[..]);
947        let mut writer = slice.writer();
948        assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
949        assert_eq!(writer.position(), 3);
950        writer.write_all(&[4, 5, 6, 7]).unwrap();
951        assert_eq!(writer.position(), 7);
952        assert_eq!(&bytes[..7], &[1, 2, 3, 4, 5, 6, 7]);
953    }
954
955    #[test]
956    fn test_writer_write_all_error() {
957        let mut bytes = [0u8; 4];
958        let slice = MutPtrByteSlice::from(&mut bytes[..]);
959        let mut writer = slice.writer();
960        let err = writer.write_all(&[1, 2, 3, 4, 5]).unwrap_err();
961        assert_eq!(err.kind(), std::io::ErrorKind::WriteZero);
962        assert_eq!(writer.position(), 0);
963    }
964
965    #[test]
966    fn test_writer_write_full_and_remaining() {
967        let mut bytes = [0u8; 4];
968        let slice = MutPtrByteSlice::from(&mut bytes[..]);
969        let mut writer = slice.writer();
970        assert_eq!(writer.write(&[1, 2, 3, 4, 5]).unwrap(), 4);
971        assert_eq!(writer.position(), 4);
972        assert_eq!(writer.write(&[6]).unwrap(), 0);
973        assert_eq!(writer.remaining().len(), 0);
974        writer.flush().unwrap();
975        let written = writer.into_written();
976        assert_eq!(written.len(), 4);
977        assert_eq!(&bytes[..], &[1, 2, 3, 4]);
978    }
979}