Path: blob/main/crates/bevy_ecs/src/system/adapter_system.rs
6604 views
use alloc::vec::Vec;1use bevy_utils::prelude::DebugName;23use super::{IntoSystem, ReadOnlySystem, RunSystemError, System, SystemParamValidationError};4use crate::{5schedule::InternedSystemSet,6system::{input::SystemInput, SystemIn},7world::unsafe_world_cell::UnsafeWorldCell,8};910/// Customizes the behavior of an [`AdapterSystem`]11///12/// # Examples13///14/// ```15/// # use bevy_ecs::prelude::*;16/// use bevy_ecs::system::{Adapt, AdapterSystem, RunSystemError};17///18/// // A system adapter that inverts the result of a system.19/// // NOTE: Instead of manually implementing this, you can just use `bevy_ecs::schedule::common_conditions::not`.20/// pub type NotSystem<S> = AdapterSystem<NotMarker, S>;21///22/// // This struct is used to customize the behavior of our adapter.23/// pub struct NotMarker;24///25/// impl<S> Adapt<S> for NotMarker26/// where27/// S: System,28/// S::Out: std::ops::Not,29/// {30/// type In = S::In;31/// type Out = <S::Out as std::ops::Not>::Output;32///33/// fn adapt(34/// &mut self,35/// input: <Self::In as SystemInput>::Inner<'_>,36/// run_system: impl FnOnce(SystemIn<'_, S>) -> Result<S::Out, RunSystemError>,37/// ) -> Result<Self::Out, RunSystemError> {38/// let result = run_system(input)?;39/// Ok(!result)40/// }41/// }42/// # let mut world = World::new();43/// # let mut system = NotSystem::new(NotMarker, IntoSystem::into_system(|| false), "".into());44/// # system.initialize(&mut world);45/// # assert!(system.run((), &mut world).unwrap());46/// ```47#[diagnostic::on_unimplemented(48message = "`{Self}` can not adapt a system of type `{S}`",49label = "invalid system adapter"50)]51pub trait Adapt<S: System>: Send + Sync + 'static {52/// The [input](System::In) type for an [`AdapterSystem`].53type In: SystemInput;54/// The [output](System::Out) type for an [`AdapterSystem`].55type Out;5657/// When used in an [`AdapterSystem`], this function customizes how the system58/// is run and how its inputs/outputs are adapted.59fn adapt(60&mut self,61input: <Self::In as SystemInput>::Inner<'_>,62run_system: impl FnOnce(SystemIn<'_, S>) -> Result<S::Out, RunSystemError>,63) -> Result<Self::Out, RunSystemError>;64}6566/// An [`IntoSystem`] creating an instance of [`AdapterSystem`].67#[derive(Clone)]68pub struct IntoAdapterSystem<Func, S> {69func: Func,70system: S,71}7273impl<Func, S> IntoAdapterSystem<Func, S> {74/// Creates a new [`IntoSystem`] that uses `func` to adapt `system`, via the [`Adapt`] trait.75pub const fn new(func: Func, system: S) -> Self {76Self { func, system }77}78}7980#[doc(hidden)]81pub struct IsAdapterSystemMarker;8283impl<Func, S, I, O, M> IntoSystem<Func::In, Func::Out, (IsAdapterSystemMarker, I, O, M)>84for IntoAdapterSystem<Func, S>85where86Func: Adapt<S::System>,87I: SystemInput,88S: IntoSystem<I, O, M>,89{90type System = AdapterSystem<Func, S::System>;9192// Required method93fn into_system(this: Self) -> Self::System {94let system = IntoSystem::into_system(this.system);95let name = system.name();96AdapterSystem::new(this.func, system, name)97}98}99100/// A [`System`] that takes the output of `S` and transforms it by applying `Func` to it.101#[derive(Clone)]102pub struct AdapterSystem<Func, S> {103func: Func,104system: S,105name: DebugName,106}107108impl<Func, S> AdapterSystem<Func, S>109where110Func: Adapt<S>,111S: System,112{113/// Creates a new [`System`] that uses `func` to adapt `system`, via the [`Adapt`] trait.114pub const fn new(func: Func, system: S, name: DebugName) -> Self {115Self { func, system, name }116}117}118119impl<Func, S> System for AdapterSystem<Func, S>120where121Func: Adapt<S>,122S: System,123{124type In = Func::In;125type Out = Func::Out;126127fn name(&self) -> DebugName {128self.name.clone()129}130131#[inline]132fn flags(&self) -> super::SystemStateFlags {133self.system.flags()134}135136#[inline]137unsafe fn run_unsafe(138&mut self,139input: SystemIn<'_, Self>,140world: UnsafeWorldCell,141) -> Result<Self::Out, RunSystemError> {142// SAFETY: `system.run_unsafe` has the same invariants as `self.run_unsafe`.143self.func.adapt(input, |input| unsafe {144self.system.run_unsafe(input, world)145})146}147148#[cfg(feature = "hotpatching")]149#[inline]150fn refresh_hotpatch(&mut self) {151self.system.refresh_hotpatch();152}153154#[inline]155fn apply_deferred(&mut self, world: &mut crate::prelude::World) {156self.system.apply_deferred(world);157}158159#[inline]160fn queue_deferred(&mut self, world: crate::world::DeferredWorld) {161self.system.queue_deferred(world);162}163164#[inline]165unsafe fn validate_param_unsafe(166&mut self,167world: UnsafeWorldCell,168) -> Result<(), SystemParamValidationError> {169// SAFETY: Delegate to other `System` implementations.170unsafe { self.system.validate_param_unsafe(world) }171}172173fn initialize(&mut self, world: &mut crate::prelude::World) -> crate::query::FilteredAccessSet {174self.system.initialize(world)175}176177fn check_change_tick(&mut self, check: crate::component::CheckChangeTicks) {178self.system.check_change_tick(check);179}180181fn default_system_sets(&self) -> Vec<InternedSystemSet> {182self.system.default_system_sets()183}184185fn get_last_run(&self) -> crate::component::Tick {186self.system.get_last_run()187}188189fn set_last_run(&mut self, last_run: crate::component::Tick) {190self.system.set_last_run(last_run);191}192}193194// SAFETY: The inner system is read-only.195unsafe impl<Func, S> ReadOnlySystem for AdapterSystem<Func, S>196where197Func: Adapt<S>,198S: ReadOnlySystem,199{200}201202impl<F, S, Out> Adapt<S> for F203where204F: Send + Sync + 'static + FnMut(S::Out) -> Out,205S: System,206{207type In = S::In;208type Out = Out;209210fn adapt(211&mut self,212input: <Self::In as SystemInput>::Inner<'_>,213run_system: impl FnOnce(SystemIn<'_, S>) -> Result<S::Out, RunSystemError>,214) -> Result<Self::Out, RunSystemError> {215run_system(input).map(self)216}217}218219220