use core::{
cell,
ops::{Deref, DerefMut},
};
#[allow(unused_imports)]
use crate::util::polyfills::{self, NonNullExt as _, NumExt as _};
#[cfg(doc)]
use crate::Ref;
pub unsafe trait ByteSlice: Deref<Target = [u8]> + Sized {}
pub trait ByteSliceMut: ByteSlice + DerefMut {}
impl<B: ByteSlice + DerefMut> ByteSliceMut for B {}
pub unsafe trait CopyableByteSlice: ByteSlice + Copy + CloneableByteSlice {}
pub unsafe trait CloneableByteSlice: ByteSlice + Clone {}
pub unsafe trait SplitByteSlice: ByteSlice {
#[inline]
fn split_at(self, mid: usize) -> Result<(Self, Self), Self> {
if mid <= self.deref().len() {
unsafe { Ok(self.split_at_unchecked(mid)) }
} else {
Err(self)
}
}
#[must_use]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self);
}
pub trait SplitByteSliceMut: SplitByteSlice + ByteSliceMut {}
impl<B: SplitByteSlice + ByteSliceMut> SplitByteSliceMut for B {}
#[allow(clippy::missing_safety_doc)] pub unsafe trait IntoByteSlice<'a>: ByteSlice {
fn into_byte_slice(self) -> &'a [u8];
}
#[allow(clippy::missing_safety_doc)] pub unsafe trait IntoByteSliceMut<'a>: IntoByteSlice<'a> + ByteSliceMut {
fn into_byte_slice_mut(self) -> &'a mut [u8];
}
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for &[u8] {}
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl CopyableByteSlice for &[u8] {}
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl CloneableByteSlice for &[u8] {}
unsafe impl SplitByteSlice for &[u8] {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
unsafe { (<[u8]>::get_unchecked(self, ..mid), <[u8]>::get_unchecked(self, mid..)) }
}
}
unsafe impl<'a> IntoByteSlice<'a> for &'a [u8] {
#[inline(always)]
fn into_byte_slice(self) -> &'a [u8] {
self
}
}
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for &mut [u8] {}
unsafe impl SplitByteSlice for &mut [u8] {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
use core::slice::from_raw_parts_mut;
let l_ptr = self.as_mut_ptr();
let r_ptr = unsafe { l_ptr.add(mid) };
let l_len = mid;
#[allow(unstable_name_collisions)]
let r_len = unsafe { self.len().unchecked_sub(mid) };
unsafe { (from_raw_parts_mut(l_ptr, l_len), from_raw_parts_mut(r_ptr, r_len)) }
}
}
unsafe impl<'a> IntoByteSlice<'a> for &'a mut [u8] {
#[inline(always)]
fn into_byte_slice(self) -> &'a [u8] {
self
}
}
unsafe impl<'a> IntoByteSliceMut<'a> for &'a mut [u8] {
#[inline(always)]
fn into_byte_slice_mut(self) -> &'a mut [u8] {
self
}
}
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for cell::Ref<'_, [u8]> {}
unsafe impl SplitByteSlice for cell::Ref<'_, [u8]> {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
cell::Ref::map_split(self, |slice|
unsafe {
SplitByteSlice::split_at_unchecked(slice, mid)
})
}
}
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe impl ByteSlice for cell::RefMut<'_, [u8]> {}
unsafe impl SplitByteSlice for cell::RefMut<'_, [u8]> {
#[inline]
unsafe fn split_at_unchecked(self, mid: usize) -> (Self, Self) {
cell::RefMut::map_split(self, |slice|
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 <= isize::MAX as usize);
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>());
}
}