soapy 0.2.9

Structure-of-arrays derive macro
Documentation
use crate::{Slice, SoaRaw, Soapy};
use std::{fmt::Debug, iter::FusedIterator, marker::PhantomData};

pub trait IterRawAdapter<T>
where
    T: Soapy,
{
    type Item;
    fn item_from_raw(raw: T::Raw) -> Self::Item;
}

pub struct IterRaw<T, A>
where
    T: Soapy,
    A: IterRawAdapter<T>,
{
    pub(crate) slice: Slice<T, ()>,
    pub(crate) len: usize,
    pub(crate) adapter: PhantomData<A>,
}

impl<T, A> IterRaw<T, A>
where
    T: Soapy,
    A: IterRawAdapter<T>,
{
    pub(crate) unsafe fn as_slice<'a>(&self) -> &'a Slice<T> {
        unsafe { self.slice.as_unsized(self.len) }
    }

    pub(crate) unsafe fn as_mut_slice(&mut self) -> &mut Slice<T> {
        unsafe { self.slice.as_unsized_mut(self.len) }
    }
}

impl<T, A> Clone for IterRaw<T, A>
where
    T: Soapy,
    A: IterRawAdapter<T>,
{
    fn clone(&self) -> Self {
        *self
    }
}

impl<T, A> Copy for IterRaw<T, A>
where
    T: Soapy,
    A: IterRawAdapter<T>,
{
}

impl<T, A> Debug for IterRaw<T, A>
where
    T: Soapy,
    A: IterRawAdapter<T>,
    for<'a> T::Ref<'a>: Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        unsafe { self.slice.as_unsized(self.len).fmt(f) }
    }
}

impl<T, A> Iterator for IterRaw<T, A>
where
    T: Soapy,
    A: IterRawAdapter<T>,
{
    type Item = A::Item;

    fn next(&mut self) -> Option<Self::Item> {
        if self.len == 0 {
            None
        } else {
            self.len -= 1;
            let out = Some(A::item_from_raw(self.slice.raw()));
            self.slice.raw = unsafe { self.slice.raw().offset(1) };
            out
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len, Some(self.len))
    }

    fn count(self) -> usize
    where
        Self: Sized,
    {
        self.len
    }

    fn nth(&mut self, n: usize) -> Option<Self::Item> {
        if n >= self.len {
            self.len = 0;
            None
        } else {
            let out = A::item_from_raw(self.slice.raw());
            self.len -= n + 1;
            self.slice.raw = unsafe { self.slice.raw().offset(n + 1) };
            Some(out)
        }
    }

    fn last(self) -> Option<Self::Item>
    where
        Self: Sized,
    {
        if self.len == 0 {
            None
        } else {
            Some(A::item_from_raw(unsafe {
                self.slice.raw().offset(self.len - 1)
            }))
        }
    }

    fn fold<B, F>(self, init: B, mut f: F) -> B
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> B,
    {
        let Self {
            slice,
            len,
            adapter: _,
        } = self;
        if len == 0 {
            return init;
        }
        let mut acc = init;
        let mut i = 0;
        loop {
            acc = f(acc, A::item_from_raw(unsafe { slice.raw().offset(i) }));
            i += 1;
            if i == len {
                break;
            }
        }
        acc
    }
}

impl<T, A> DoubleEndedIterator for IterRaw<T, A>
where
    T: Soapy,
    A: IterRawAdapter<T>,
{
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.len == 0 {
            None
        } else {
            self.len -= 1;
            Some(unsafe {
                A::item_from_raw(self.slice.as_unsized(self.len).raw().offset(self.len))
            })
        }
    }

    fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
        if n >= self.len {
            self.len = 0;
            None
        } else {
            self.len -= n + 1;
            Some(A::item_from_raw(unsafe {
                self.slice.as_unsized(self.len).raw().offset(self.len)
            }))
        }
    }
}

impl<T, A> FusedIterator for IterRaw<T, A>
where
    T: Soapy,
    A: IterRawAdapter<T>,
{
}

impl<T, A> ExactSizeIterator for IterRaw<T, A>
where
    T: Soapy,
    A: IterRawAdapter<T>,
{
}

macro_rules! iter_with_raw {
    ($t:ty $(,$lifetime:tt)?) => {
        impl<$($lifetime,)? T> Iterator for $t
        where
            T: $($lifetime +)? Soapy,
        {
            type Item = <$t as IterRawAdapter<T>>::Item;

            fn next(&mut self) -> Option<Self::Item> {
                self.iter_raw.next()
            }

            fn size_hint(&self) -> (usize, Option<usize>) {
                self.iter_raw.size_hint()
            }

            fn count(self) -> usize
            where
                Self: Sized,
            {
                self.iter_raw.count()
            }

            fn nth(&mut self, n: usize) -> Option<Self::Item> {
                self.iter_raw.nth(n)
            }

            fn last(self) -> Option<Self::Item>
            where
                Self: Sized,
            {
                self.iter_raw.last()
            }

            fn fold<B, F>(self, init: B, f: F) -> B
            where
                Self: Sized,
                F: FnMut(B, Self::Item) -> B,
            {
                self.iter_raw.fold(init, f)
            }
        }

        impl<$($lifetime,)? T> DoubleEndedIterator for $t
        where
            T: $($lifetime +)? Soapy,
        {
            fn next_back(&mut self) -> Option<Self::Item> {
                self.iter_raw.next_back()
            }
        }

        impl<$($lifetime,)? T> FusedIterator for $t where T: $($lifetime +)? Soapy {}
        impl<$($lifetime,)? T> ExactSizeIterator for $t where T: $($lifetime +)? Soapy {}

        impl<$($lifetime,)? T> AsRef<Slice<T>> for $t where T: $($lifetime +)? Soapy {
            fn as_ref(&self) -> &Slice<T> {
                unsafe { self.iter_raw.as_slice() }
           }
        }
    };
}

pub(crate) use iter_with_raw;