use std::{any::TypeId, borrow::Cow};
use crate::{
archetype::{Archetype, ArchetypeDependResult, Flags},
system::{IntoSystem, RunSystem, System, SystemMeta},
system_params::SystemParam,
world::*,
};
use pi_proc_macros::all_tuples;
pub type SystemParamItem<'w, P> = <P as SystemParam>::Item<'w>;
pub trait SystemParamFunction<Marker>: Send + Sync + 'static {
type Param: SystemParam;
fn run(&mut self, _param_value: SystemParamItem<Self::Param>) {}
}
pub struct FunctionSystem<Marker: 'static, F>
where
F: SystemParamFunction<Marker>,
{
func: F,
param: ParamSystem<F::Param>,
}
impl<Marker: 'static, F> IntoSystem<Marker> for F
where
F: SystemParamFunction<Marker>,
{
type System = FunctionSystem<Marker, F>;
fn into_system(self) -> Self::System {
FunctionSystem {
func: self,
param: ParamSystem::new(SystemMeta::new::<F>()),
}
}
}
impl<Marker, F> System for FunctionSystem<Marker, F>
where
F: SystemParamFunction<Marker>,
{
#[inline]
fn name(&self) -> &Cow<'static, str> {
self.param.name()
}
#[inline]
fn type_id(&self) -> TypeId {
self.param.type_id()
}
#[inline]
fn initialize(&mut self, world: &mut World) {
self.param.initialize(world)
}
fn archetype_depend(
&self,
world: &World,
archetype: &Archetype,
result: &mut ArchetypeDependResult,
) {
self.param.archetype_depend(world, archetype, result)
}
fn res_depend(
&self,
world: &World,
res_tid: &TypeId,
res_name: &Cow<'static, str>,
single: bool,
result: &mut Flags,
) {
self.param
.res_depend(world, res_tid, res_name, single, result)
}
#[inline]
fn align(&mut self, world: &World) {
self.param.align(world)
}
}
impl<Marker, F> RunSystem for FunctionSystem<Marker, F>
where
F: SystemParamFunction<Marker>,
{
#[inline]
fn run(&mut self, world: &World) {
let params = self.param.get_param(world);
self.func.run(params);
}
}
pub struct ParamSystem<P: SystemParam> {
pub(crate) param_state: Option<P::State>,
pub(crate) system_meta: SystemMeta,
}
impl<P: SystemParam> ParamSystem<P> {
pub fn new(system_meta: SystemMeta) -> Self {
Self {
param_state: None,
system_meta,
}
}
#[inline]
pub(crate) fn name(&self) -> &Cow<'static, str> {
&self.system_meta.name
}
#[inline]
pub(crate) fn type_id(&self) -> TypeId {
self.system_meta.type_id
}
#[inline]
pub(crate) fn initialize(&mut self, world: &mut World) {
self.param_state = Some(P::init_state(world, &mut self.system_meta));
}
pub(crate) fn archetype_depend(
&self,
world: &World,
archetype: &Archetype,
result: &mut ArchetypeDependResult,
) {
P::archetype_depend(
world,
&self.system_meta,
self.param_state.as_ref().unwrap(),
archetype,
result,
)
}
pub(crate) fn res_depend(
&self,
world: &World,
res_tid: &TypeId,
res_name: &Cow<'static, str>,
single: bool,
result: &mut Flags,
) {
P::res_depend(
world,
&self.system_meta,
self.param_state.as_ref().unwrap(),
res_tid,
res_name,
single,
result,
)
}
#[inline]
pub(crate) fn align(&mut self, world: &World) {
let param_state = self.param_state.as_mut().unwrap();
P::align(world, &mut self.system_meta, param_state);
}
#[inline]
pub fn get_param<'w>(&'w mut self, world: &'w World) -> SystemParamItem<'w, P> {
let param_state = self.param_state.as_mut().unwrap();
P::get_param(world, &mut self.system_meta, param_state)
}
}
macro_rules! impl_system_function {
($($param: ident),*) => {
#[allow(non_snake_case)]
impl<Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<fn($($param,)*)> for Func
where
for <'a> &'a mut Func:
FnMut($($param),*) +
FnMut($(SystemParamItem<$param>),*),
{
type Param = ($($param,)*);
#[inline]
fn run(&mut self, param_value: SystemParamItem< ($($param,)*)>) {
#[allow(clippy::too_many_arguments)]
fn call_inner<$($param,)*>(
mut f: impl FnMut($($param,)*),
$($param: $param,)*
) {
f($($param,)*)
}
let ($($param,)*) = param_value;
call_inner(self, $($param),*)
}
}
};
}
all_tuples!(impl_system_function, 0, 16, F);