Convert to fallible system in IntoSystemConfigs (#17051)

# Objective

- #16589 added an enum to switch between fallible and infallible system.
This branching should be unnecessary if we wrap infallible systems in a
function to return `Ok(())`.

## Solution

- Create a wrapper system for `System<(), ()>`s that returns `Ok` on the
call to `run` and `run_unsafe`. The wrapper should compile out, but I
haven't checked.
- I removed the `impl IntoSystemConfigs for BoxedSystem<(), ()>` as I
couldn't figure out a way to keep the impl without double boxing.

## Testing

- ran `many_foxes` example to check if it still runs.

## Migration Guide

- `IntoSystemConfigs` has been removed for `BoxedSystem<(), ()>`. Either
use `InfallibleSystemWrapper` before boxing or make your system return
`bevy::ecs::prelude::Result`.
This commit is contained in:
Mike 2024-12-30 16:39:29 -08:00 committed by GitHub
parent 33afd38ee1
commit ac43d5c94f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 74 additions and 140 deletions

View File

@ -9,7 +9,7 @@ use crate::{
set::{InternedSystemSet, IntoSystemSet, SystemSet},
Chain,
},
system::{BoxedSystem, IntoSystem, ScheduleSystem, System},
system::{BoxedSystem, InfallibleSystemWrapper, IntoSystem, ScheduleSystem, System},
};
fn new_condition<M>(condition: impl Condition<M>) -> BoxedCondition {
@ -519,6 +519,7 @@ impl IntoSystemConfigs<()> for SystemConfigs {
}
}
/// Marker component to allow for conflicting implementations of [`IntoSystemConfigs`]
#[doc(hidden)]
pub struct Infallible;
@ -527,17 +528,12 @@ where
F: IntoSystem<(), (), Marker>,
{
fn into_configs(self) -> SystemConfigs {
let boxed_system = Box::new(IntoSystem::into_system(self));
SystemConfigs::new_system(ScheduleSystem::Infallible(boxed_system))
}
}
impl IntoSystemConfigs<()> for BoxedSystem<(), ()> {
fn into_configs(self) -> SystemConfigs {
SystemConfigs::new_system(ScheduleSystem::Infallible(self))
let wrapper = InfallibleSystemWrapper::new(IntoSystem::into_system(self));
SystemConfigs::new_system(Box::new(wrapper))
}
}
/// Marker component to allow for conflicting implementations of [`IntoSystemConfigs`]
#[doc(hidden)]
pub struct Fallible;
@ -547,13 +543,13 @@ where
{
fn into_configs(self) -> SystemConfigs {
let boxed_system = Box::new(IntoSystem::into_system(self));
SystemConfigs::new_system(ScheduleSystem::Fallible(boxed_system))
SystemConfigs::new_system(boxed_system)
}
}
impl IntoSystemConfigs<()> for BoxedSystem<(), Result> {
fn into_configs(self) -> SystemConfigs {
SystemConfigs::new_system(ScheduleSystem::Fallible(self))
SystemConfigs::new_system(self)
}
}

View File

@ -18,6 +18,7 @@ use crate::{
component::{ComponentId, Tick},
prelude::{IntoSystemSet, SystemSet},
query::Access,
result::Result,
schedule::{BoxedCondition, InternedSystemSet, NodeId, SystemTypeSet},
system::{ScheduleSystem, System, SystemIn},
world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
@ -158,7 +159,7 @@ pub(super) fn is_apply_deferred(system: &ScheduleSystem) -> bool {
impl System for ApplyDeferred {
type In = ();
type Out = ();
type Out = Result<()>;
fn name(&self) -> Cow<'static, str> {
Cow::Borrowed("bevy_ecs::apply_deferred")
@ -203,11 +204,13 @@ impl System for ApplyDeferred {
) -> Self::Out {
// This system does nothing on its own. The executor will apply deferred
// commands from other systems instead of running this system.
Ok(())
}
fn run(&mut self, _input: SystemIn<'_, Self>, _world: &mut World) -> Self::Out {
// This system does nothing on its own. The executor will apply deferred
// commands from other systems instead of running this system.
Ok(())
}
fn apply_deferred(&mut self, _world: &mut World) {}
@ -259,7 +262,7 @@ mod __rust_begin_short_backtrace {
use crate::{
result::Result,
system::{ReadOnlySystem, ScheduleSystem, System},
system::{ReadOnlySystem, ScheduleSystem},
world::{unsafe_world_cell::UnsafeWorldCell, World},
};

View File

@ -20,7 +20,7 @@ use crate::{
prelude::Resource,
query::Access,
schedule::{is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule},
system::{ScheduleSystem, System},
system::ScheduleSystem,
world::{unsafe_world_cell::UnsafeWorldCell, World},
};

View File

@ -7,7 +7,6 @@ use crate::{
schedule::{
executor::is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule,
},
system::System,
world::World,
};
@ -136,7 +135,7 @@ impl SystemExecutor for SimpleExecutor {
impl SimpleExecutor {
/// Creates a new simple executor for use in a [`Schedule`](crate::schedule::Schedule).
/// This calls each system in order and immediately calls [`System::apply_deferred`].
/// This calls each system in order and immediately calls [`System::apply_deferred`](crate::system::System).
pub const fn new() -> Self {
Self {
evaluated_sets: FixedBitSet::new(),

View File

@ -5,7 +5,6 @@ use tracing::info_span;
use crate::{
schedule::{is_apply_deferred, BoxedCondition, ExecutorKind, SystemExecutor, SystemSchedule},
system::System,
world::World,
};

View File

@ -21,7 +21,7 @@ use crate::{
prelude::Component,
result::Result,
schedule::*,
system::{IntoSystem, Resource, ScheduleSystem, System},
system::{IntoSystem, Resource, ScheduleSystem},
world::World,
};
@ -1053,7 +1053,7 @@ impl ScheduleGraph {
Ok(())
}
/// Initializes any newly-added systems and conditions by calling [`System::initialize`]
/// Initializes any newly-added systems and conditions by calling [`System::initialize`](crate::system::System)
pub fn initialize(&mut self, world: &mut World) {
for (id, i) in self.uninit.drain(..) {
match id {
@ -1200,8 +1200,8 @@ impl ScheduleGraph {
let id = NodeId::System(self.systems.len());
self.systems
.push(SystemNode::new(ScheduleSystem::Infallible(Box::new(
IntoSystem::into_system(ApplyDeferred),
.push(SystemNode::new(Box::new(IntoSystem::into_system(
ApplyDeferred,
))));
self.system_conditions.push(Vec::new());

View File

@ -1,6 +1,6 @@
use crate::{
schedule::{InternedScheduleLabel, NodeId, Schedule, ScheduleLabel},
system::{IntoSystem, ResMut, Resource, System},
system::{IntoSystem, ResMut, Resource},
};
use alloc::vec::Vec;
use bevy_utils::{HashMap, TypeIdMap};

View File

@ -1,183 +1,120 @@
use alloc::{borrow::Cow, vec::Vec};
use core::any::TypeId;
use crate::{
archetype::ArchetypeComponentId,
component::{ComponentId, Tick},
query::Access,
result::Result,
schedule::InternedSystemSet,
system::{input::SystemIn, BoxedSystem, System},
world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
};
/// A type which wraps and unifies the different sorts of systems that can be added to a schedule.
pub enum ScheduleSystem {
/// A system that does not return a result.
Infallible(BoxedSystem<(), ()>),
/// A system that does return a result.
Fallible(BoxedSystem<(), Result>),
use super::IntoSystem;
/// A wrapper system to change a system that returns `()` to return `Ok(())` to make it into a [`ScheduleSystem`]
pub struct InfallibleSystemWrapper<S: System<In = (), Out = ()>>(S);
impl<S: System<In = (), Out = ()>> InfallibleSystemWrapper<S> {
/// Create a new `OkWrapperSystem`
pub fn new(system: S) -> Self {
Self(IntoSystem::into_system(system))
}
}
impl System for ScheduleSystem {
impl<S: System<In = (), Out = ()>> System for InfallibleSystemWrapper<S> {
type In = ();
type Out = Result;
#[inline(always)]
#[inline]
fn name(&self) -> Cow<'static, str> {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.name(),
ScheduleSystem::Fallible(inner_system) => inner_system.name(),
}
self.0.name()
}
#[inline(always)]
fn type_id(&self) -> TypeId {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.type_id(),
ScheduleSystem::Fallible(inner_system) => inner_system.type_id(),
}
}
#[inline(always)]
#[inline]
fn component_access(&self) -> &Access<ComponentId> {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.component_access(),
ScheduleSystem::Fallible(inner_system) => inner_system.component_access(),
}
self.0.component_access()
}
#[inline(always)]
#[inline]
fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.archetype_component_access(),
ScheduleSystem::Fallible(inner_system) => inner_system.archetype_component_access(),
}
self.0.archetype_component_access()
}
#[inline(always)]
#[inline]
fn is_send(&self) -> bool {
self.0.is_send()
}
#[inline]
fn is_exclusive(&self) -> bool {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.is_exclusive(),
ScheduleSystem::Fallible(inner_system) => inner_system.is_exclusive(),
}
self.0.is_exclusive()
}
#[inline(always)]
#[inline]
fn has_deferred(&self) -> bool {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.has_deferred(),
ScheduleSystem::Fallible(inner_system) => inner_system.has_deferred(),
}
self.0.has_deferred()
}
#[inline(always)]
#[inline]
unsafe fn run_unsafe(
&mut self,
input: SystemIn<'_, Self>,
world: UnsafeWorldCell,
) -> Self::Out {
match self {
ScheduleSystem::Infallible(inner_system) => {
inner_system.run_unsafe(input, world);
Ok(())
}
ScheduleSystem::Fallible(inner_system) => inner_system.run_unsafe(input, world),
}
self.0.run_unsafe(input, world);
Ok(())
}
#[inline(always)]
#[inline]
fn run(&mut self, input: SystemIn<'_, Self>, world: &mut World) -> Self::Out {
match self {
ScheduleSystem::Infallible(inner_system) => {
inner_system.run(input, world);
Ok(())
}
ScheduleSystem::Fallible(inner_system) => inner_system.run(input, world),
}
self.0.run(input, world);
Ok(())
}
#[inline(always)]
#[inline]
fn apply_deferred(&mut self, world: &mut World) {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.apply_deferred(world),
ScheduleSystem::Fallible(inner_system) => inner_system.apply_deferred(world),
}
self.0.apply_deferred(world);
}
#[inline(always)]
#[inline]
fn queue_deferred(&mut self, world: DeferredWorld) {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.queue_deferred(world),
ScheduleSystem::Fallible(inner_system) => inner_system.queue_deferred(world),
}
self.0.queue_deferred(world);
}
#[inline(always)]
fn is_send(&self) -> bool {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.is_send(),
ScheduleSystem::Fallible(inner_system) => inner_system.is_send(),
}
}
#[inline(always)]
#[inline]
unsafe fn validate_param_unsafe(&mut self, world: UnsafeWorldCell) -> bool {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.validate_param_unsafe(world),
ScheduleSystem::Fallible(inner_system) => inner_system.validate_param_unsafe(world),
}
self.0.validate_param_unsafe(world)
}
#[inline(always)]
#[inline]
fn initialize(&mut self, world: &mut World) {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.initialize(world),
ScheduleSystem::Fallible(inner_system) => inner_system.initialize(world),
}
self.0.initialize(world);
}
#[inline(always)]
#[inline]
fn update_archetype_component_access(&mut self, world: UnsafeWorldCell) {
match self {
ScheduleSystem::Infallible(inner_system) => {
inner_system.update_archetype_component_access(world);
}
ScheduleSystem::Fallible(inner_system) => {
inner_system.update_archetype_component_access(world);
}
}
self.0.update_archetype_component_access(world);
}
#[inline(always)]
#[inline]
fn check_change_tick(&mut self, change_tick: Tick) {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.check_change_tick(change_tick),
ScheduleSystem::Fallible(inner_system) => inner_system.check_change_tick(change_tick),
}
self.0.check_change_tick(change_tick);
}
#[inline(always)]
fn default_system_sets(&self) -> Vec<InternedSystemSet> {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.default_system_sets(),
ScheduleSystem::Fallible(inner_system) => inner_system.default_system_sets(),
}
}
#[inline(always)]
#[inline]
fn get_last_run(&self) -> Tick {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.get_last_run(),
ScheduleSystem::Fallible(inner_system) => inner_system.get_last_run(),
}
self.0.get_last_run()
}
#[inline(always)]
#[inline]
fn set_last_run(&mut self, last_run: Tick) {
match self {
ScheduleSystem::Infallible(inner_system) => inner_system.set_last_run(last_run),
ScheduleSystem::Fallible(inner_system) => inner_system.set_last_run(last_run),
}
self.0.set_last_run(last_run);
}
fn default_system_sets(&self) -> Vec<crate::schedule::InternedSystemSet> {
self.0.default_system_sets()
}
}
/// Type alias for a `BoxedSystem` that a `Schedule` can store.
pub type ScheduleSystem = BoxedSystem<(), Result>;