use alloc::vec::Vec;
use bevy_utils::prelude::DebugName;
use super::{IntoSystem, ReadOnlySystem, RunSystemError, System, SystemParamValidationError};
use crate::{
schedule::InternedSystemSet,
system::{input::SystemInput, SystemIn},
world::unsafe_world_cell::UnsafeWorldCell,
};
#[diagnostic::on_unimplemented(
message = "`{Self}` can not adapt a system of type `{S}`",
label = "invalid system adapter"
)]
pub trait Adapt<S: System>: Send + Sync + 'static {
type In: SystemInput;
type Out;
fn adapt(
&mut self,
input: <Self::In as SystemInput>::Inner<'_>,
run_system: impl FnOnce(SystemIn<'_, S>) -> Result<S::Out, RunSystemError>,
) -> Result<Self::Out, RunSystemError>;
}
#[derive(Clone)]
pub struct IntoAdapterSystem<Func, S> {
func: Func,
system: S,
}
impl<Func, S> IntoAdapterSystem<Func, S> {
pub const fn new(func: Func, system: S) -> Self {
Self { func, system }
}
}
#[doc(hidden)]
pub struct IsAdapterSystemMarker;
impl<Func, S, I, O, M> IntoSystem<Func::In, Func::Out, (IsAdapterSystemMarker, I, O, M)>
for IntoAdapterSystem<Func, S>
where
Func: Adapt<S::System>,
I: SystemInput,
S: IntoSystem<I, O, M>,
{
type System = AdapterSystem<Func, S::System>;
fn into_system(this: Self) -> Self::System {
let system = IntoSystem::into_system(this.system);
let name = system.name();
AdapterSystem::new(this.func, system, name)
}
}
#[derive(Clone)]
pub struct AdapterSystem<Func, S> {
func: Func,
system: S,
name: DebugName,
}
impl<Func, S> AdapterSystem<Func, S>
where
Func: Adapt<S>,
S: System,
{
pub const fn new(func: Func, system: S, name: DebugName) -> Self {
Self { func, system, name }
}
}
impl<Func, S> System for AdapterSystem<Func, S>
where
Func: Adapt<S>,
S: System,
{
type In = Func::In;
type Out = Func::Out;
fn name(&self) -> DebugName {
self.name.clone()
}
#[inline]
fn flags(&self) -> super::SystemStateFlags {
self.system.flags()
}
#[inline]
unsafe fn run_unsafe(
&mut self,
input: SystemIn<'_, Self>,
world: UnsafeWorldCell,
) -> Result<Self::Out, RunSystemError> {
self.func.adapt(input, |input| unsafe {
self.system.run_unsafe(input, world)
})
}
#[cfg(feature = "hotpatching")]
#[inline]
fn refresh_hotpatch(&mut self) {
self.system.refresh_hotpatch();
}
#[inline]
fn apply_deferred(&mut self, world: &mut crate::prelude::World) {
self.system.apply_deferred(world);
}
#[inline]
fn queue_deferred(&mut self, world: crate::world::DeferredWorld) {
self.system.queue_deferred(world);
}
#[inline]
unsafe fn validate_param_unsafe(
&mut self,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
unsafe { self.system.validate_param_unsafe(world) }
}
fn initialize(&mut self, world: &mut crate::prelude::World) -> crate::query::FilteredAccessSet {
self.system.initialize(world)
}
fn check_change_tick(&mut self, check: crate::change_detection::CheckChangeTicks) {
self.system.check_change_tick(check);
}
fn default_system_sets(&self) -> Vec<InternedSystemSet> {
self.system.default_system_sets()
}
fn get_last_run(&self) -> crate::change_detection::Tick {
self.system.get_last_run()
}
fn set_last_run(&mut self, last_run: crate::change_detection::Tick) {
self.system.set_last_run(last_run);
}
}
unsafe impl<Func, S> ReadOnlySystem for AdapterSystem<Func, S>
where
Func: Adapt<S>,
S: ReadOnlySystem,
{
}
impl<F, S, Out> Adapt<S> for F
where
F: Send + Sync + 'static + FnMut(S::Out) -> Out,
S: System,
{
type In = S::In;
type Out = Out;
fn adapt(
&mut self,
input: <Self::In as SystemInput>::Inner<'_>,
run_system: impl FnOnce(SystemIn<'_, S>) -> Result<S::Out, RunSystemError>,
) -> Result<Self::Out, RunSystemError> {
run_system(input).map(self)
}
}