#![no_std]
use core::ops::Deref;
use core::ops::DerefMut;
use core::ops::Index;
use core::ops::IndexMut;
use core::ptr;
#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Debug)]
pub struct UncookedSlice<T> {
inner: *mut [T],
}
impl<T> UncookedSlice<T> {
pub const unsafe fn new(ptr: *mut [T]) -> Self {
UncookedSlice { inner: ptr }
}
pub const fn inner(self) -> *mut [T] {
self.inner
}
}
impl<T> Index<usize> for UncookedSlice<T> {
type Output = T;
fn index(&self, index: usize) -> &T {
unsafe { &*self.inner.cast::<T>().add(index) }
}
}
impl<T> IndexMut<usize> for UncookedSlice<T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
unsafe { &mut *self.inner.cast::<T>().add(index) }
}
}
impl<T> Deref for UncookedSlice<T> {
type Target = *mut [T];
fn deref(&self) -> &*mut [T] {
&self.inner
}
}
impl<T> DerefMut for UncookedSlice<T> {
fn deref_mut(&mut self) -> &mut *mut [T] {
&mut self.inner
}
}
impl<T: Copy> Iterator for UncookedSlice<T> {
type Item = T;
fn next(&mut self) -> Option<T> {
let old_len = match self.inner.len() {
0 => return None,
len => len,
};
let old_ptr = self.inner.cast::<T>();
let new_len = old_len - 1;
let new_ptr = unsafe { old_ptr.add(1) };
let new_slice = ptr::slice_from_raw_parts_mut(new_ptr, new_len);
self.inner = new_slice;
Some(unsafe { *old_ptr })
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_iterable() {
let mut data = [0, 1, 2, 3, 4, 5];
let ptr = &raw mut data[..];
let uncooked = unsafe { UncookedSlice::new(ptr) };
let mut buf = [0i32; 6];
for (i, item) in uncooked.enumerate() {
buf[i] = item;
}
let uncooked2 = unsafe { UncookedSlice::new(ptr) };
assert_eq!(uncooked, uncooked2);
assert_eq!(buf, data);
}
#[test]
fn test_deref_raw_slice() {
let mut data = [0, 1, 2, 3, 4, 5];
let ptr = &raw mut data[..];
let uncooked = unsafe { UncookedSlice::new(ptr) };
let len = uncooked.len();
assert_eq!(uncooked.inner.len(), len);
}
#[test]
#[allow(unconditional_panic)]
#[allow(clippy::out_of_bounds_indexing)]
fn test_index() {
extern crate std;
let mut data = [0, 1, 2, 3, 4, 5];
let ptr = &raw mut data[..];
let uncooked = unsafe { UncookedSlice::new(ptr) };
assert_eq!(data[0], 0);
assert_eq!(data[1], 1);
assert_eq!(data[2], 2);
assert_eq!(data[3], 3);
assert_eq!(data[4], 4);
assert_eq!(data[5], 5);
let catch_unwind = std::panic::catch_unwind(|| data[6]);
assert!(catch_unwind.is_err())
}
#[test]
#[allow(unconditional_panic)]
#[allow(clippy::out_of_bounds_indexing)]
fn test_index_write() {
extern crate std;
let mut data = [0, 1, 2, 3, 4, 5];
let ptr = &raw mut data[..];
let mut uncooked = unsafe { UncookedSlice::new(ptr) };
uncooked[0] = 1;
assert_eq!(uncooked[0], 1);
uncooked[0] = uncooked[5];
assert_eq!(uncooked[0], 5);
let catch_unwind = std::panic::catch_unwind(|| data[6]);
assert!(catch_unwind.is_err())
}
}