yaks 0.1.0

Minimalistic framework for automatic multithreading of hecs via rayon
Documentation
use std::marker::PhantomData;

use crate::{AtomicBorrow, ResourceCell};

pub struct WrappedResources<'a, Wrapped> {
    phantom_data: PhantomData<&'a ()>,
    pub(crate) tuple: Wrapped,
}

pub trait ResourceTuple {
    type Cells;
    type Borrows;
    const LENGTH: usize;

    fn instantiate_borrows() -> Self::Borrows;
}

pub trait ResourceWrap {
    type Types: ResourceTuple<Cells = Self::Cells, Borrows = Self::Borrows>;
    type Cells;
    type Borrows;

    fn wrap(&mut self, borrows: &mut Self::Borrows) -> WrappedResources<Self::Cells>;
}

impl<'a, R0> ResourceWrap for &'a mut R0
where
    R0: Send + Sync,
{
    type Types = (R0,);
    type Cells = (ResourceCell<R0>,);
    type Borrows = (AtomicBorrow,);

    fn wrap(&mut self, borrows: &mut Self::Borrows) -> WrappedResources<Self::Cells> {
        WrappedResources {
            phantom_data: PhantomData,
            tuple: (ResourceCell::new(self, &mut borrows.0),),
        }
    }
}

impl ResourceTuple for () {
    type Cells = ();
    type Borrows = ();
    const LENGTH: usize = 0;

    fn instantiate_borrows() -> Self::Borrows {}
}

impl ResourceWrap for () {
    type Types = ();
    type Cells = ();
    type Borrows = ();

    fn wrap(&mut self, _: &mut Self::Borrows) -> WrappedResources<Self::Cells> {
        WrappedResources {
            phantom_data: PhantomData,
            tuple: (),
        }
    }
}

impl<R0> ResourceTuple for (R0,)
where
    R0: Send + Sync,
{
    type Cells = (ResourceCell<R0>,);
    type Borrows = (AtomicBorrow,);
    const LENGTH: usize = 1;

    fn instantiate_borrows() -> Self::Borrows {
        (AtomicBorrow::new(),)
    }
}

impl<R0> ResourceWrap for (&'_ mut R0,)
where
    R0: Send + Sync,
{
    type Types = (R0,);
    type Cells = (ResourceCell<R0>,);
    type Borrows = (AtomicBorrow,);

    fn wrap(&mut self, borrows: &mut Self::Borrows) -> WrappedResources<Self::Cells> {
        WrappedResources {
            phantom_data: PhantomData,
            tuple: (ResourceCell::new(self.0, &mut borrows.0),),
        }
    }
}

macro_rules! swap_to_atomic_borrow {
    ($anything:tt) => {
        AtomicBorrow
    };
    (new $anything:tt) => {
        AtomicBorrow::new()
    };
}

macro_rules! impl_resource_tuple {
    ($($letter:ident),*) => {
        impl<$($letter),*> ResourceTuple for ($($letter,)*)
        where
            $($letter: Send + Sync,)*
        {
            type Cells = ($(ResourceCell<$letter>,)*);
            type Borrows = ($(swap_to_atomic_borrow!($letter),)*);
            const LENGTH: usize = count!($($letter)*);

            fn instantiate_borrows() -> Self::Borrows {
                ($(swap_to_atomic_borrow!(new $letter),)*)
            }
        }
    }
}

impl_for_tuples!(impl_resource_tuple);

macro_rules! impl_resource_wrap {
    ($($letter:ident),*) => {
        paste::item! {
            impl<$($letter),*> ResourceWrap for ($(&'_ mut $letter,)*)
            where
                $($letter: Send + Sync,)*
            {
                type Types = ($($letter,)*);
                type Cells = ($(ResourceCell<$letter>,)*);
                type Borrows = ($(swap_to_atomic_borrow!($letter),)*);

                #[allow(non_snake_case)]
                fn wrap(&mut self, borrows: &mut Self::Borrows) -> WrappedResources<Self::Cells> {
                    let ($([<S $letter>],)*) = self;
                    let ($([<B $letter>],)*) = borrows;
                    WrappedResources {
                        phantom_data: PhantomData,
                        tuple: (
                            $( ResourceCell::new([<S $letter>], [<B $letter>]) ,)*
                        )
                    }
                }
            }
        }
    }
}

impl_for_tuples!(impl_resource_wrap);