mod func;
use alloc::vec::Vec;
use core::{any::TypeId, ptr::NonNull};
use crate::{
action::ActionBuffer, archetype::Archetype, component::ComponentInfo, world::World, Access,
ActionBufferSliceExt,
};
pub use self::func::{
ActionEncoderState, FnArg, FnArgState, FromWorld, IsFunctionSystem, QueryArg, Res, ResMut,
ResMutNoSend, ResMutNoSendState, ResMutState, ResNoSync, ResNoSyncState, ResState, State,
StateState,
};
pub trait ActionBufferQueue {
fn get<'a>(&self) -> ActionBuffer;
fn flush(&mut self, buffer: ActionBuffer);
}
impl ActionBufferQueue for Vec<ActionBuffer> {
fn get(&self) -> ActionBuffer {
ActionBuffer::new()
}
fn flush(&mut self, buffer: ActionBuffer) {
self.push(buffer);
}
}
pub unsafe trait System {
#[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 component_access(&self, comp: &ComponentInfo) -> Option<Access>;
#[must_use]
fn resource_type_access(&self, ty: TypeId) -> Option<Access>;
unsafe fn run_unchecked(&mut self, world: NonNull<World>, queue: &mut dyn ActionBufferQueue);
fn run(&mut self, world: &mut World, queue: &mut dyn ActionBufferQueue) {
unsafe { self.run_unchecked(NonNull::from(world), queue) };
}
fn run_alone(&mut self, world: &mut World) {
let mut buffers = Vec::new();
self.run(world, &mut buffers);
buffers.execute_all(world);
}
}
pub trait IntoSystem<Marker> {
type System: System + Send + 'static;
#[must_use]
fn into_system(self) -> Self::System;
}
pub enum IsSystem {}
impl<T> IntoSystem<IsSystem> for T
where
T: System + Send + 'static,
{
type System = T;
fn into_system(self) -> T {
self
}
}
pub trait LocalSystem {
fn run(&mut self, world: &mut World);
}
pub enum IsLocalSystem {}
pub struct IntoLocalSystem<S> {
system: S,
}
unsafe impl<S> System for IntoLocalSystem<S>
where
S: LocalSystem,
{
fn is_local(&self) -> bool {
true
}
fn world_access(&self) -> Option<Access> {
Some(Access::Write)
}
fn visit_archetype(&self, _archetype: &Archetype) -> bool {
true
}
fn component_access(&self, _comp: &ComponentInfo) -> Option<Access> {
Some(Access::Write)
}
fn resource_type_access(&self, _ty: TypeId) -> Option<Access> {
Some(Access::Write)
}
unsafe fn run_unchecked(
&mut self,
mut world: NonNull<World>,
_queue: &mut dyn ActionBufferQueue,
) {
let world = unsafe { world.as_mut() };
self.system.run(world);
}
}
impl<S> IntoSystem<IsLocalSystem> for S
where
S: LocalSystem + Send + 'static,
{
type System = IntoLocalSystem<S>;
fn into_system(self) -> IntoLocalSystem<S> {
IntoLocalSystem { system: self }
}
}
pub struct SystemSequence<T>(pub T);
macro_rules! impl_system {
() => {};
($($a:ident)+) => {
#[allow(non_snake_case)]
impl< Marker, $($a),+ > IntoSystem<Marker> for ($($a,)+)
where
$($a: IntoSystem<Marker>,)+
{
type System = SystemSequence<($($a::System,)+)>;
fn into_system(self) -> Self::System {
let ($($a,)+) = self;
SystemSequence(($($a.into_system(),)+))
}
}
#[allow(non_snake_case)]
unsafe impl< $($a),+ > System for SystemSequence<($($a,)+)>
where
$($a: System,)+
{
fn is_local(&self) -> bool {
let ($($a,)+) = &self.0;
true $(&& $a.is_local())+
}
#[inline]
fn world_access(&self) -> Option<Access> {
let ($($a,)+) = &self.0;
let mut result = None;
$(
result = match (result, $a.world_access()) {
(Some(Access::Write), _) | (_, Some(Access::Write)) => Some(Access::Write),
(Some(Access::Read), _) | (_, Some(Access::Read)) => Some(Access::Read),
(None, None) => None,
};
)+
result
}
#[inline]
fn visit_archetype(&self, archetype: &Archetype) -> bool {
let ($($a,)*) = &self.0;
false $(|| $a.visit_archetype(archetype))+
}
#[inline]
fn component_access(&self, comp: &ComponentInfo) -> Option<Access> {
let ($($a,)+) = &self.0;
let mut result = None;
$(
result = match (result, $a.component_access(comp)) {
(Some(Access::Write), _) | (_, Some(Access::Write)) => Some(Access::Write),
(Some(Access::Read), _) | (_, Some(Access::Read)) => Some(Access::Read),
(None, None) => None,
};
)+
result
}
#[inline]
fn resource_type_access(&self, ty: TypeId) -> Option<Access> {
let ($($a,)+) = &self.0;
let mut result = None;
$(
result = match (result, $a.resource_type_access(ty)) {
(Some(Access::Write), _) | (_, Some(Access::Write)) => Some(Access::Write),
(Some(Access::Read), _) | (_, Some(Access::Read)) => Some(Access::Read),
(None, None) => None,
};
)+
result
}
#[inline]
unsafe fn run_unchecked(&mut self, world: NonNull<World>, queue: &mut dyn ActionBufferQueue) {
let ($($a,)+) = &mut self.0;
unsafe {
$($a.run_unchecked(world, queue);)+
}
}
}
};
}
for_tuple!(impl_system);