use std::{
marker::PhantomData, mem::transmute, ops::{Deref, DerefMut}
};
use crate::{
archetype::ComponentInfo, prelude::FromWorld, system::{Relation, SystemMeta}, world::{ComponentIndex, Tick, World}
};
use pi_proc_macros::all_tuples;
pub use pi_world_macros::SystemParam;
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 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,
tick: Tick,
) -> Self::Item<'world>;
fn get_self<'world>(
world: &'world World,
system_meta: &'world SystemMeta,
state: &'world mut Self::State,
tick: Tick,
) -> Self;
}
pub struct Local<'a, T>(&'a mut T, Tick);
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<'a, T: Sized> Local<'a, T> {
pub fn tick(&self) -> Tick {
self.1
}
}
impl<T: Send + Sync + 'static + FromWorld> 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::from_world(world)
}
fn get_param<'world>(
_world: &'world World,
_system_meta: &'world SystemMeta,
state: &'world mut Self::State,
tick: Tick,
) -> Self::Item<'world> {
Local(state, tick)
}
#[inline]
fn get_self<'world>(
world: &'world World,
system_meta: &'world SystemMeta,
state: &'world mut Self::State,
tick: Tick,
) -> Self {
unsafe { transmute(Self::get_param(world, system_meta, state, tick)) }
}
}
pub struct ComponentDebugIndex<T: 'static + Send + Sync>(pub ComponentIndex, PhantomData<T>);
impl<T: 'static + Send + Sync> SystemParam for ComponentDebugIndex<T> {
type State = ComponentIndex;
type Item<'world> = ComponentDebugIndex<T>;
fn init_state(world: &mut World, _meta: &mut SystemMeta) -> Self::State {
let info = ComponentInfo::of::<T>(0);
let rc = world.add_component_info(info);
rc.0
}
fn get_param<'world>(
_world: &'world World,
_system_meta: &'world SystemMeta,
_state: &'world mut Self::State,
_tick: Tick,
) -> Self::Item<'world> {
ComponentDebugIndex(_state.clone(), PhantomData)
}
#[inline]
fn get_self<'world>(
world: &'world World,
system_meta: &'world SystemMeta,
state: &'world mut Self::State,
tick: Tick,
) -> Self {
unsafe { transmute(Self::get_param(world, system_meta, state, tick)) }
}
}
impl SystemParam for &World {
type State = ();
type Item<'world> = &'world World;
fn init_state(_world: &mut World, meta: &mut SystemMeta) -> Self::State {
meta.relate(Relation::ReadAll);
meta.related_ok();
meta.add_res(Relation::ReadAll);
()
}
fn get_param<'world>(
world: &'world World,
_system_meta: &'world SystemMeta,
_state: &'world mut Self::State,
_tick: Tick,
) -> Self::Item<'world> {
world
}
#[inline]
fn get_self<'world>(
world: &'world World,
system_meta: &'world SystemMeta,
state: &'world mut Self::State,
tick: Tick,
) -> Self {
unsafe { transmute(Self::get_param(world, system_meta, state, tick)) }
}
}
impl SystemParam for &mut World {
type State = ();
type Item<'world> = &'world mut World;
fn init_state(_world: &mut World, meta: &mut SystemMeta) -> Self::State {
meta.relate(Relation::WriteAll);
meta.related_ok();
meta.add_res(Relation::WriteAll);
()
}
fn get_param<'world>(
world: &'world World,
_system_meta: &'world SystemMeta,
_state: &'world mut Self::State,
_tick: Tick,
) -> Self::Item<'world> {
unsafe { &mut *(world as *const World as usize as *mut World) }
}
#[inline]
fn get_self<'world>(
world: &'world World,
system_meta: &'world SystemMeta,
state: &'world mut Self::State,
tick: Tick,
) -> Self {
unsafe { transmute(Self::get_param(world, system_meta, state, tick)) }
}
}
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>,)*);
fn init_state(_world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {
(($($param::init_state(_world, _system_meta),)*))
}
fn align(_world: &World, _system_meta: &SystemMeta, state: &mut Self::State) {
let ($($param,)*) = state;
$($param::align(_world, _system_meta, $param);)*
}
#[allow(clippy::unused_unit)]
fn get_param<'world>(
_world: &'world World,
_system_meta: &'world SystemMeta,
state: &'world mut Self::State,
_tick: Tick,
) -> Self::Item<'world> {
let ($($param,)*) = state;
($($param::get_param(_world, _system_meta, $param, _tick),)*)
}
fn get_self<'world>(
_world: &'world World,
_system_meta: &'world SystemMeta,
state: &'world mut Self::State,
_tick: Tick,
) -> Self {
let ($($param,)*) = state;
($($param::get_self(_world, _system_meta, $param, _tick),)*)
}
}
};
}
all_tuples!(impl_system_param_tuple, 0, 32, P);