stack 0.4.0

DSTs and arrays on the stack!
Documentation
use std::fmt;
use std::ops::{Deref, DerefMut};
use std::ptr::copy_nonoverlapping;
use std::mem::{MaybeUninit, forget, size_of, align_of};
use std::slice::{from_raw_parts, from_raw_parts_mut};
use std::marker;
use crate::{ArrayVec, Vector};

#[macro_export]
macro_rules! small_dst {
    ($x:expr) => {
        {
            let v = $x;
            let dst = unsafe { $crate::SmallDST::new_ref(&v as &_, &v) };
            ::std::mem::forget(v);
            dst
        }
    };
}

pub struct SmallDST<T: ?Sized, A: Vector<Item=usize> = ArrayVec<[usize; 9]>> {
    data: A,
    _phantom: marker::PhantomData<T>,
}

impl<T: ?Sized + Clone, A: Vector<Item=usize>> Clone for SmallDST<T, A> {
    fn clone(&self) -> Self {
        small_dst!((&**self).clone())
    }
}

impl<T: ?Sized, A: Vector<Item=usize>> SmallDST<T, A> {
    fn ptr_len() -> usize {
        assert_eq!(size_of::<*const T>() % size_of::<usize>(), 0);
        size_of::<*const T>() / size_of::<usize>()
    }

    fn data_len() -> usize {
        Self::ptr_len() - 1
    }

    fn ref_data<'a>(v: &'a *const T) -> &'a [usize] {
        unsafe { from_raw_parts(v as *const *const T as *const usize, Self::ptr_len()) }
    }

    fn mut_data_const<'a>(v: &'a mut MaybeUninit<*const T>) -> &'a mut [MaybeUninit<usize>] {
        unsafe { from_raw_parts_mut(v.as_mut_ptr() as *mut usize as *mut MaybeUninit<usize>, Self::ptr_len()) }
    }

    fn mut_data_mut<'a>(v: &'a mut MaybeUninit<*mut T>) -> &'a mut [MaybeUninit<usize>] {
        unsafe { from_raw_parts_mut(v.as_mut_ptr() as *mut usize as *mut MaybeUninit<usize>, Self::ptr_len()) }
    }

    #[cfg(feature = "unstable")]
    pub fn new<U: marker::Unsize<T>>(v: U) -> Self {
        let ret = unsafe { Self::new_ref(&v, &v) };
        forget(v);
        ret
    }

    #[inline]
    pub unsafe fn new_ref<U>(v: &T, u: &U) -> Self {
        let t = v as *const T;
        let data = Self::ref_data(&t);
        assert_eq!(data[0], u as *const U as usize);

        Self::from_ref(u, &data[1..])
    }

    #[inline]
    pub unsafe fn data(&self) -> &A {
        &self.data
    }

    unsafe fn from_value<U>(v: U, data: &[usize]) -> Self {
        let ret = Self::from_ref(&v, data);
        forget(v);
        ret
    }

    unsafe fn from_ref<U>(v: &U, data: &[usize]) -> Self {
        assert!(align_of::<U>() <= align_of::<A::Item>()); // TODO: support arbitrary alignments
        assert_eq!(data.len(), Self::data_len());

        let size = (size_of::<U>() + size_of::<usize>() - 1) / size_of::<usize>();

        let mut a = A::with_capacity(Self::data_len() + size);
        a.set_len(Self::data_len() + size);
        copy_nonoverlapping(data.as_ptr(), a.as_mut_ptr(), Self::data_len());
        copy_nonoverlapping(v as *const U as *const u8, a.as_mut_ptr().offset(Self::data_len() as isize) as *mut u8, size_of::<U>());

        SmallDST {
            data: a,
            _phantom: marker::PhantomData,
        }
    }
}

impl<T: ?Sized, A: Vector<Item=usize>> Drop for SmallDST<T, A> {
    #[inline]
    fn drop(&mut self) {
        use std::ptr;

        unsafe {
            if self.data.len() > 0 {
                self.data.set_len(0);
                ptr::drop_in_place(&mut **self);
            }
        }
    }
}

impl<T: Sized, A: Vector<Item=usize>> From<T> for SmallDST<T, A> {
    #[inline]
    fn from(t: T) -> Self {
        unsafe { Self::from_value(t, &[]) }
    }
}

impl<T: ?Sized, A: Vector<Item=usize>> Deref for SmallDST<T, A> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &Self::Target {
        unsafe {
            let mut v = MaybeUninit::uninit();
            {
                let v = Self::mut_data_const(&mut v);
                v[0] = MaybeUninit::new(self.data.as_ptr().offset(Self::data_len() as isize) as usize);
                copy_nonoverlapping(self.data.as_ptr(), v[1..].as_mut_ptr() as *mut usize, Self::data_len());
            }
            &*v.assume_init()
        }
    }
}

impl<T: ?Sized, A: Vector<Item=usize>> DerefMut for SmallDST<T, A> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe {
            let mut v = MaybeUninit::uninit();
            {
                let v = Self::mut_data_mut(&mut v);
                v[0] = MaybeUninit::new(self.data.as_ptr().offset(Self::data_len() as isize) as usize);
                copy_nonoverlapping(self.data.as_ptr(), v[1..].as_mut_ptr() as *mut usize, Self::data_len());
            }
            &mut *v.assume_init()
        }
    }
}

impl<T: ?Sized + fmt::Debug, A: Vector<Item=usize>> fmt::Debug for SmallDST<T, A> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&**self, fmt)
    }
}