// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT//// Copyright 2024 The Fuchsia Authors//// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.// This file may not be copied, modified, or distributed except according to// those terms. //! Traits for types that encapsulate a `[u8]`.//!//! These traits are used to bound the `B` parameter of [`Ref`]. use core::{ cell, ops::{Deref, DerefMut},}; // For each trait polyfill, as soon as the corresponding feature is stable, the// polyfill import will be unused because method/function resolution will prefer// the inherent method/function over a trait method/function. Thus, we suppress// the `unused_imports` warning.//// See the documentation on `util::polyfills` for more information.#[allow(unused_imports)]use crate::util::polyfills::{self, NonNullExt as _, NumExt as _};#[cfg(doc)]use crate::Ref; /// A mutable or immutable reference to a byte slice.////// `ByteSlice` abstracts over the mutability of a byte slice reference, and is/// implemented for various special reference types such as/// [`Ref<[u8]>`](core::cell::Ref) and [`RefMut<[u8]>`](core::cell::RefMut).////// # Safety////// Implementations of `ByteSlice` must promise that their implementations of/// [`Deref`] and [`DerefMut`] are "stable". In particular, given `B: ByteSlice`/// and `b: B`, two calls, each to either `b.deref()` or `b.deref_mut()`, must/// return a byte slice with the same address and length. This must hold even if/// the two calls are separated by an arbitrary sequence of calls to methods on/// `ByteSlice`, [`ByteSliceMut`], [`IntoByteSlice`], or [`IntoByteSliceMut`],/// or on their super-traits. This does *not* need to hold if the two calls are/// separated by any method calls, field accesses, or field modifications *other/// than* those from these traits.////// Note that this also implies that, given `b: B`, the address and length/// cannot be modified via objects other than `b`, either on the same thread or/// on another thread.pub unsafe trait ByteSlice: Deref<Target = [u8]> + Sized {} /// A mutable reference to a byte slice.////// `ByteSliceMut` abstracts over various ways of storing a mutable reference to/// a byte slice, and is implemented for various special reference types such as/// `RefMut<[u8]>`.////// `ByteSliceMut` is a shorthand for [`ByteSlice`] and [`DerefMut`].pub trait ByteSliceMut: ByteSlice + DerefMut {}impl<B: ByteSlice + DerefMut> ByteSliceMut for B {} /// A [`ByteSlice`] which can be copied without violating dereference stability.////// # Safety////// If `B: CopyableByteSlice`, then the dereference stability properties/// required by [`ByteSlice`] (see that trait's safety documentation) do not/// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also/// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by/// copying `b`.pub unsafe trait CopyableByteSlice: ByteSlice + Copy + CloneableByteSlice {} /// A [`ByteSlice`] which can be cloned without violating dereference stability.////// # Safety////// If `B: CloneableByteSlice`, then the dereference stability properties/// required by [`ByteSlice`] (see that trait's safety documentation) do not/// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also/// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by/// `b.clone()`, `b.clone().clone()`, etc.pub unsafe trait CloneableByteSlice: ByteSlice + Clone {} /// A [`ByteSlice`] that can be split in two.////// # Safety////// Unsafe code may depend for its soundness on the assumption that `split_at`/// and `split_at_unchecked` are implemented correctly. In particular, given `B:/// SplitByteSlice` and `b: B`, if `b.deref()` returns a byte slice with address/// `addr` and length `len`, then if `split <= len`, both of these/// invocations:/// - `b.split_at(split)`/// - `b.split_at_unchecked(split)`////// ...will return `(first, second)` such that:/// - `first`'s address is `addr` and its length is `split`/// - `second`'s address is `addr + split` and its length is `len - split`pub unsafe trait SplitByteSlice: ByteSlice { /// Attempts to split `self` at the midpoint. /// /// `s.split_at(mid)` returns `Ok((s[..mid], s[mid..]))` if `mid <= /// s.deref().len()` and otherwise returns `Err(s)`. /// /// # Safety /// /// Unsafe code may rely on this function correctly implementing the above /// functionality. #[inline] fn split_at(self, mid: usize) -> Result<(Self, Self), Self> { if mid <= self.deref().len() { // SAFETY: Above, we ensure that `mid <= self.deref().len()`. By // invariant on `ByteSlice`, a supertrait of `SplitByteSlice`, // `.deref()` is guaranteed to be "stable"; i.e., it will always // dereference to a byte slice of the same address and length. Thus, // we can be sure that the above precondition remains satisfied // through the call to `split_at_unchecked`. unsafe { Ok(self.split_at_unchecked(mid)) } } else { Err(self) } } /// Splits the slice at the midpoint, possibly omitting bounds checks. /// /// `s.split_at_unchecked(mid)` returns `s[..mid]` and `s[mid..]`. /// /// # Safety /// /// `mid` must not be greater than `self.deref().len()`. /// /// # Panics /// /// Implementations of this method may choose to perform a bounds check and /// panic if `mid > self.deref().len()`. They may also panic for any other /// reason. Since it is optional, callers must not rely on this behavior for /// soundness. #[must_use] unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self);} /// A shorthand for [`SplitByteSlice`] and [`ByteSliceMut`].pub trait SplitByteSliceMut: SplitByteSlice + ByteSliceMut {}impl<B: SplitByteSlice + ByteSliceMut> SplitByteSliceMut for B {} #[allow(clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice`./// A [`ByteSlice`] that conveys no ownership, and so can be converted into a/// byte slice.////// Some `ByteSlice` types (notably, the standard library's [`Ref`] type) convey/// ownership, and so they cannot soundly be moved by-value into a byte slice/// type (`&[u8]`). Some methods in this crate's API (such as [`Ref::into_ref`])/// are only compatible with `ByteSlice` types without these ownership/// semantics.////// [`Ref`]: core::cell::Refpub unsafe trait IntoByteSlice<'a>: ByteSlice { /// Coverts `self` into a `&[u8]`. /// /// # Safety /// /// The returned reference has the same address and length as `self.deref()` /// and `self.deref_mut()`. /// /// Note that, combined with the safety invariant on [`ByteSlice`], this /// safety invariant implies that the returned reference is "stable" in the /// sense described in the `ByteSlice` docs. fn into_byte_slice(self) -> &'a [u8];} #[allow(clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice_mut`./// A [`ByteSliceMut`] that conveys no ownership, and so can be converted into a/// mutable byte slice.////// Some `ByteSliceMut` types (notably, the standard library's [`RefMut`] type)/// convey ownership, and so they cannot soundly be moved by-value into a byte/// slice type (`&mut [u8]`). Some methods in this crate's API (such as/// [`Ref::into_mut`]) are only compatible with `ByteSliceMut` types without/// these ownership semantics.////// [`RefMut`]: core::cell::RefMutpub unsafe trait IntoByteSliceMut<'a>: IntoByteSlice<'a> + ByteSliceMut { /// Coverts `self` into a `&mut [u8]`. /// /// # Safety /// /// The returned reference has the same address and length as `self.deref()` /// and `self.deref_mut()`. /// /// Note that, combined with the safety invariant on [`ByteSlice`], this /// safety invariant implies that the returned reference is "stable" in the /// sense described in the `ByteSlice` docs. fn into_byte_slice_mut(self) -> &'a mut [u8];} // FIXME(#429): Add a "SAFETY" comment and remove this `allow`.#[allow(clippy::undocumented_unsafe_blocks)]unsafe impl ByteSlice for &[u8] {} // FIXME(#429): Add a "SAFETY" comment and remove this `allow`.#[allow(clippy::undocumented_unsafe_blocks)]unsafe impl CopyableByteSlice for &[u8] {} // FIXME(#429): Add a "SAFETY" comment and remove this `allow`.#[allow(clippy::undocumented_unsafe_blocks)]unsafe impl CloneableByteSlice for &[u8] {} // SAFETY: This delegates to `polyfills:split_at_unchecked`, which is documented// to correctly split `self` into two slices at the given `mid` point.unsafe impl SplitByteSlice for &[u8] { #[inline] unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { // SAFETY: By contract on caller, `mid` is not greater than // `self.len()`. #[allow(clippy::multiple_unsafe_ops_per_block)] unsafe { (<[u8]>::get_unchecked(self, ..mid), <[u8]>::get_unchecked(self, mid..)) } }} // SAFETY: See inline.unsafe impl<'a> IntoByteSlice<'a> for &'a [u8] { #[inline(always)] fn into_byte_slice(self) -> &'a [u8] { // SAFETY: It would be patently insane to implement `<Deref for // &[u8]>::deref` as anything other than `fn deref(&self) -> &[u8] { // *self }`. Assuming this holds, then `self` is stable as required by // `into_byte_slice`. self }} // FIXME(#429): Add a "SAFETY" comment and remove this `allow`.#[allow(clippy::undocumented_unsafe_blocks)]unsafe impl ByteSlice for &mut [u8] {} // SAFETY: This delegates to `polyfills:split_at_mut_unchecked`, which is// documented to correctly split `self` into two slices at the given `mid`// point.unsafe impl SplitByteSlice for &mut [u8] { #[inline] unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { use core::slice::from_raw_parts_mut; // `l_ptr` is non-null, because `self` is non-null, by invariant on // `&mut [u8]`. let l_ptr = self.as_mut_ptr(); // SAFETY: By contract on caller, `mid` is not greater than // `self.len()`. let r_ptr = unsafe { l_ptr.add(mid) }; let l_len = mid; // SAFETY: By contract on caller, `mid` is not greater than // `self.len()`. // // FIXME(#67): Remove this allow. See NumExt for more details. #[allow(unstable_name_collisions)] let r_len = unsafe { self.len().unchecked_sub(mid) }; // SAFETY: These invocations of `from_raw_parts_mut` satisfy its // documented safety preconditions [1]: // - The data `l_ptr` and `r_ptr` are valid for both reads and writes of // `l_len` and `r_len` bytes, respectively, and they are trivially // aligned. In particular: // - The entire memory range of each slice is contained within a // single allocated object, since `l_ptr` and `r_ptr` are both // derived from within the address range of `self`. // - Both `l_ptr` and `r_ptr` are non-null and trivially aligned. // `self` is non-null by invariant on `&mut [u8]`, and the // operations that derive `l_ptr` and `r_ptr` from `self` do not // nullify either pointer. // - The data `l_ptr` and `r_ptr` point to `l_len` and `r_len`, // respectively, consecutive properly initialized values of type `u8`. // This is true for `self` by invariant on `&mut [u8]`, and remains // true for these two sub-slices of `self`. // - The memory referenced by the returned slice cannot be accessed // through any other pointer (not derived from the return value) for // the duration of lifetime `'a``, because: // - `split_at_unchecked` consumes `self` (which is not `Copy`), // - `split_at_unchecked` does not exfiltrate any references to this // memory, besides those references returned below, // - the returned slices are non-overlapping. // - The individual sizes of the sub-slices of `self` are no larger than // `isize::MAX`, because their combined sizes are no larger than // `isize::MAX`, by invariant on `self`. // // [1] https://doc.rust-lang.org/std/slice/fn.from_raw_parts_mut.html#safety #[allow(clippy::multiple_unsafe_ops_per_block)] unsafe { (from_raw_parts_mut(l_ptr, l_len), from_raw_parts_mut(r_ptr, r_len)) } }} // SAFETY: See inline.unsafe impl<'a> IntoByteSlice<'a> for &'a mut [u8] { #[inline(always)] fn into_byte_slice(self) -> &'a [u8] { // SAFETY: It would be patently insane to implement `<Deref for &mut // [u8]>::deref` as anything other than `fn deref(&self) -> &[u8] { // *self }`. Assuming this holds, then `self` is stable as required by // `into_byte_slice`. self }} // SAFETY: See inline.unsafe impl<'a> IntoByteSliceMut<'a> for &'a mut [u8] { #[inline(always)] fn into_byte_slice_mut(self) -> &'a mut [u8] { // SAFETY: It would be patently insane to implement `<DerefMut for &mut // [u8]>::deref` as anything other than `fn deref_mut(&mut self) -> &mut // [u8] { *self }`. Assuming this holds, then `self` is stable as // required by `into_byte_slice_mut`. self }} // FIXME(#429): Add a "SAFETY" comment and remove this `allow`.#[allow(clippy::undocumented_unsafe_blocks)]unsafe impl ByteSlice for cell::Ref<'_, [u8]> {} // SAFETY: This delegates to stdlib implementation of `Ref::map_split`, which is// assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is// documented to correctly split `self` into two slices at the given `mid`// point.unsafe impl SplitByteSlice for cell::Ref<'_, [u8]> { #[inline] unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { cell::Ref::map_split(self, |slice| // SAFETY: By precondition on caller, `mid` is not greater than // `slice.len()`. unsafe { SplitByteSlice::split_at_unchecked(slice, mid) }) }} // FIXME(#429): Add a "SAFETY" comment and remove this `allow`.#[allow(clippy::undocumented_unsafe_blocks)]unsafe impl ByteSlice for cell::RefMut<'_, [u8]> {} // SAFETY: This delegates to stdlib implementation of `RefMut::map_split`, which// is assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is// documented to correctly split `self` into two slices at the given `mid`// point.unsafe impl SplitByteSlice for cell::RefMut<'_, [u8]> { #[inline] unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { cell::RefMut::map_split(self, |slice| // SAFETY: By precondition on caller, `mid` is not greater than // `slice.len()` unsafe { SplitByteSlice::split_at_unchecked(slice, mid) }) }} #[cfg(kani)]mod proofs { use super::*; fn any_vec() -> Vec<u8> { let len = kani::any(); kani::assume(len <= crate::DstLayout::MAX_SIZE); vec![0u8; len] } #[kani::proof] fn prove_split_at_unchecked() { let v = any_vec(); let slc = v.as_slice(); let mid = kani::any(); kani::assume(mid <= slc.len()); let (l, r) = unsafe { slc.split_at_unchecked(mid) }; assert_eq!(l.len() + r.len(), slc.len()); let slc: *const _ = slc; let l: *const _ = l; let r: *const _ = r; assert_eq!(slc.cast::<u8>(), l.cast::<u8>()); assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>()); let mut v = any_vec(); let slc = v.as_mut_slice(); let len = slc.len(); let mid = kani::any(); kani::assume(mid <= slc.len()); let (l, r) = unsafe { slc.split_at_unchecked(mid) }; assert_eq!(l.len() + r.len(), len); let l: *mut _ = l; let r: *mut _ = r; let slc: *mut _ = slc; assert_eq!(slc.cast::<u8>(), l.cast::<u8>()); assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>()); }} #[cfg(test)]mod tests { use core::cell::RefCell; use super::*; #[test] fn test_ref_split_at_unchecked() { let cell = RefCell::new([1, 2, 3, 4]); let borrow = cell.borrow(); let slice_ref: cell::Ref<'_, [u8]> = cell::Ref::map(borrow, |a| &a[..]); // SAFETY: 2 is within bounds of [1, 2, 3, 4] let (l, r) = unsafe { slice_ref.split_at_unchecked(2) }; assert_eq!(*l, [1, 2]); assert_eq!(*r, [3, 4]); } #[test] fn test_ref_mut_split_at_unchecked() { let cell = RefCell::new([1, 2, 3, 4]); let borrow_mut = cell.borrow_mut(); let slice_ref_mut: cell::RefMut<'_, [u8]> = cell::RefMut::map(borrow_mut, |a| &mut a[..]); // SAFETY: 2 is within bounds of [1, 2, 3, 4] let (l, r) = unsafe { slice_ref_mut.split_at_unchecked(2) }; assert_eq!(*l, [1, 2]); assert_eq!(*r, [3, 4]); }}
// SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT
//
// Copyright 2024 The Fuchsia Authors
//
// Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0
// <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option.
// This file may not be copied, modified, or distributed except according to
// those terms.
//! Traits for types that encapsulate a `[u8]`.
//!
//! These traits are used to bound the `B` parameter of [`Ref`].
use core::{
cell,
ops::{Deref, DerefMut},
};
// For each trait polyfill, as soon as the corresponding feature is stable, the
// polyfill import will be unused because method/function resolution will prefer
// the inherent method/function over a trait method/function. Thus, we suppress
// the `unused_imports` warning.
//
// See the documentation on `util::polyfills` for more information.
#[allow(unused_imports)]
use crate::util::polyfills::{self, NonNullExt as _, NumExt as _};
#[cfg(doc)]
use crate::Ref;
/// A mutable or immutable reference to a byte slice.
///
/// `ByteSlice` abstracts over the mutability of a byte slice reference, and is
/// implemented for various special reference types such as
/// [`Ref<[u8]>`](core::cell::Ref) and [`RefMut<[u8]>`](core::cell::RefMut).
///
/// # Safety
///
/// Implementations of `ByteSlice` must promise that their implementations of
/// [`Deref`] and [`DerefMut`] are "stable". In particular, given `B: ByteSlice`
/// and `b: B`, two calls, each to either `b.deref()` or `b.deref_mut()`, must
/// return a byte slice with the same address and length. This must hold even if
/// the two calls are separated by an arbitrary sequence of calls to methods on
/// `ByteSlice`, [`ByteSliceMut`], [`IntoByteSlice`], or [`IntoByteSliceMut`],
/// or on their super-traits. This does *not* need to hold if the two calls are
/// separated by any method calls, field accesses, or field modifications *other
/// than* those from these traits.
///
/// Note that this also implies that, given `b: B`, the address and length
/// cannot be modified via objects other than `b`, either on the same thread or
/// on another thread.
pub unsafe trait ByteSlice: Deref<Target = [u8]> + Sized {}
/// A mutable reference to a byte slice.
///
/// `ByteSliceMut` abstracts over various ways of storing a mutable reference to
/// a byte slice, and is implemented for various special reference types such as
/// `RefMut<[u8]>`.
///
/// `ByteSliceMut` is a shorthand for [`ByteSlice`] and [`DerefMut`].
pub trait ByteSliceMut: ByteSlice + DerefMut {}
impl<B: ByteSlice + DerefMut> ByteSliceMut for B {}
/// A [`ByteSlice`] which can be copied without violating dereference stability.
///
/// # Safety
///
/// If `B: CopyableByteSlice`, then the dereference stability properties
/// required by [`ByteSlice`] (see that trait's safety documentation) do not
/// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also
/// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by
/// copying `b`.
pub unsafe trait CopyableByteSlice: ByteSlice + Copy + CloneableByteSlice {}
/// A [`ByteSlice`] which can be cloned without violating dereference stability.
///
/// # Safety
///
/// If `B: CloneableByteSlice`, then the dereference stability properties
/// required by [`ByteSlice`] (see that trait's safety documentation) do not
/// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also
/// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by
/// `b.clone()`, `b.clone().clone()`, etc.
pub unsafe trait CloneableByteSlice: ByteSlice + Clone {}
/// A [`ByteSlice`] that can be split in two.
///
/// # Safety
///
/// Unsafe code may depend for its soundness on the assumption that `split_at`
/// and `split_at_unchecked` are implemented correctly. In particular, given `B:
/// SplitByteSlice` and `b: B`, if `b.deref()` returns a byte slice with address
/// `addr` and length `len`, then if `split <= len`, both of these
/// invocations:
/// - `b.split_at(split)`
/// - `b.split_at_unchecked(split)`
///
/// ...will return `(first, second)` such that:
/// - `first`'s address is `addr` and its length is `split`
/// - `second`'s address is `addr + split` and its length is `len - split`
pub unsafe trait SplitByteSlice: ByteSlice {
/// Attempts to split `self` at the midpoint.
///
/// `s.split_at(mid)` returns `Ok((s[..mid], s[mid..]))` if `mid <=
/// s.deref().len()` and otherwise returns `Err(s)`.
///
/// # Safety
///
/// Unsafe code may rely on this function correctly implementing the above
/// functionality.
#[inline]
fn split_at(self, mid: usize) -> Result<(Self, Self), Self> {
if mid <= self.deref().len() {
// SAFETY: Above, we ensure that `mid <= self.deref().len()`. By
// invariant on `ByteSlice`, a supertrait of `SplitByteSlice`,
// `.deref()` is guaranteed to be "stable"; i.e., it will always
// dereference to a byte slice of the same address and length. Thus,
// we can be sure that the above precondition remains satisfied
// through the call to `split_at_unchecked`.
unsafe { Ok(self.split_at_unchecked(mid)) }
} else {
Err(self)
}
}
/// Splits the slice at the midpoint, possibly omitting bounds checks.
///
/// `s.split_at_unchecked(mid)` returns `s[..mid]` and `s[mid..]`.
///
/// # Safety
///
/// `mid` must not be greater than `self.deref().len()`.
///
/// # Panics
///
/// Implementations of this method may choose to perform a bounds check and
/// panic if `mid > self.deref().len()`. They may also panic for any other
/// reason. Since it is optional, callers must not rely on this behavior for
/// soundness.
#[must_use]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self);
}
/// A shorthand for [`SplitByteSlice`] and [`ByteSliceMut`].
pub trait SplitByteSliceMut: SplitByteSlice + ByteSliceMut {}
impl<B: SplitByteSlice + ByteSliceMut> SplitByteSliceMut for B {}
#[allow(clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice`.
/// A [`ByteSlice`] that conveys no ownership, and so can be converted into a
/// byte slice.
///
/// Some `ByteSlice` types (notably, the standard library's [`Ref`] type) convey
/// ownership, and so they cannot soundly be moved by-value into a byte slice
/// type (`&[u8]`). Some methods in this crate's API (such as [`Ref::into_ref`])
/// are only compatible with `ByteSlice` types without these ownership
/// semantics.
///
/// [`Ref`]: core::cell::Ref
pub unsafe trait IntoByteSlice<'a>: ByteSlice {
/// Coverts `self` into a `&[u8]`.
///
/// # Safety
///
/// The returned reference has the same address and length as `self.deref()`
/// and `self.deref_mut()`.
///
/// Note that, combined with the safety invariant on [`ByteSlice`], this
/// safety invariant implies that the returned reference is "stable" in the
/// sense described in the `ByteSlice` docs.
fn into_byte_slice(self) -> &'a [u8];
}
#[allow(clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice_mut`.
/// A [`ByteSliceMut`] that conveys no ownership, and so can be converted into a
/// mutable byte slice.
///
/// Some `ByteSliceMut` types (notably, the standard library's [`RefMut`] type)
/// convey ownership, and so they cannot soundly be moved by-value into a byte
/// slice type (`&mut [u8]`). Some methods in this crate's API (such as
/// [`Ref::into_mut`]) are only compatible with `ByteSliceMut` types without
/// these ownership semantics.
///
/// [`RefMut`]: core::cell::RefMut
pub unsafe trait IntoByteSliceMut<'a>: IntoByteSlice<'a> + ByteSliceMut {
/// Coverts `self` into a `&mut [u8]`.
///
/// # Safety
///
/// The returned reference has the same address and length as `self.deref()`
/// and `self.deref_mut()`.
///
/// Note that, combined with the safety invariant on [`ByteSlice`], this
/// safety invariant implies that the returned reference is "stable" in the
/// sense described in the `ByteSlice` docs.
fn into_byte_slice_mut(self) -> &'a mut [u8];
}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for &[u8] {}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl CopyableByteSlice for &[u8] {}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl CloneableByteSlice for &[u8] {}
// SAFETY: This delegates to `polyfills:split_at_unchecked`, which is documented
// to correctly split `self` into two slices at the given `mid` point.
unsafe impl SplitByteSlice for &[u8] {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
// SAFETY: By contract on caller, `mid` is not greater than
// `self.len()`.
#[allow(clippy::multiple_unsafe_ops_per_block)]
unsafe {
(<[u8]>::get_unchecked(self, ..mid), <[u8]>::get_unchecked(self, mid..))
}
}
}
// SAFETY: See inline.
unsafe impl<'a> IntoByteSlice<'a> for &'a [u8] {
#[inline(always)]
fn into_byte_slice(self) -> &'a [u8] {
// SAFETY: It would be patently insane to implement `<Deref for
// &[u8]>::deref` as anything other than `fn deref(&self) -> &[u8] {
// *self }`. Assuming this holds, then `self` is stable as required by
// `into_byte_slice`.
self
}
}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for &mut [u8] {}
// SAFETY: This delegates to `polyfills:split_at_mut_unchecked`, which is
// documented to correctly split `self` into two slices at the given `mid`
// point.
unsafe impl SplitByteSlice for &mut [u8] {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
use core::slice::from_raw_parts_mut;
// `l_ptr` is non-null, because `self` is non-null, by invariant on
// `&mut [u8]`.
let l_ptr = self.as_mut_ptr();
// SAFETY: By contract on caller, `mid` is not greater than
// `self.len()`.
let r_ptr = unsafe { l_ptr.add(mid) };
let l_len = mid;
// SAFETY: By contract on caller, `mid` is not greater than
// `self.len()`.
//
// FIXME(#67): Remove this allow. See NumExt for more details.
#[allow(unstable_name_collisions)]
let r_len = unsafe { self.len().unchecked_sub(mid) };
// SAFETY: These invocations of `from_raw_parts_mut` satisfy its
// documented safety preconditions [1]:
// - The data `l_ptr` and `r_ptr` are valid for both reads and writes of
// `l_len` and `r_len` bytes, respectively, and they are trivially
// aligned. In particular:
// - The entire memory range of each slice is contained within a
// single allocated object, since `l_ptr` and `r_ptr` are both
// derived from within the address range of `self`.
// - Both `l_ptr` and `r_ptr` are non-null and trivially aligned.
// `self` is non-null by invariant on `&mut [u8]`, and the
// operations that derive `l_ptr` and `r_ptr` from `self` do not
// nullify either pointer.
// - The data `l_ptr` and `r_ptr` point to `l_len` and `r_len`,
// respectively, consecutive properly initialized values of type `u8`.
// This is true for `self` by invariant on `&mut [u8]`, and remains
// true for these two sub-slices of `self`.
// - The memory referenced by the returned slice cannot be accessed
// through any other pointer (not derived from the return value) for
// the duration of lifetime `'a``, because:
// - `split_at_unchecked` consumes `self` (which is not `Copy`),
// - `split_at_unchecked` does not exfiltrate any references to this
// memory, besides those references returned below,
// - the returned slices are non-overlapping.
// - The individual sizes of the sub-slices of `self` are no larger than
// `isize::MAX`, because their combined sizes are no larger than
// `isize::MAX`, by invariant on `self`.
//
// [1] https://doc.rust-lang.org/std/slice/fn.from_raw_parts_mut.html#safety
#[allow(clippy::multiple_unsafe_ops_per_block)]
unsafe {
(from_raw_parts_mut(l_ptr, l_len), from_raw_parts_mut(r_ptr, r_len))
}
}
}
// SAFETY: See inline.
unsafe impl<'a> IntoByteSlice<'a> for &'a mut [u8] {
#[inline(always)]
fn into_byte_slice(self) -> &'a [u8] {
// SAFETY: It would be patently insane to implement `<Deref for &mut
// [u8]>::deref` as anything other than `fn deref(&self) -> &[u8] {
// *self }`. Assuming this holds, then `self` is stable as required by
// `into_byte_slice`.
self
}
}
// SAFETY: See inline.
unsafe impl<'a> IntoByteSliceMut<'a> for &'a mut [u8] {
#[inline(always)]
fn into_byte_slice_mut(self) -> &'a mut [u8] {
// SAFETY: It would be patently insane to implement `<DerefMut for &mut
// [u8]>::deref` as anything other than `fn deref_mut(&mut self) -> &mut
// [u8] { *self }`. Assuming this holds, then `self` is stable as
// required by `into_byte_slice_mut`.
self
}
}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for cell::Ref<'_, [u8]> {}
// SAFETY: This delegates to stdlib implementation of `Ref::map_split`, which is
// assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is
// documented to correctly split `self` into two slices at the given `mid`
// point.
unsafe impl SplitByteSlice for cell::Ref<'_, [u8]> {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
cell::Ref::map_split(self, |slice|
// SAFETY: By precondition on caller, `mid` is not greater than
// `slice.len()`.
unsafe {
SplitByteSlice::split_at_unchecked(slice, mid)
})
}
}
// FIXME(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for cell::RefMut<'_, [u8]> {}
// SAFETY: This delegates to stdlib implementation of `RefMut::map_split`, which
// is assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is
// documented to correctly split `self` into two slices at the given `mid`
// point.
unsafe impl SplitByteSlice for cell::RefMut<'_, [u8]> {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
cell::RefMut::map_split(self, |slice|
// SAFETY: By precondition on caller, `mid` is not greater than
// `slice.len()`
unsafe {
SplitByteSlice::split_at_unchecked(slice, mid)
})
}
}
#[cfg(kani)]
mod proofs {
use super::*;
fn any_vec() -> Vec<u8> {
let len = kani::any();
kani::assume(len <= crate::DstLayout::MAX_SIZE);
vec![0u8; len]
}
#[kani::proof]
fn prove_split_at_unchecked() {
let v = any_vec();
let slc = v.as_slice();
let mid = kani::any();
kani::assume(mid <= slc.len());
let (l, r) = unsafe { slc.split_at_unchecked(mid) };
assert_eq!(l.len() + r.len(), slc.len());
let slc: *const _ = slc;
let l: *const _ = l;
let r: *const _ = r;
assert_eq!(slc.cast::<u8>(), l.cast::<u8>());
assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>());
let mut v = any_vec();
let slc = v.as_mut_slice();
let len = slc.len();
let mid = kani::any();
kani::assume(mid <= slc.len());
let (l, r) = unsafe { slc.split_at_unchecked(mid) };
assert_eq!(l.len() + r.len(), len);
let l: *mut _ = l;
let r: *mut _ = r;
let slc: *mut _ = slc;
assert_eq!(slc.cast::<u8>(), l.cast::<u8>());
assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>());
}
}
#[cfg(test)]
mod tests {
use core::cell::RefCell;
use super::*;
#[test]
fn test_ref_split_at_unchecked() {
let cell = RefCell::new([1, 2, 3, 4]);
let borrow = cell.borrow();
let slice_ref: cell::Ref<'_, [u8]> = cell::Ref::map(borrow, |a| &a[..]);
// SAFETY: 2 is within bounds of [1, 2, 3, 4]
let (l, r) = unsafe { slice_ref.split_at_unchecked(2) };
assert_eq!(*l, [1, 2]);
assert_eq!(*r, [3, 4]);
}
#[test]
fn test_ref_mut_split_at_unchecked() {
let cell = RefCell::new([1, 2, 3, 4]);
let borrow_mut = cell.borrow_mut();
let slice_ref_mut: cell::RefMut<'_, [u8]> = cell::RefMut::map(borrow_mut, |a| &mut a[..]);
// SAFETY: 2 is within bounds of [1, 2, 3, 4]
let (l, r) = unsafe { slice_ref_mut.split_at_unchecked(2) };
assert_eq!(*l, [1, 2]);
assert_eq!(*r, [3, 4]);
}
}