mod action;
mod res;
mod state;
mod view;
mod world;
use core::{
any::{type_name, TypeId},
marker::PhantomData,
ptr::NonNull,
};
use crate::{archetype::Archetype, component::ComponentInfo, world::World};
use super::{Access, ActionBufferQueue, IntoSystem, System};
pub use self::{
action::ActionEncoderState,
res::{
Res, ResMut, ResMutNoSend, ResMutNoSendState, ResMutState, ResNoSync, ResNoSyncState,
ResState,
},
state::{State, StateState},
view::QueryArg,
};
pub struct IsFunctionSystem<Args> {
marker: PhantomData<fn(Args)>,
}
pub unsafe trait FnArgState: Send + 'static {
type Arg<'a>: FnArg<State = Self> + 'a;
#[must_use]
fn new() -> Self;
#[must_use]
fn is_local(&self) -> bool;
#[must_use]
fn world_access(&self) -> Option<Access>;
#[must_use]
fn visit_archetype(&self, archetype: &Archetype) -> bool;
#[must_use]
fn borrows_components_at_runtime(&self) -> bool;
#[must_use]
fn component_access(&self, comp: &ComponentInfo) -> Option<Access>;
#[must_use]
fn resource_type_access(&self, ty: TypeId) -> Option<Access>;
unsafe fn get_unchecked<'a>(
&'a mut self,
world: NonNull<World>,
queue: &mut dyn ActionBufferQueue,
) -> Self::Arg<'a>;
#[inline(always)]
unsafe fn flush_unchecked(&mut self, world: NonNull<World>, queue: &mut dyn ActionBufferQueue) {
let _ = world;
let _ = queue;
}
}
pub trait FnArg {
type State: FnArgState;
}
pub struct FunctionSystem<F, ArgStates> {
f: F,
args: ArgStates,
}
macro_rules! impl_func {
($($a:ident)*) => {
#[allow(unused_variables, unused_mut, non_snake_case)]
unsafe impl<Func $(,$a)*> System for FunctionSystem<Func, ($($a,)*)>
where
$($a: FnArgState,)*
Func: for<'a> FnMut($($a::Arg<'a>,)*),
{
#[inline(always)]
fn is_local(&self) -> bool {
let ($($a,)*) = &self.args;
false $( || $a.is_local() )*
}
#[inline(always)]
fn world_access(&self) -> Option<Access> {
let ($($a,)*) = &self.args;
let mut result = None;
$(
result = match (result, $a.world_access()) {
(None, one) | (one, None) => one,
(Some(Access::Read), Some(Access::Read)) => Some(Access::Read),
_ => {
panic!("Mutable `World` aliasing in system `{}`", type_name::<Self>());
}
};
)*
result
}
#[inline(always)]
fn visit_archetype(&self, archetype: &Archetype) -> bool {
let ($($a,)*) = &self.args;
false $( || $a.visit_archetype(archetype) )*
}
#[inline(always)]
fn component_access(&self, comp: &ComponentInfo) -> Option<Access> {
let ($($a,)*) = &self.args;
let mut result = None;
let mut runtime_borrow = true;
$(
if let Some(access) = $a.component_access(comp) {
runtime_borrow &= $a.borrows_components_at_runtime();
result = match (result, access) {
(None, one) => Some(one),
(Some(Access::Read), Access::Read) => Some(Access::Read),
_ => {
if runtime_borrow {
Some(Access::Write)
} else {
panic!("Conflicting args in system `{}`.\nA component is aliased mutably.\nIf arguments require mutable aliasing, all arguments that access a type must use runtime borrow check.\nFor example `View` type does not use runtime borrow check and should be replaced with `ViewCell`.", type_name::<Func>());
}
}
};
}
)*
result
}
#[inline(always)]
fn resource_type_access(&self, ty: TypeId) -> Option<Access> {
let ($($a,)*) = &self.args;
let mut result = None;
$(
result = match (result, $a.resource_type_access(ty)) {
(None, one) | (one, None) => one,
(Some(Access::Read), Some(Access::Read)) => Some(Access::Read),
_ => {
panic!("Conflicting args in system `{}`.
A resource is aliased mutably.",
type_name::<$a>());
}
};
)*
result
}
#[inline(always)]
unsafe fn run_unchecked(&mut self, world: NonNull<World>, queue: &mut dyn ActionBufferQueue) {
let ($($a,)*) = &mut self.args;
{
$(
let $a = unsafe { $a.get_unchecked(world, queue) };
)*
(self.f)($($a,)*);
}
$(
unsafe { $a.flush_unchecked(world, queue) };
)*
}
}
impl<Func $(, $a)*> IntoSystem<IsFunctionSystem<($($a,)*)>> for Func
where
$($a: FnArg,)*
Func: FnMut($($a),*) + Send + 'static,
Func: for<'a> FnMut($(<$a::State as FnArgState>::Arg<'a>),*),
{
type System = FunctionSystem<Self, ($($a::State,)*)>;
#[inline(always)]
fn into_system(self) -> Self::System {
FunctionSystem {
f: self,
args: ($($a::State::new(),)*),
}
}
}
}
}
for_tuple!(impl_func);
pub trait FromWorld {
#[must_use]
fn from_world(world: &World) -> Self;
}
impl<T> FromWorld for T
where
T: Default,
{
#[inline(always)]
fn from_world(_: &World) -> Self {
T::default()
}
}