entwine 0.1.0

Generic slice-like interface for operating on multiple slices at the same time
Documentation
use core::marker::PhantomData;
use core::mem;
use core::ops::RangeBounds;
use core::ptr;

use crate::raw::{ElementCtor, EntwineCore, Ptr, PtrMut, Ref, RefMut, Value};
use crate::{RefMutT, RefT};

unsafe impl<T> EntwineCore for [T] {
    type ElementCtor = SliceElementCtor<T>;

    type RangeMut<'a>
    where
        Self: 'a,
    = &'a mut [T];

    #[inline]
    fn len(&self) -> usize {
        <[T]>::len(self)
    }

    #[inline]
    fn range_mut<R: RangeBounds<usize>>(&mut self, range: R) -> Option<&mut Self> {
        let start = range.start_bound().cloned();
        let end = range.end_bound().cloned();
        self.get_mut((start, end))
    }

    #[inline]
    fn split_at_mut(&mut self, mid: usize) -> (&mut Self, &mut Self) {
        <[T]>::split_at_mut(self, mid)
    }

    #[inline]
    fn reverse(&mut self) {
        <[T]>::reverse(self)
    }

    #[inline]
    unsafe fn get_unchecked(&self, idx: usize) -> RefT<'_, Self> {
        <[T]>::get_unchecked(self, idx)
    }

    #[inline]
    unsafe fn get_unchecked_mut(&mut self, idx: usize) -> RefMutT<'_, Self> {
        <[T]>::get_unchecked_mut(self, idx)
    }
}

pub struct SliceElementCtor<T> {
    _marker: PhantomData<T>,
}

impl<T> ElementCtor for SliceElementCtor<T> {
    type Value = T;

    type Ref<'a>
    where
        Self: 'a,
    = &'a T;

    type RefMut<'a>
    where
        Self: 'a,
    = &'a mut T;

    type Ptr = *const T;
    type PtrMut = *mut T;
}

unsafe impl<T> Value<SliceElementCtor<T>> for T {
    #[inline]
    fn is_zero_sized() -> bool {
        mem::size_of::<T>() == 0
    }

    #[inline]
    fn as_ref(&self) -> &'_ T {
        self
    }

    #[inline]
    fn as_mut(&mut self) -> &'_ mut T {
        self
    }
}

unsafe impl<'a, T> Ref<'a, SliceElementCtor<T>> for &'a T {
    #[inline]
    fn to_ptr(&self) -> *const T {
        *self
    }

    #[inline]
    fn reborrow<'r>(self) -> &'r T
    where
        'a: 'r,
    {
        self
    }
}

unsafe impl<'a, T> RefMut<'a, SliceElementCtor<T>> for &'a mut T {
    #[inline]
    fn to_ref(&self) -> &'_ T {
        self
    }

    #[inline]
    fn to_mut_ptr(&mut self) -> *mut T {
        *self
    }

    #[inline]
    fn reborrow_mut<'r>(self) -> &'r mut T
    where
        'a: 'r,
    {
        self
    }
}

unsafe impl<T> Ptr<SliceElementCtor<T>> for *const T {
    #[inline]
    unsafe fn deref<'r>(&self) -> &'r T {
        &**self
    }

    #[inline]
    unsafe fn read(src: &Self) -> T {
        ptr::read(*src)
    }

    #[inline]
    unsafe fn add(&self, count: usize) -> Self {
        <*const T>::add(*self, count)
    }

    #[inline]
    unsafe fn offset(&self, count: isize) -> Self {
        <*const T>::offset(*self, count)
    }

    #[inline]
    fn width(l: &Self, r: &Self) -> usize {
        assert!(mem::size_of::<T>() > 0);
        (*r as usize - *l as usize) / mem::size_of::<T>()
    }

    #[inline]
    fn null() -> Self {
        ptr::null()
    }
}

unsafe impl<T> PtrMut<SliceElementCtor<T>> for *mut T {
    #[inline]
    unsafe fn deref_mut<'r>(&self) -> &'r mut T {
        &mut **self
    }

    #[inline]
    unsafe fn to_const(&self) -> *const T {
        *self
    }

    #[inline]
    unsafe fn write(dst: &Self, src: T) {
        ptr::write(*dst, src)
    }

    #[inline]
    unsafe fn add(&self, count: usize) -> Self {
        <*mut T>::add(*self, count)
    }

    #[inline]
    unsafe fn offset(&self, count: isize) -> Self {
        <*mut T>::offset(*self, count)
    }

    #[inline]
    fn width(l: &Self, r: &Self) -> usize {
        assert!(mem::size_of::<T>() > 0);
        (*r as usize - *l as usize) / mem::size_of::<T>()
    }

    #[inline]
    unsafe fn copy_nonoverlapping(src: &*const T, dst: &Self, n: usize) {
        ptr::copy_nonoverlapping(*src, *dst, n)
    }

    #[inline]
    fn null_mut() -> Self {
        ptr::null_mut()
    }

    #[inline]
    unsafe fn swap(a: &Self, b: &Self) {
        ptr::swap(*a, *b)
    }
}

#[cfg(test)]
mod tests {
    use crate::Entwine;

    use rand::Rng;

    #[test]
    fn random_sort() {
        #[cfg(not(feature = "extended_random_tests"))]
        const R: usize = 1;
        #[cfg(feature = "extended_random_tests")]
        const R: usize = 128;
        #[cfg(not(feature = "extended_random_tests"))]
        const N: usize = 1024;
        #[cfg(feature = "extended_random_tests")]
        const N: usize = 4096;

        let mut rng = rand::thread_rng();

        let mut u16s = [0u16; N];

        for _ in 0..R {
            rng.fill(u16s.as_mut());

            (&mut u16s[..],).sort_unstable_by(|a, b| a.cmp(b));

            let mut last = u16s[0];
            for &i in &u16s[1..] {
                if i < last {
                    panic!("slice is not sorted: {:?}", &u16s);
                }
                last = i;
            }
        }
    }
}