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