pulz-schedule 0.1.0-alpha2

For scheduling systems and managing their resources
Documentation
use std::marker::PhantomData;

use pulz_functional_utils::{
    func::{FuncMut, FuncOnce},
    tuple::Tuple,
};

use super::{
    SendSystem, System, SystemInit,
    data::{SystemData, SystemDataSend},
};
use crate::{
    resource::{Resources, ResourcesSend},
    system::IntoSystem,
};
pub struct FuncSystem<F, D>
where
    D: SystemData + Tuple,
{
    func: F,
    args_data: Option<D::Data>,
}

impl<F, D> FuncSystem<F, D>
where
    F: FuncMut<D, Output = ()>,
    D: SystemData + Tuple,
{
    pub const fn new(func: F) -> Self {
        Self {
            func,
            args_data: None,
        }
    }
}

#[diagnostic::do_not_recommend]
impl<F, D> SystemInit for FuncSystem<F, D>
where
    F: 'static,
    D: SystemData + Tuple + 'static,
{
    #[inline]
    fn init(&mut self, resources: &mut Resources) {
        self.args_data = Some(D::init(resources));
    }

    #[inline]
    fn system_type_name(&self) -> &'static str {
        std::any::type_name::<F>()
    }

    #[inline]
    fn system_type_id(&self) -> std::any::TypeId {
        std::any::TypeId::of::<F>()
    }
}

#[diagnostic::do_not_recommend]
impl<F, D> System for FuncSystem<F, D>
where
    F: FuncMut<D, Output = ()> + 'static,
    for<'a> &'a mut F: FuncOnce<D::Arg<'a>, Output = ()> + 'a,
    D: SystemData + Tuple + 'static,
    for<'a> D::Arg<'a>: Tuple,
{
    fn run<'a>(&'a mut self, resources: &'a Resources) {
        let data = self.args_data.as_mut().expect("not initialized");
        let args = D::get(resources, data);
        <&mut F>::call_once(&mut self.func, args);
    }

    #[inline]
    fn update_access(&self, res: &Resources, access: &mut crate::resource::ResourceAccess) {
        D::update_access(
            res,
            access,
            self.args_data.as_ref().expect("not initialized"),
        );
    }
}

#[diagnostic::do_not_recommend]
impl<F, D> SendSystem for FuncSystem<F, D>
where
    F: FuncMut<D, Output = ()> + Send + Sync + 'static,
    for<'a> &'a mut F: FuncOnce<D::Arg<'a>, Output = ()> + 'a,
    D: SystemDataSend + Tuple + 'static,
    for<'a> D::Arg<'a>: Tuple,
{
    fn run_send<'a>(&'a mut self, resources: &'a ResourcesSend) {
        let data = self.args_data.as_mut().expect("not initialized");
        let args = D::get_send(resources, data);
        <&mut F>::call_once(&mut self.func, args);
    }
}

#[doc(hidden)]
pub struct NonExclusiveSystemMarker<D>(PhantomData<fn(D)>);

#[diagnostic::do_not_recommend]
impl<F, D> IntoSystem<NonExclusiveSystemMarker<D>> for F
where
    D: SystemData + Tuple,
    F: FuncMut<D, Output = ()>,
    FuncSystem<F, D>: System,
{
    type System = FuncSystem<F, D>;

    #[inline]
    fn into_system(self) -> Self::System {
        FuncSystem::<F, D>::new(self)
    }
}