use std::{any::TypeId, borrow::Cow, future::Future, marker::PhantomData, mem::transmute, pin::Pin};
use crate::{
function_system::ParamSystem,
system::{AsyncRunSystem, IntoAsyncSystem, System, SystemMeta, TypeInfo},
system_params::SystemParam,
world::*,
};
use pi_proc_macros::all_tuples;
pub trait AsyncSystemParamFunction<Marker, Out>: Clone + Send + Sync + 'static {
type Param: SystemParam;
fn run(self, _param_value: Self::Param) -> Pin<Box<dyn Future<Output = Out> + Send + 'static>>;
}
pub struct AsyncFunctionSystem<Marker, Out, F>
where
F: AsyncSystemParamFunction<Marker, Out>,
{
pub func: F,
pub param: ParamSystem<F::Param>,
pub marker: PhantomData<Out>,
}
impl<Marker: 'static, F, Out: 'static + Send + Sync> IntoAsyncSystem<Marker, Out> for F
where
F: AsyncSystemParamFunction<Marker, Out>,
{
type System = AsyncFunctionSystem<Marker, Out, F>;
fn into_async_system(self) -> Self::System {
AsyncFunctionSystem {
func: self,
param: ParamSystem::new(SystemMeta::new(TypeInfo::of::<F>())),
marker: PhantomData,
}
}
}
impl<Marker: 'static, F, Out: 'static + Send + Sync> System for AsyncFunctionSystem<Marker, Out, F>
where
F: AsyncSystemParamFunction<Marker, Out>,
{
type Out = Out;
#[inline]
fn name(&self) -> &Cow<'static, str> {
self.param.name()
}
#[inline]
fn id(&self) -> TypeId {
self.param.type_id()
}
#[inline]
fn initialize(&mut self, world: &mut World) {
self.param.initialize(world)
}
#[inline]
fn align(&mut self, world: &World) {
self.param.align(world)
}
}
impl<Marker: 'static, Out: 'static + Send + Sync, F> AsyncRunSystem for AsyncFunctionSystem<Marker, Out, F>
where
F: AsyncSystemParamFunction<Marker, Out>,
{
#[inline]
fn run(&mut self, world: &'static World) -> Pin<Box<dyn Future<Output = Out> + Send + 'static>> {
self.param.align(world);
let tick = world.increment_tick();
let param_state = self.param.param_state.as_mut().unwrap();
let params = F::Param::get_self(world, &mut self.param.system_meta, param_state, tick);
self.func.clone().run(params)
}
}
macro_rules! impl_async_system_function {
($($param: ident),*) => {
#[allow(non_snake_case)]
impl<Func: Clone + Send + Sync + 'static, Out, R, $($param: SystemParam),*> AsyncSystemParamFunction<fn($($param,)*)->R, Out> for Func
where Func:
FnMut($($param),*) -> R,
R: Future<Output=Out>,
{
type Param = ($($param,)*);
#[inline]
fn run(mut self, param_value: ($($param,)*)) -> Pin<Box<dyn Future<Output = Out> + Send + 'static>> {
let ($($param,)*) = param_value;
let r: Pin<Box<dyn Future<Output = Out>>> = Box::pin(self($($param,)*));
unsafe {transmute(r)}
}
}
};
}
all_tuples!(impl_async_system_function, 0, 16, F);