use std::ops::{
Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
};
use std::{fmt, mem::MaybeUninit, ptr};
#[repr(transparent)]
pub struct UninitSlice([MaybeUninit<u8>]);
impl UninitSlice {
#[inline]
pub unsafe fn from_raw_parts_mut<'a>(ptr: *mut u8, len: usize) -> &'a mut UninitSlice {
UninitSlice::from_uninit_mut(core::slice::from_raw_parts_mut(ptr.cast(), len))
}
#[inline]
fn from_uninit(slice: &[MaybeUninit<u8>]) -> &UninitSlice {
unsafe { &*(ptr::from_ref(slice) as *const UninitSlice) }
}
#[inline]
fn from_uninit_mut(slice: &mut [MaybeUninit<u8>]) -> &mut UninitSlice {
unsafe { &mut *(ptr::from_mut(slice) as *mut UninitSlice) }
}
#[inline]
pub fn write_byte(&mut self, index: usize, byte: u8) {
assert!(index < self.len());
unsafe { self[index..].as_mut_ptr().write(byte) }
}
#[inline]
pub fn copy_from_slice(&mut self, src: &[u8]) {
use core::ptr;
assert_eq!(self.len(), src.len());
unsafe {
ptr::copy_nonoverlapping(src.as_ptr(), self.as_mut_ptr(), self.len());
}
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut u8 {
self.0.as_mut_ptr().cast()
}
#[inline]
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub unsafe fn as_uninit_slice_mut(&mut self) -> &mut [MaybeUninit<u8>] {
&mut self.0
}
}
impl AsMut<[MaybeUninit<u8>]> for UninitSlice {
fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
&mut self.0
}
}
impl fmt::Debug for UninitSlice {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.debug_struct("UninitSlice[...]").finish()
}
}
macro_rules! impl_index {
($($t:ty),*) => {
$(
impl Index<$t> for UninitSlice {
type Output = UninitSlice;
#[inline]
fn index(&self, index: $t) -> &UninitSlice {
UninitSlice::from_uninit(&self.0[index])
}
}
impl IndexMut<$t> for UninitSlice {
#[inline]
fn index_mut(&mut self, index: $t) -> &mut UninitSlice {
UninitSlice::from_uninit_mut(&mut self.0[index])
}
}
)*
};
}
impl_index!(
Range<usize>,
RangeFrom<usize>,
RangeFull,
RangeInclusive<usize>,
RangeTo<usize>,
RangeToInclusive<usize>
);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn index_and_uninit_access() {
let mut data = [0u8; 8];
let slice = unsafe { UninitSlice::from_raw_parts_mut(data.as_mut_ptr(), data.len()) };
assert_eq!(slice[..].len(), 8);
assert_eq!(slice[2..].len(), 6);
assert_eq!(slice[..3].len(), 3);
assert_eq!(slice[..=3].len(), 4);
assert_eq!(slice[1..3].len(), 2);
assert_eq!(slice[1..=3].len(), 3);
unsafe { slice.as_uninit_slice_mut()[0].write(b'a') };
AsMut::<[MaybeUninit<u8>]>::as_mut(slice)[1].write(b'b');
assert_eq!(&data[..2], b"ab");
}
}