#![allow(clippy::too_many_arguments)]
use bevy_mod_ffi_core::dyn_system_param;
use bytemuck::Pod;
use std::slice;
mod builder;
pub use builder::{ParamBuilder, ParamCursor};
mod commands;
pub use commands::{Command, Commands};
mod observer;
pub use observer::{
EntityObserverSystem, IntoEntityObserverSystem, IntoObserverSystem, ObserverSystem, On,
OnEntity, SharedEvent,
};
mod param;
pub use param::SystemParam;
mod state;
pub use state::{SystemRef, SystemState};
pub type SystemClosure = Box<dyn FnMut(&[*mut dyn_system_param], *const u8, *mut u8)>;
#[allow(clippy::missing_safety_doc)]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn bevy_guest_run_system(
f_ptr: *mut (),
params: *const *mut dyn_system_param,
params_len: usize,
input_ptr: *const u8,
output_ptr: *mut u8,
) {
let f = unsafe { &mut *(f_ptr as *mut SystemClosure) };
let params_slice = unsafe { slice::from_raw_parts(params, params_len) };
f(params_slice, input_ptr, output_ptr);
}
pub trait SystemInput {}
#[repr(transparent)]
pub struct In<T>(pub T);
impl<T: Pod> SystemInput for In<T> {}
pub trait System {
type In;
type Out;
type Param: SystemParam;
fn run(
&mut self,
input: Self::In,
params: <Self::Param as SystemParam>::Item<'_, '_>,
) -> Self::Out;
}
pub trait IntoSystem<Marker> {
type In;
type Out;
type System: System<In = Self::In, Out = Self::Out>;
fn into_system(self) -> Self::System;
}
pub struct InputMarker;
pub struct FunctionSystem<F, Marker> {
pub f: F,
_marker: std::marker::PhantomData<fn() -> Marker>,
}
impl<F, Marker> FunctionSystem<F, Marker> {
pub fn new(f: F) -> Self {
Self {
f,
_marker: std::marker::PhantomData,
}
}
}
macro_rules! impl_system_fn {
($($param:ident),*) => {
#[allow(non_snake_case)]
impl<Out, F, $($param: SystemParam,)*> System for FunctionSystem<F, fn($($param,)*) -> Out>
where
F: Send + Sync + 'static,
for<'a> &'a mut F:
FnMut($($param,)*) -> Out +
FnMut($($param::Item<'_, '_>,)*) -> Out,
Out: 'static,
{
type In = ();
type Out = Out;
type Param = ($($param,)*);
fn run(
&mut self,
_input: Self::In,
param_value: <Self::Param as SystemParam>::Item<'_, '_>,
) -> Self::Out {
fn call<Out, $($param,)*>(
mut f: impl FnMut($($param,)*) -> Out,
$($param: $param,)*
) -> Out {
f($($param,)*)
}
let ($($param,)*) = param_value;
call(&mut self.f, $($param,)*)
}
}
#[allow(non_snake_case)]
impl<Out, F, $($param: SystemParam,)*> IntoSystem<fn($($param,)*) -> Out> for F
where
F: Send + Sync + 'static,
for<'a> &'a mut F:
FnMut($($param,)*) -> Out +
FnMut($($param::Item<'_, '_>,)*) -> Out,
Out: 'static,
{
type In = ();
type Out = Out;
type System = FunctionSystem<F, fn($($param,)*) -> Out>;
fn into_system(self) -> Self::System {
FunctionSystem::new(self)
}
}
#[allow(non_snake_case)]
impl<I, Out, Func, $($param: SystemParam,)*> System for FunctionSystem<Func, (InputMarker, fn(I, $($param,)*) -> Out)>
where
I: SystemInput,
Func: Send + Sync + 'static,
for<'a> &'a mut Func:
FnMut(I, $($param,)*) -> Out +
FnMut(I, $($param::Item<'_, '_>,)*) -> Out,
Out: 'static,
{
type In = I;
type Out = Out;
type Param = ($($param,)*);
fn run(
&mut self,
input: Self::In,
param_value: <Self::Param as SystemParam>::Item<'_, '_>,
) -> Self::Out {
fn call<I, Out, $($param,)*>(
mut f: impl FnMut(I, $($param,)*) -> Out,
input: I,
$($param: $param,)*
) -> Out {
f(input, $($param,)*)
}
let ($($param,)*) = param_value;
call(&mut self.f, input, $($param,)*)
}
}
#[allow(non_snake_case, clippy::too_many_arguments)]
impl<I, Out, Func, $($param: SystemParam,)*> IntoSystem<(InputMarker, fn(I, $($param,)*) -> Out)> for Func
where
I: SystemInput,
Func: Send + Sync + 'static,
for<'a> &'a mut Func:
FnMut(I, $($param,)*) -> Out +
FnMut(I, $($param::Item<'_, '_>,)*) -> Out,
Out: 'static,
{
type In = I;
type Out = Out;
type System = FunctionSystem<Func, (InputMarker, fn(I, $($param,)*) -> Out)>;
fn into_system(self) -> Self::System {
FunctionSystem::new(self)
}
}
};
}
impl_system_fn!();
impl_system_fn!(P0);
impl_system_fn!(P0, P1);
impl_system_fn!(P0, P1, P2);
impl_system_fn!(P0, P1, P2, P3);
impl_system_fn!(P0, P1, P2, P3, P4);
impl_system_fn!(P0, P1, P2, P3, P4, P5);
impl_system_fn!(P0, P1, P2, P3, P4, P5, P6);
impl_system_fn!(P0, P1, P2, P3, P4, P5, P6, P7);