1*499dc02cSMiguel Ojeda // SPDX-License-Identifier: (BSD-2-Clause OR Apache-2.0) OR MIT 2*499dc02cSMiguel Ojeda 3c3739801SMiguel Ojeda // Copyright 2024 The Fuchsia Authors 4c3739801SMiguel Ojeda // 5c3739801SMiguel Ojeda // Licensed under a BSD-style license <LICENSE-BSD>, Apache License, Version 2.0 6c3739801SMiguel Ojeda // <LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0>, or the MIT 7c3739801SMiguel Ojeda // license <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your option. 8c3739801SMiguel Ojeda // This file may not be copied, modified, or distributed except according to 9c3739801SMiguel Ojeda // those terms. 10c3739801SMiguel Ojeda 11c3739801SMiguel Ojeda //! Traits for types that encapsulate a `[u8]`. 12c3739801SMiguel Ojeda //! 13c3739801SMiguel Ojeda //! These traits are used to bound the `B` parameter of [`Ref`]. 14c3739801SMiguel Ojeda 15c3739801SMiguel Ojeda use core::{ 16c3739801SMiguel Ojeda cell, 17c3739801SMiguel Ojeda ops::{Deref, DerefMut}, 18c3739801SMiguel Ojeda }; 19c3739801SMiguel Ojeda 20c3739801SMiguel Ojeda // For each trait polyfill, as soon as the corresponding feature is stable, the 21c3739801SMiguel Ojeda // polyfill import will be unused because method/function resolution will prefer 22c3739801SMiguel Ojeda // the inherent method/function over a trait method/function. Thus, we suppress 23c3739801SMiguel Ojeda // the `unused_imports` warning. 24c3739801SMiguel Ojeda // 25c3739801SMiguel Ojeda // See the documentation on `util::polyfills` for more information. 26c3739801SMiguel Ojeda #[allow(unused_imports)] 27c3739801SMiguel Ojeda use crate::util::polyfills::{self, NonNullExt as _, NumExt as _}; 28c3739801SMiguel Ojeda #[cfg(doc)] 29c3739801SMiguel Ojeda use crate::Ref; 30c3739801SMiguel Ojeda 31c3739801SMiguel Ojeda /// A mutable or immutable reference to a byte slice. 32c3739801SMiguel Ojeda /// 33c3739801SMiguel Ojeda /// `ByteSlice` abstracts over the mutability of a byte slice reference, and is 34c3739801SMiguel Ojeda /// implemented for various special reference types such as 35c3739801SMiguel Ojeda /// [`Ref<[u8]>`](core::cell::Ref) and [`RefMut<[u8]>`](core::cell::RefMut). 36c3739801SMiguel Ojeda /// 37c3739801SMiguel Ojeda /// # Safety 38c3739801SMiguel Ojeda /// 39c3739801SMiguel Ojeda /// Implementations of `ByteSlice` must promise that their implementations of 40c3739801SMiguel Ojeda /// [`Deref`] and [`DerefMut`] are "stable". In particular, given `B: ByteSlice` 41c3739801SMiguel Ojeda /// and `b: B`, two calls, each to either `b.deref()` or `b.deref_mut()`, must 42c3739801SMiguel Ojeda /// return a byte slice with the same address and length. This must hold even if 43c3739801SMiguel Ojeda /// the two calls are separated by an arbitrary sequence of calls to methods on 44c3739801SMiguel Ojeda /// `ByteSlice`, [`ByteSliceMut`], [`IntoByteSlice`], or [`IntoByteSliceMut`], 45c3739801SMiguel Ojeda /// or on their super-traits. This does *not* need to hold if the two calls are 46c3739801SMiguel Ojeda /// separated by any method calls, field accesses, or field modifications *other 47c3739801SMiguel Ojeda /// than* those from these traits. 48c3739801SMiguel Ojeda /// 49c3739801SMiguel Ojeda /// Note that this also implies that, given `b: B`, the address and length 50c3739801SMiguel Ojeda /// cannot be modified via objects other than `b`, either on the same thread or 51c3739801SMiguel Ojeda /// on another thread. 52c3739801SMiguel Ojeda pub unsafe trait ByteSlice: Deref<Target = [u8]> + Sized {} 53c3739801SMiguel Ojeda 54c3739801SMiguel Ojeda /// A mutable reference to a byte slice. 55c3739801SMiguel Ojeda /// 56c3739801SMiguel Ojeda /// `ByteSliceMut` abstracts over various ways of storing a mutable reference to 57c3739801SMiguel Ojeda /// a byte slice, and is implemented for various special reference types such as 58c3739801SMiguel Ojeda /// `RefMut<[u8]>`. 59c3739801SMiguel Ojeda /// 60c3739801SMiguel Ojeda /// `ByteSliceMut` is a shorthand for [`ByteSlice`] and [`DerefMut`]. 61c3739801SMiguel Ojeda pub trait ByteSliceMut: ByteSlice + DerefMut {} 62c3739801SMiguel Ojeda impl<B: ByteSlice + DerefMut> ByteSliceMut for B {} 63c3739801SMiguel Ojeda 64c3739801SMiguel Ojeda /// A [`ByteSlice`] which can be copied without violating dereference stability. 65c3739801SMiguel Ojeda /// 66c3739801SMiguel Ojeda /// # Safety 67c3739801SMiguel Ojeda /// 68c3739801SMiguel Ojeda /// If `B: CopyableByteSlice`, then the dereference stability properties 69c3739801SMiguel Ojeda /// required by [`ByteSlice`] (see that trait's safety documentation) do not 70c3739801SMiguel Ojeda /// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also 71c3739801SMiguel Ojeda /// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by 72c3739801SMiguel Ojeda /// copying `b`. 73c3739801SMiguel Ojeda pub unsafe trait CopyableByteSlice: ByteSlice + Copy + CloneableByteSlice {} 74c3739801SMiguel Ojeda 75c3739801SMiguel Ojeda /// A [`ByteSlice`] which can be cloned without violating dereference stability. 76c3739801SMiguel Ojeda /// 77c3739801SMiguel Ojeda /// # Safety 78c3739801SMiguel Ojeda /// 79c3739801SMiguel Ojeda /// If `B: CloneableByteSlice`, then the dereference stability properties 80c3739801SMiguel Ojeda /// required by [`ByteSlice`] (see that trait's safety documentation) do not 81c3739801SMiguel Ojeda /// only hold regarding two calls to `b.deref()` or `b.deref_mut()`, but also 82c3739801SMiguel Ojeda /// hold regarding `c.deref()` or `c.deref_mut()`, where `c` is produced by 83c3739801SMiguel Ojeda /// `b.clone()`, `b.clone().clone()`, etc. 84c3739801SMiguel Ojeda pub unsafe trait CloneableByteSlice: ByteSlice + Clone {} 85c3739801SMiguel Ojeda 86c3739801SMiguel Ojeda /// A [`ByteSlice`] that can be split in two. 87c3739801SMiguel Ojeda /// 88c3739801SMiguel Ojeda /// # Safety 89c3739801SMiguel Ojeda /// 90c3739801SMiguel Ojeda /// Unsafe code may depend for its soundness on the assumption that `split_at` 91c3739801SMiguel Ojeda /// and `split_at_unchecked` are implemented correctly. In particular, given `B: 92c3739801SMiguel Ojeda /// SplitByteSlice` and `b: B`, if `b.deref()` returns a byte slice with address 93c3739801SMiguel Ojeda /// `addr` and length `len`, then if `split <= len`, both of these 94c3739801SMiguel Ojeda /// invocations: 95c3739801SMiguel Ojeda /// - `b.split_at(split)` 96c3739801SMiguel Ojeda /// - `b.split_at_unchecked(split)` 97c3739801SMiguel Ojeda /// 98c3739801SMiguel Ojeda /// ...will return `(first, second)` such that: 99c3739801SMiguel Ojeda /// - `first`'s address is `addr` and its length is `split` 100c3739801SMiguel Ojeda /// - `second`'s address is `addr + split` and its length is `len - split` 101c3739801SMiguel Ojeda pub unsafe trait SplitByteSlice: ByteSlice { 102c3739801SMiguel Ojeda /// Attempts to split `self` at the midpoint. 103c3739801SMiguel Ojeda /// 104c3739801SMiguel Ojeda /// `s.split_at(mid)` returns `Ok((s[..mid], s[mid..]))` if `mid <= 105c3739801SMiguel Ojeda /// s.deref().len()` and otherwise returns `Err(s)`. 106c3739801SMiguel Ojeda /// 107c3739801SMiguel Ojeda /// # Safety 108c3739801SMiguel Ojeda /// 109c3739801SMiguel Ojeda /// Unsafe code may rely on this function correctly implementing the above 110c3739801SMiguel Ojeda /// functionality. 111c3739801SMiguel Ojeda #[inline] 112c3739801SMiguel Ojeda fn split_at(self, mid: usize) -> Result<(Self, Self), Self> { 113c3739801SMiguel Ojeda if mid <= self.deref().len() { 114c3739801SMiguel Ojeda // SAFETY: Above, we ensure that `mid <= self.deref().len()`. By 115c3739801SMiguel Ojeda // invariant on `ByteSlice`, a supertrait of `SplitByteSlice`, 116c3739801SMiguel Ojeda // `.deref()` is guaranteed to be "stable"; i.e., it will always 117c3739801SMiguel Ojeda // dereference to a byte slice of the same address and length. Thus, 118c3739801SMiguel Ojeda // we can be sure that the above precondition remains satisfied 119c3739801SMiguel Ojeda // through the call to `split_at_unchecked`. 120c3739801SMiguel Ojeda unsafe { Ok(self.split_at_unchecked(mid)) } 121c3739801SMiguel Ojeda } else { 122c3739801SMiguel Ojeda Err(self) 123c3739801SMiguel Ojeda } 124c3739801SMiguel Ojeda } 125c3739801SMiguel Ojeda 126c3739801SMiguel Ojeda /// Splits the slice at the midpoint, possibly omitting bounds checks. 127c3739801SMiguel Ojeda /// 128c3739801SMiguel Ojeda /// `s.split_at_unchecked(mid)` returns `s[..mid]` and `s[mid..]`. 129c3739801SMiguel Ojeda /// 130c3739801SMiguel Ojeda /// # Safety 131c3739801SMiguel Ojeda /// 132c3739801SMiguel Ojeda /// `mid` must not be greater than `self.deref().len()`. 133c3739801SMiguel Ojeda /// 134c3739801SMiguel Ojeda /// # Panics 135c3739801SMiguel Ojeda /// 136c3739801SMiguel Ojeda /// Implementations of this method may choose to perform a bounds check and 137c3739801SMiguel Ojeda /// panic if `mid > self.deref().len()`. They may also panic for any other 138c3739801SMiguel Ojeda /// reason. Since it is optional, callers must not rely on this behavior for 139c3739801SMiguel Ojeda /// soundness. 140c3739801SMiguel Ojeda #[must_use] 141c3739801SMiguel Ojeda unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self); 142c3739801SMiguel Ojeda } 143c3739801SMiguel Ojeda 144c3739801SMiguel Ojeda /// A shorthand for [`SplitByteSlice`] and [`ByteSliceMut`]. 145c3739801SMiguel Ojeda pub trait SplitByteSliceMut: SplitByteSlice + ByteSliceMut {} 146c3739801SMiguel Ojeda impl<B: SplitByteSlice + ByteSliceMut> SplitByteSliceMut for B {} 147c3739801SMiguel Ojeda 148c3739801SMiguel Ojeda #[allow(clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice`. 149c3739801SMiguel Ojeda /// A [`ByteSlice`] that conveys no ownership, and so can be converted into a 150c3739801SMiguel Ojeda /// byte slice. 151c3739801SMiguel Ojeda /// 152c3739801SMiguel Ojeda /// Some `ByteSlice` types (notably, the standard library's [`Ref`] type) convey 153c3739801SMiguel Ojeda /// ownership, and so they cannot soundly be moved by-value into a byte slice 154c3739801SMiguel Ojeda /// type (`&[u8]`). Some methods in this crate's API (such as [`Ref::into_ref`]) 155c3739801SMiguel Ojeda /// are only compatible with `ByteSlice` types without these ownership 156c3739801SMiguel Ojeda /// semantics. 157c3739801SMiguel Ojeda /// 158c3739801SMiguel Ojeda /// [`Ref`]: core::cell::Ref 159c3739801SMiguel Ojeda pub unsafe trait IntoByteSlice<'a>: ByteSlice { 160c3739801SMiguel Ojeda /// Coverts `self` into a `&[u8]`. 161c3739801SMiguel Ojeda /// 162c3739801SMiguel Ojeda /// # Safety 163c3739801SMiguel Ojeda /// 164c3739801SMiguel Ojeda /// The returned reference has the same address and length as `self.deref()` 165c3739801SMiguel Ojeda /// and `self.deref_mut()`. 166c3739801SMiguel Ojeda /// 167c3739801SMiguel Ojeda /// Note that, combined with the safety invariant on [`ByteSlice`], this 168c3739801SMiguel Ojeda /// safety invariant implies that the returned reference is "stable" in the 169c3739801SMiguel Ojeda /// sense described in the `ByteSlice` docs. 170c3739801SMiguel Ojeda fn into_byte_slice(self) -> &'a [u8]; 171c3739801SMiguel Ojeda } 172c3739801SMiguel Ojeda 173c3739801SMiguel Ojeda #[allow(clippy::missing_safety_doc)] // There's a `Safety` section on `into_byte_slice_mut`. 174c3739801SMiguel Ojeda /// A [`ByteSliceMut`] that conveys no ownership, and so can be converted into a 175c3739801SMiguel Ojeda /// mutable byte slice. 176c3739801SMiguel Ojeda /// 177c3739801SMiguel Ojeda /// Some `ByteSliceMut` types (notably, the standard library's [`RefMut`] type) 178c3739801SMiguel Ojeda /// convey ownership, and so they cannot soundly be moved by-value into a byte 179c3739801SMiguel Ojeda /// slice type (`&mut [u8]`). Some methods in this crate's API (such as 180c3739801SMiguel Ojeda /// [`Ref::into_mut`]) are only compatible with `ByteSliceMut` types without 181c3739801SMiguel Ojeda /// these ownership semantics. 182c3739801SMiguel Ojeda /// 183c3739801SMiguel Ojeda /// [`RefMut`]: core::cell::RefMut 184c3739801SMiguel Ojeda pub unsafe trait IntoByteSliceMut<'a>: IntoByteSlice<'a> + ByteSliceMut { 185c3739801SMiguel Ojeda /// Coverts `self` into a `&mut [u8]`. 186c3739801SMiguel Ojeda /// 187c3739801SMiguel Ojeda /// # Safety 188c3739801SMiguel Ojeda /// 189c3739801SMiguel Ojeda /// The returned reference has the same address and length as `self.deref()` 190c3739801SMiguel Ojeda /// and `self.deref_mut()`. 191c3739801SMiguel Ojeda /// 192c3739801SMiguel Ojeda /// Note that, combined with the safety invariant on [`ByteSlice`], this 193c3739801SMiguel Ojeda /// safety invariant implies that the returned reference is "stable" in the 194c3739801SMiguel Ojeda /// sense described in the `ByteSlice` docs. 195c3739801SMiguel Ojeda fn into_byte_slice_mut(self) -> &'a mut [u8]; 196c3739801SMiguel Ojeda } 197c3739801SMiguel Ojeda 198c3739801SMiguel Ojeda // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. 199c3739801SMiguel Ojeda #[allow(clippy::undocumented_unsafe_blocks)] 200c3739801SMiguel Ojeda unsafe impl ByteSlice for &[u8] {} 201c3739801SMiguel Ojeda 202c3739801SMiguel Ojeda // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. 203c3739801SMiguel Ojeda #[allow(clippy::undocumented_unsafe_blocks)] 204c3739801SMiguel Ojeda unsafe impl CopyableByteSlice for &[u8] {} 205c3739801SMiguel Ojeda 206c3739801SMiguel Ojeda // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. 207c3739801SMiguel Ojeda #[allow(clippy::undocumented_unsafe_blocks)] 208c3739801SMiguel Ojeda unsafe impl CloneableByteSlice for &[u8] {} 209c3739801SMiguel Ojeda 210c3739801SMiguel Ojeda // SAFETY: This delegates to `polyfills:split_at_unchecked`, which is documented 211c3739801SMiguel Ojeda // to correctly split `self` into two slices at the given `mid` point. 212c3739801SMiguel Ojeda unsafe impl SplitByteSlice for &[u8] { 213c3739801SMiguel Ojeda #[inline] 214c3739801SMiguel Ojeda unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { 215c3739801SMiguel Ojeda // SAFETY: By contract on caller, `mid` is not greater than 216c3739801SMiguel Ojeda // `self.len()`. 217c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)] 218c3739801SMiguel Ojeda unsafe { 219c3739801SMiguel Ojeda (<[u8]>::get_unchecked(self, ..mid), <[u8]>::get_unchecked(self, mid..)) 220c3739801SMiguel Ojeda } 221c3739801SMiguel Ojeda } 222c3739801SMiguel Ojeda } 223c3739801SMiguel Ojeda 224c3739801SMiguel Ojeda // SAFETY: See inline. 225c3739801SMiguel Ojeda unsafe impl<'a> IntoByteSlice<'a> for &'a [u8] { 226c3739801SMiguel Ojeda #[inline(always)] 227c3739801SMiguel Ojeda fn into_byte_slice(self) -> &'a [u8] { 228c3739801SMiguel Ojeda // SAFETY: It would be patently insane to implement `<Deref for 229c3739801SMiguel Ojeda // &[u8]>::deref` as anything other than `fn deref(&self) -> &[u8] { 230c3739801SMiguel Ojeda // *self }`. Assuming this holds, then `self` is stable as required by 231c3739801SMiguel Ojeda // `into_byte_slice`. 232c3739801SMiguel Ojeda self 233c3739801SMiguel Ojeda } 234c3739801SMiguel Ojeda } 235c3739801SMiguel Ojeda 236c3739801SMiguel Ojeda // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. 237c3739801SMiguel Ojeda #[allow(clippy::undocumented_unsafe_blocks)] 238c3739801SMiguel Ojeda unsafe impl ByteSlice for &mut [u8] {} 239c3739801SMiguel Ojeda 240c3739801SMiguel Ojeda // SAFETY: This delegates to `polyfills:split_at_mut_unchecked`, which is 241c3739801SMiguel Ojeda // documented to correctly split `self` into two slices at the given `mid` 242c3739801SMiguel Ojeda // point. 243c3739801SMiguel Ojeda unsafe impl SplitByteSlice for &mut [u8] { 244c3739801SMiguel Ojeda #[inline] 245c3739801SMiguel Ojeda unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { 246c3739801SMiguel Ojeda use core::slice::from_raw_parts_mut; 247c3739801SMiguel Ojeda 248c3739801SMiguel Ojeda // `l_ptr` is non-null, because `self` is non-null, by invariant on 249c3739801SMiguel Ojeda // `&mut [u8]`. 250c3739801SMiguel Ojeda let l_ptr = self.as_mut_ptr(); 251c3739801SMiguel Ojeda 252c3739801SMiguel Ojeda // SAFETY: By contract on caller, `mid` is not greater than 253c3739801SMiguel Ojeda // `self.len()`. 254c3739801SMiguel Ojeda let r_ptr = unsafe { l_ptr.add(mid) }; 255c3739801SMiguel Ojeda 256c3739801SMiguel Ojeda let l_len = mid; 257c3739801SMiguel Ojeda 258c3739801SMiguel Ojeda // SAFETY: By contract on caller, `mid` is not greater than 259c3739801SMiguel Ojeda // `self.len()`. 260c3739801SMiguel Ojeda // 261c3739801SMiguel Ojeda // FIXME(#67): Remove this allow. See NumExt for more details. 262c3739801SMiguel Ojeda #[allow(unstable_name_collisions)] 263c3739801SMiguel Ojeda let r_len = unsafe { self.len().unchecked_sub(mid) }; 264c3739801SMiguel Ojeda 265c3739801SMiguel Ojeda // SAFETY: These invocations of `from_raw_parts_mut` satisfy its 266c3739801SMiguel Ojeda // documented safety preconditions [1]: 267c3739801SMiguel Ojeda // - The data `l_ptr` and `r_ptr` are valid for both reads and writes of 268c3739801SMiguel Ojeda // `l_len` and `r_len` bytes, respectively, and they are trivially 269c3739801SMiguel Ojeda // aligned. In particular: 270c3739801SMiguel Ojeda // - The entire memory range of each slice is contained within a 271c3739801SMiguel Ojeda // single allocated object, since `l_ptr` and `r_ptr` are both 272c3739801SMiguel Ojeda // derived from within the address range of `self`. 273c3739801SMiguel Ojeda // - Both `l_ptr` and `r_ptr` are non-null and trivially aligned. 274c3739801SMiguel Ojeda // `self` is non-null by invariant on `&mut [u8]`, and the 275c3739801SMiguel Ojeda // operations that derive `l_ptr` and `r_ptr` from `self` do not 276c3739801SMiguel Ojeda // nullify either pointer. 277c3739801SMiguel Ojeda // - The data `l_ptr` and `r_ptr` point to `l_len` and `r_len`, 278c3739801SMiguel Ojeda // respectively, consecutive properly initialized values of type `u8`. 279c3739801SMiguel Ojeda // This is true for `self` by invariant on `&mut [u8]`, and remains 280c3739801SMiguel Ojeda // true for these two sub-slices of `self`. 281c3739801SMiguel Ojeda // - The memory referenced by the returned slice cannot be accessed 282c3739801SMiguel Ojeda // through any other pointer (not derived from the return value) for 283c3739801SMiguel Ojeda // the duration of lifetime `'a``, because: 284c3739801SMiguel Ojeda // - `split_at_unchecked` consumes `self` (which is not `Copy`), 285c3739801SMiguel Ojeda // - `split_at_unchecked` does not exfiltrate any references to this 286c3739801SMiguel Ojeda // memory, besides those references returned below, 287c3739801SMiguel Ojeda // - the returned slices are non-overlapping. 288c3739801SMiguel Ojeda // - The individual sizes of the sub-slices of `self` are no larger than 289c3739801SMiguel Ojeda // `isize::MAX`, because their combined sizes are no larger than 290c3739801SMiguel Ojeda // `isize::MAX`, by invariant on `self`. 291c3739801SMiguel Ojeda // 292c3739801SMiguel Ojeda // [1] https://doc.rust-lang.org/std/slice/fn.from_raw_parts_mut.html#safety 293c3739801SMiguel Ojeda #[allow(clippy::multiple_unsafe_ops_per_block)] 294c3739801SMiguel Ojeda unsafe { 295c3739801SMiguel Ojeda (from_raw_parts_mut(l_ptr, l_len), from_raw_parts_mut(r_ptr, r_len)) 296c3739801SMiguel Ojeda } 297c3739801SMiguel Ojeda } 298c3739801SMiguel Ojeda } 299c3739801SMiguel Ojeda 300c3739801SMiguel Ojeda // SAFETY: See inline. 301c3739801SMiguel Ojeda unsafe impl<'a> IntoByteSlice<'a> for &'a mut [u8] { 302c3739801SMiguel Ojeda #[inline(always)] 303c3739801SMiguel Ojeda fn into_byte_slice(self) -> &'a [u8] { 304c3739801SMiguel Ojeda // SAFETY: It would be patently insane to implement `<Deref for &mut 305c3739801SMiguel Ojeda // [u8]>::deref` as anything other than `fn deref(&self) -> &[u8] { 306c3739801SMiguel Ojeda // *self }`. Assuming this holds, then `self` is stable as required by 307c3739801SMiguel Ojeda // `into_byte_slice`. 308c3739801SMiguel Ojeda self 309c3739801SMiguel Ojeda } 310c3739801SMiguel Ojeda } 311c3739801SMiguel Ojeda 312c3739801SMiguel Ojeda // SAFETY: See inline. 313c3739801SMiguel Ojeda unsafe impl<'a> IntoByteSliceMut<'a> for &'a mut [u8] { 314c3739801SMiguel Ojeda #[inline(always)] 315c3739801SMiguel Ojeda fn into_byte_slice_mut(self) -> &'a mut [u8] { 316c3739801SMiguel Ojeda // SAFETY: It would be patently insane to implement `<DerefMut for &mut 317c3739801SMiguel Ojeda // [u8]>::deref` as anything other than `fn deref_mut(&mut self) -> &mut 318c3739801SMiguel Ojeda // [u8] { *self }`. Assuming this holds, then `self` is stable as 319c3739801SMiguel Ojeda // required by `into_byte_slice_mut`. 320c3739801SMiguel Ojeda self 321c3739801SMiguel Ojeda } 322c3739801SMiguel Ojeda } 323c3739801SMiguel Ojeda 324c3739801SMiguel Ojeda // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. 325c3739801SMiguel Ojeda #[allow(clippy::undocumented_unsafe_blocks)] 326c3739801SMiguel Ojeda unsafe impl ByteSlice for cell::Ref<'_, [u8]> {} 327c3739801SMiguel Ojeda 328c3739801SMiguel Ojeda // SAFETY: This delegates to stdlib implementation of `Ref::map_split`, which is 329c3739801SMiguel Ojeda // assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is 330c3739801SMiguel Ojeda // documented to correctly split `self` into two slices at the given `mid` 331c3739801SMiguel Ojeda // point. 332c3739801SMiguel Ojeda unsafe impl SplitByteSlice for cell::Ref<'_, [u8]> { 333c3739801SMiguel Ojeda #[inline] 334c3739801SMiguel Ojeda unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { 335c3739801SMiguel Ojeda cell::Ref::map_split(self, |slice| 336c3739801SMiguel Ojeda // SAFETY: By precondition on caller, `mid` is not greater than 337c3739801SMiguel Ojeda // `slice.len()`. 338c3739801SMiguel Ojeda unsafe { 339c3739801SMiguel Ojeda SplitByteSlice::split_at_unchecked(slice, mid) 340c3739801SMiguel Ojeda }) 341c3739801SMiguel Ojeda } 342c3739801SMiguel Ojeda } 343c3739801SMiguel Ojeda 344c3739801SMiguel Ojeda // FIXME(#429): Add a "SAFETY" comment and remove this `allow`. 345c3739801SMiguel Ojeda #[allow(clippy::undocumented_unsafe_blocks)] 346c3739801SMiguel Ojeda unsafe impl ByteSlice for cell::RefMut<'_, [u8]> {} 347c3739801SMiguel Ojeda 348c3739801SMiguel Ojeda // SAFETY: This delegates to stdlib implementation of `RefMut::map_split`, which 349c3739801SMiguel Ojeda // is assumed to be correct, and `SplitByteSlice::split_at_unchecked`, which is 350c3739801SMiguel Ojeda // documented to correctly split `self` into two slices at the given `mid` 351c3739801SMiguel Ojeda // point. 352c3739801SMiguel Ojeda unsafe impl SplitByteSlice for cell::RefMut<'_, [u8]> { 353c3739801SMiguel Ojeda #[inline] 354c3739801SMiguel Ojeda unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) { 355c3739801SMiguel Ojeda cell::RefMut::map_split(self, |slice| 356c3739801SMiguel Ojeda // SAFETY: By precondition on caller, `mid` is not greater than 357c3739801SMiguel Ojeda // `slice.len()` 358c3739801SMiguel Ojeda unsafe { 359c3739801SMiguel Ojeda SplitByteSlice::split_at_unchecked(slice, mid) 360c3739801SMiguel Ojeda }) 361c3739801SMiguel Ojeda } 362c3739801SMiguel Ojeda } 363c3739801SMiguel Ojeda 364c3739801SMiguel Ojeda #[cfg(kani)] 365c3739801SMiguel Ojeda mod proofs { 366c3739801SMiguel Ojeda use super::*; 367c3739801SMiguel Ojeda 368c3739801SMiguel Ojeda fn any_vec() -> Vec<u8> { 369c3739801SMiguel Ojeda let len = kani::any(); 370c3739801SMiguel Ojeda kani::assume(len <= crate::DstLayout::MAX_SIZE); 371c3739801SMiguel Ojeda vec![0u8; len] 372c3739801SMiguel Ojeda } 373c3739801SMiguel Ojeda 374c3739801SMiguel Ojeda #[kani::proof] 375c3739801SMiguel Ojeda fn prove_split_at_unchecked() { 376c3739801SMiguel Ojeda let v = any_vec(); 377c3739801SMiguel Ojeda let slc = v.as_slice(); 378c3739801SMiguel Ojeda let mid = kani::any(); 379c3739801SMiguel Ojeda kani::assume(mid <= slc.len()); 380c3739801SMiguel Ojeda let (l, r) = unsafe { slc.split_at_unchecked(mid) }; 381c3739801SMiguel Ojeda assert_eq!(l.len() + r.len(), slc.len()); 382c3739801SMiguel Ojeda 383c3739801SMiguel Ojeda let slc: *const _ = slc; 384c3739801SMiguel Ojeda let l: *const _ = l; 385c3739801SMiguel Ojeda let r: *const _ = r; 386c3739801SMiguel Ojeda 387c3739801SMiguel Ojeda assert_eq!(slc.cast::<u8>(), l.cast::<u8>()); 388c3739801SMiguel Ojeda assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>()); 389c3739801SMiguel Ojeda 390c3739801SMiguel Ojeda let mut v = any_vec(); 391c3739801SMiguel Ojeda let slc = v.as_mut_slice(); 392c3739801SMiguel Ojeda let len = slc.len(); 393c3739801SMiguel Ojeda let mid = kani::any(); 394c3739801SMiguel Ojeda kani::assume(mid <= slc.len()); 395c3739801SMiguel Ojeda let (l, r) = unsafe { slc.split_at_unchecked(mid) }; 396c3739801SMiguel Ojeda assert_eq!(l.len() + r.len(), len); 397c3739801SMiguel Ojeda 398c3739801SMiguel Ojeda let l: *mut _ = l; 399c3739801SMiguel Ojeda let r: *mut _ = r; 400c3739801SMiguel Ojeda let slc: *mut _ = slc; 401c3739801SMiguel Ojeda 402c3739801SMiguel Ojeda assert_eq!(slc.cast::<u8>(), l.cast::<u8>()); 403c3739801SMiguel Ojeda assert_eq!(unsafe { slc.cast::<u8>().add(mid) }, r.cast::<u8>()); 404c3739801SMiguel Ojeda } 405c3739801SMiguel Ojeda } 406c3739801SMiguel Ojeda 407c3739801SMiguel Ojeda #[cfg(test)] 408c3739801SMiguel Ojeda mod tests { 409c3739801SMiguel Ojeda use core::cell::RefCell; 410c3739801SMiguel Ojeda 411c3739801SMiguel Ojeda use super::*; 412c3739801SMiguel Ojeda 413c3739801SMiguel Ojeda #[test] 414c3739801SMiguel Ojeda fn test_ref_split_at_unchecked() { 415c3739801SMiguel Ojeda let cell = RefCell::new([1, 2, 3, 4]); 416c3739801SMiguel Ojeda let borrow = cell.borrow(); 417c3739801SMiguel Ojeda let slice_ref: cell::Ref<'_, [u8]> = cell::Ref::map(borrow, |a| &a[..]); 418c3739801SMiguel Ojeda // SAFETY: 2 is within bounds of [1, 2, 3, 4] 419c3739801SMiguel Ojeda let (l, r) = unsafe { slice_ref.split_at_unchecked(2) }; 420c3739801SMiguel Ojeda assert_eq!(*l, [1, 2]); 421c3739801SMiguel Ojeda assert_eq!(*r, [3, 4]); 422c3739801SMiguel Ojeda } 423c3739801SMiguel Ojeda 424c3739801SMiguel Ojeda #[test] 425c3739801SMiguel Ojeda fn test_ref_mut_split_at_unchecked() { 426c3739801SMiguel Ojeda let cell = RefCell::new([1, 2, 3, 4]); 427c3739801SMiguel Ojeda let borrow_mut = cell.borrow_mut(); 428c3739801SMiguel Ojeda let slice_ref_mut: cell::RefMut<'_, [u8]> = cell::RefMut::map(borrow_mut, |a| &mut a[..]); 429c3739801SMiguel Ojeda // SAFETY: 2 is within bounds of [1, 2, 3, 4] 430c3739801SMiguel Ojeda let (l, r) = unsafe { slice_ref_mut.split_at_unchecked(2) }; 431c3739801SMiguel Ojeda assert_eq!(*l, [1, 2]); 432c3739801SMiguel Ojeda assert_eq!(*r, [3, 4]); 433c3739801SMiguel Ojeda } 434c3739801SMiguel Ojeda } 435