use std::{
marker::PhantomData, mem::transmute, ops::{Deref, DerefMut}
};
use crate::{
world_ptr::Ptr,
archetype::ComponentInfo, prelude::FromWorld, system::{Relation, SystemMeta}, world::{ComponentIndex, 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> + 'world;
fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State;
#[allow(unused_variables)]
fn align(state: &mut Self::State) {}
fn init(_state: &mut Self::State) {}
fn get_param<'world>(
state: &'world mut Self::State,
) -> Self::Item<'world>;
fn get_self<'world>(
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 + '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>(
state: &'world mut Self::State,
) -> Self::Item<'world> {
Local(state)
}
#[inline]
fn get_self<'world>(
state: &'world mut Self::State,
) -> Self {
unsafe { transmute(Self::get_param(state)) }
}
}
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>(
_state: &'world mut Self::State,
) -> Self::Item<'world> {
ComponentDebugIndex(_state.clone(), PhantomData)
}
#[inline]
fn get_self<'world>(
state: &'world mut Self::State,
) -> Self {
unsafe { transmute(Self::get_param(state)) }
}
}
impl SystemParam for &World {
type State = Ptr<World>;
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);
Ptr::new(world)
}
fn get_param<'world>(
state: &'world mut Self::State,
) -> Self::Item<'world> {
&*state
}
#[inline]
fn get_self<'world>(
state: &'world mut Self::State,
) -> Self {
unsafe { transmute(Self::get_param( state)) }
}
}
impl SystemParam for &mut World {
type State = Ptr<World>;
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);
Ptr::new(world)
}
fn get_param<'world>(
state: &'world mut Self::State,
) -> Self::Item<'world> {
&mut *state
}
#[inline]
fn get_self<'world>(
state: &'world mut Self::State,
) -> Self {
unsafe { transmute(Self::get_param( 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>,)*);
fn init_state(_world: &mut World, _system_meta: &mut SystemMeta) -> Self::State {
(($($param::init_state(_world, _system_meta),)*))
}
#[allow(clippy::unused_unit)]
fn init<'world>(
state: &'world mut Self::State,
) {
let ($($param,)*) = state;
($($param::init($param),)*);
}
fn align(state: &mut Self::State) {
let ($($param,)*) = state;
$($param::align($param);)*
}
#[allow(clippy::unused_unit)]
fn get_param<'world>(
state: &'world mut Self::State,
) -> Self::Item<'world> {
let ($($param,)*) = state;
($($param::get_param($param),)*)
}
fn get_self<'world>(
state: &'world mut Self::State,
) -> Self {
let ($($param,)*) = state;
($($param::get_self($param),)*)
}
}
};
}
all_tuples!(impl_system_param_tuple, 0, 32, P);