use std::{any::TypeId, borrow::Cow, mem::transmute, ops::{Deref, DerefMut}};
use crate::{
archetype::{Archetype, ArchetypeDependResult, Flags},
system::SystemMeta,
world::World,
};
use pi_proc_macros::all_tuples;
pub trait SystemParam: Sized + Send + Sync {
type State: Send + Sync + 'static;
type Item<'world>: SystemParam<State = Self::State>;
fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State;
#[inline]
#[allow(unused_variables)]
fn archetype_depend(
world: &World,
system_meta: &SystemMeta,
state: &Self::State,
archetype: &Archetype,
result: &mut ArchetypeDependResult,
) {
}
#[inline]
#[allow(unused_variables)]
fn res_depend(
world: &World,
system_meta: &SystemMeta,
state: &Self::State,
res_tid: &TypeId,
res_name: &Cow<'static, str>,
single: bool,
result: &mut Flags,
) {
}
#[inline]
#[allow(unused_variables)]
fn align(world: &World, system_meta: &SystemMeta, state: &mut Self::State) {}
fn get_param<'world>(
world: &'world World,
system_meta: &'world SystemMeta,
state: &'world mut Self::State,
) -> Self::Item<'world>;
fn get_self<'world>(
world: &'world World,
system_meta: &'world SystemMeta,
state: &'world mut Self::State,
) -> Self;
}
pub struct Local<'a, T>(&'a mut T);
impl<'a, T: Sized> Deref for Local<'a, T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, T: Sized> DerefMut for Local<'a, T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}
impl<T: Send + Sync + Default + 'static> SystemParam for Local<'_, T> {
type State = T;
type Item<'world> = Local<'world, T>;
fn init_state(_world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {
T::default()
}
fn get_param<'world>(
_world: &'world World,
_system_meta: &'world SystemMeta,
state: &'world mut Self::State,
) -> Self::Item<'world> {
Local(state)
}
#[inline]
fn get_self<'world>(
world: &'world World,
system_meta: &'world SystemMeta,
state: &'world mut Self::State,
) -> Self {
unsafe { transmute(Self::get_param(world, system_meta, state)) }
}
}
impl SystemParam for &World {
type State = ();
type Item<'world> = &'world World;
fn init_state(_world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {
()
}
fn get_param<'world>(
world: &'world World,
_system_meta: &'world SystemMeta,
_state: &'world mut Self::State,
) -> Self::Item<'world> {
world
}
#[inline]
fn get_self<'world>(
world: &'world World,
system_meta: &'world SystemMeta,
state: &'world mut Self::State,
) -> Self {
unsafe { transmute(Self::get_param(world, system_meta, state)) }
}
}
macro_rules! impl_system_param_tuple {
($($param: ident),*) => {
#[allow(clippy::undocumented_unsafe_blocks)] #[allow(non_snake_case)]
impl<$($param: SystemParam),*> SystemParam for ($($param,)*) {
type State = ($($param::State,)*);
type Item<'w> = ($($param::Item::<'w>,)*);
#[inline]
fn init_state(_world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {
(($($param::init_state(_world, _system_meta),)*))
}
#[inline]
fn archetype_depend(_world: &World, _system_meta: &SystemMeta, state: &Self::State, _archetype: &Archetype, _result: &mut ArchetypeDependResult) {
let ($($param,)*) = state;
$($param::archetype_depend(_world, _system_meta, $param, _archetype, _result);)*
}
#[inline]
fn res_depend(_world: &World, _system_meta: &SystemMeta, state: &Self::State, _res_tid: &TypeId, _res_name: &Cow<'static, str>, _single: bool, _result: &mut Flags) {
let ($($param,)*) = state;
$($param::res_depend(_world, _system_meta, $param, _res_tid, _res_name, _single, _result);)*
}
#[inline]
fn align(_world: &World, _system_meta: &SystemMeta, state: &mut Self::State) {
let ($($param,)*) = state;
$($param::align(_world, _system_meta, $param);)*
}
#[inline]
#[allow(clippy::unused_unit)]
fn get_param<'world>(
_world: &'world World,
_system_meta: &'world SystemMeta,
state: &'world mut Self::State,
) -> Self::Item<'world> {
let ($($param,)*) = state;
($($param::get_param(_world, _system_meta, $param),)*)
}
#[inline]
fn get_self<'world>(
_world: &'world World,
_system_meta: &'world SystemMeta,
state: &'world mut Self::State,
) -> Self {
let ($($param,)*) = state;
($($param::get_self(_world, _system_meta, $param),)*)
}
}
};
}
all_tuples!(impl_system_param_tuple, 0, 16, P);