Skip to content

Commit 4ba1911

Browse files
committed
use System<> for handler and rework Commands trait
1 parent 5c5d22b commit 4ba1911

File tree

4 files changed

+92
-54
lines changed

4 files changed

+92
-54
lines changed

crates/bevy_ecs/src/system/commands/config.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
use super::{fallible::*, Command};
2+
use crate::system::System;
13
use std::{
24
fmt::Debug,
35
ops::{Deref, DerefMut},
46
};
57

6-
use super::{fallible::*, Command};
7-
88
pub trait AddCommand {
99
fn add_command(&mut self, command: impl Command);
1010
}
@@ -93,7 +93,7 @@ macro_rules! impl_fallible_commands {
9393
{
9494
pub fn on_failure<'this, H>(&'this mut self, error_handler: H) -> $returnty
9595
where
96-
H: FnOnce(CommandError<'_, C>) + Send + Sync + 'static,
96+
H: System<In = CommandError<C>, Out = ()>,
9797
{
9898
let command = self.command.take().unwrap();
9999
self.inner.add_command(FallibleCommandWrapper {
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
use super::Command;
2-
use crate::world::World;
1+
use super::{Command, CommandArgs};
2+
use crate::system::System;
33
use bevy_utils::tracing::error;
4-
use std::fmt::Debug;
4+
use std::{borrow::Cow, fmt::Debug};
55

6-
pub struct CommandError<'a, C: FallibleCommand> {
6+
pub struct CommandError<C: FallibleCommand> {
77
pub error: C::Error,
8-
pub world: &'a mut World,
8+
pub system_name: Cow<'static, str>,
99
}
1010

1111
pub trait FallibleCommand: Send + Sync + 'static {
1212
type Error;
1313

14-
fn try_write(self, world: &mut World) -> Result<(), Self::Error>;
14+
fn try_write(self, args: CommandArgs) -> Result<(), Self::Error>;
1515
}
1616

1717
pub trait InfallibleCommand: Send + Sync + 'static {
18-
fn write(self, world: &mut World);
18+
fn write(self, args: CommandArgs);
1919
}
2020

2121
pub(crate) struct IgnoreFallibleCommandWrapper<C: FallibleCommand>(pub(crate) C);
@@ -24,8 +24,8 @@ impl<C> Command for IgnoreFallibleCommandWrapper<C>
2424
where
2525
C: FallibleCommand,
2626
{
27-
fn write(self: Box<Self>, world: &mut World) {
28-
let _ = self.0.try_write(world);
27+
fn write(self: Box<Self>, args: CommandArgs) {
28+
let _ = self.0.try_write(args);
2929
}
3030
}
3131

@@ -36,9 +36,13 @@ where
3636
C: FallibleCommand,
3737
C::Error: Debug,
3838
{
39-
fn write(self: Box<Self>, world: &mut World) {
40-
if let Err(err) = self.0.try_write(world) {
41-
error!("Commands failed with error: {:?}", err);
39+
fn write(self: Box<Self>, args: CommandArgs) {
40+
let CommandArgs { world, system_name } = args;
41+
if let Err(err) = self.0.try_write(CommandArgs { world, system_name }) {
42+
error!(
43+
"Commands failed with error: `{:?}` in system `{}`",
44+
err, system_name
45+
);
4246
}
4347
}
4448
}
@@ -50,17 +54,21 @@ where
5054
C: FallibleCommand,
5155
C::Error: Debug,
5256
{
53-
fn write(self: Box<Self>, world: &mut World) {
54-
if let Err(err) = self.0.try_write(world) {
55-
panic!("Commands failed with error: {:?}", err);
57+
fn write(self: Box<Self>, args: CommandArgs) {
58+
let CommandArgs { world, system_name } = args;
59+
if let Err(err) = self.0.try_write(CommandArgs { world, system_name }) {
60+
error!(
61+
"Commands failed with error: `{:?}` in system `{}`",
62+
err, system_name
63+
);
5664
}
5765
}
5866
}
5967

6068
pub(crate) struct FallibleCommandWrapper<C, E>
6169
where
6270
C: FallibleCommand,
63-
E: FnOnce(CommandError<'_, C>) + Send + Sync + 'static,
71+
E: System<In = CommandError<C>, Out = ()>,
6472
{
6573
pub(crate) command: C,
6674
pub(crate) error_handler: E,
@@ -69,16 +77,28 @@ where
6977
impl<C, E> Command for FallibleCommandWrapper<C, E>
7078
where
7179
C: FallibleCommand,
72-
E: FnOnce(CommandError<'_, C>) + Send + Sync + 'static,
80+
E: System<In = CommandError<C>, Out = ()>,
7381
{
74-
fn write(self: Box<Self>, world: &mut World) {
82+
fn write(self: Box<Self>, args: CommandArgs) {
7583
let FallibleCommandWrapper {
7684
command,
77-
error_handler,
85+
mut error_handler,
7886
} = *self;
7987

80-
if let Err(error) = command.try_write(world) {
81-
(error_handler)(CommandError { error, world });
88+
let CommandArgs {
89+
mut world,
90+
system_name,
91+
} = args;
92+
93+
if let Err(error) = command.try_write(CommandArgs { world, system_name }) {
94+
error_handler.initialize(&mut world);
95+
error_handler.run(
96+
CommandError {
97+
error,
98+
system_name: system_name.clone(),
99+
},
100+
&mut world,
101+
);
82102
}
83103
}
84104
}
@@ -94,7 +114,7 @@ impl<C> Command for InfallibleCommandWrapper<C>
94114
where
95115
C: InfallibleCommand,
96116
{
97-
fn write(self: Box<Self>, world: &mut World) {
98-
self.command.write(world);
117+
fn write(self: Box<Self>, args: CommandArgs) {
118+
self.command.write(args);
99119
}
100120
}

crates/bevy_ecs/src/system/commands/mod.rs

+41-26
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,28 @@ use crate::{
88
world::World,
99
};
1010
use fallible::*;
11-
use std::{fmt::Debug, marker::PhantomData};
11+
use std::{borrow::Cow, fmt::Debug, marker::PhantomData};
1212

1313
pub use config::*;
1414
pub use fallible::{FallibleCommand, InfallibleCommand};
1515

16+
pub struct CommandArgs<'a> {
17+
pub world: &'a mut World,
18+
pub system_name: &'a Cow<'static, str>,
19+
}
20+
21+
// IMPL DerefMut<Target = World> for CommandArgs to help with breaking backwards compatilibilty?
22+
1623
/// A [`World`] mutation.
1724
pub trait Command: Send + Sync + 'static {
18-
fn write(self: Box<Self>, world: &mut World);
25+
fn write(self: Box<Self>, args: CommandArgs);
1926
}
2027

2128
/// A queue of [`Command`]s.
2229
#[derive(Default)]
2330
pub struct CommandQueue {
24-
commands: Vec<Box<dyn Command>>,
31+
pub(crate) commands: Vec<Box<dyn Command>>,
32+
pub(crate) system_name: Cow<'static, str>,
2533
}
2634

2735
impl CommandQueue {
@@ -30,7 +38,10 @@ impl CommandQueue {
3038
pub fn apply(&mut self, world: &mut World) {
3139
world.flush();
3240
for command in self.commands.drain(..) {
33-
command.write(world);
41+
command.write(CommandArgs {
42+
world,
43+
system_name: &self.system_name,
44+
});
3445
}
3546
}
3647

@@ -336,8 +347,8 @@ impl<T> InfallibleCommand for Spawn<T>
336347
where
337348
T: Bundle,
338349
{
339-
fn write(self, world: &mut World) {
340-
world.spawn().insert_bundle(self.bundle);
350+
fn write(self, args: CommandArgs) {
351+
args.world.spawn().insert_bundle(self.bundle);
341352
}
342353
}
343354

@@ -354,8 +365,8 @@ where
354365
I: IntoIterator + Send + Sync + 'static,
355366
I::Item: Bundle,
356367
{
357-
fn write(self, world: &mut World) {
358-
world.spawn_batch(self.bundles_iter);
368+
fn write(self, args: CommandArgs) {
369+
args.world.spawn_batch(self.bundles_iter);
359370
}
360371
}
361372

@@ -372,8 +383,8 @@ pub struct DespawnError {
372383
impl FallibleCommand for Despawn {
373384
type Error = DespawnError;
374385

375-
fn try_write(self, world: &mut World) -> Result<(), Self::Error> {
376-
if world.despawn(self.entity) {
386+
fn try_write(self, args: CommandArgs) -> Result<(), Self::Error> {
387+
if args.world.despawn(self.entity) {
377388
Ok(())
378389
} else {
379390
Err(DespawnError {
@@ -408,8 +419,8 @@ where
408419
{
409420
type Error = InsertBundleError<T>;
410421

411-
fn try_write(self, world: &mut World) -> Result<(), Self::Error> {
412-
if let Some(mut entity_mut) = world.get_entity_mut(self.entity) {
422+
fn try_write(self, args: CommandArgs) -> Result<(), Self::Error> {
423+
if let Some(mut entity_mut) = args.world.get_entity_mut(self.entity) {
413424
entity_mut.insert_bundle(self.bundle);
414425
Ok(())
415426
} else {
@@ -447,8 +458,8 @@ where
447458
{
448459
type Error = InsertError<T>;
449460

450-
fn try_write(self, world: &mut World) -> Result<(), Self::Error> {
451-
match world.get_entity_mut(self.entity) {
461+
fn try_write(self, args: CommandArgs) -> Result<(), Self::Error> {
462+
match args.world.get_entity_mut(self.entity) {
452463
Some(mut entity) => {
453464
entity.insert(self.component);
454465
Ok(())
@@ -487,8 +498,8 @@ where
487498
{
488499
type Error = RemoveError<T>;
489500

490-
fn try_write(self, world: &mut World) -> Result<(), Self::Error> {
491-
if let Some(mut entity_mut) = world.get_entity_mut(self.entity) {
501+
fn try_write(self, args: CommandArgs) -> Result<(), Self::Error> {
502+
if let Some(mut entity_mut) = args.world.get_entity_mut(self.entity) {
492503
entity_mut.remove::<T>();
493504
Ok(())
494505
} else {
@@ -526,8 +537,8 @@ where
526537
{
527538
type Error = RemoveBundleError<T>;
528539

529-
fn try_write(self, world: &mut World) -> Result<(), Self::Error> {
530-
if let Some(mut entity_mut) = world.get_entity_mut(self.entity) {
540+
fn try_write(self, args: CommandArgs) -> Result<(), Self::Error> {
541+
if let Some(mut entity_mut) = args.world.get_entity_mut(self.entity) {
531542
// remove intersection to gracefully handle components that were removed before running
532543
// this command
533544
entity_mut.remove_bundle_intersection::<T>();
@@ -546,8 +557,8 @@ pub struct InsertResource<T: Component> {
546557
}
547558

548559
impl<T: Component> InfallibleCommand for InsertResource<T> {
549-
fn write(self, world: &mut World) {
550-
world.insert_resource(self.resource);
560+
fn write(self, args: CommandArgs) {
561+
args.world.insert_resource(self.resource);
551562
}
552563
}
553564

@@ -570,8 +581,8 @@ impl<T> Debug for RemoveResourceError<T> {
570581
impl<T: Component> FallibleCommand for RemoveResource<T> {
571582
type Error = RemoveResourceError<T>;
572583

573-
fn try_write(self, world: &mut World) -> Result<(), Self::Error> {
574-
if world.remove_resource::<T>().is_some() {
584+
fn try_write(self, args: CommandArgs) -> Result<(), Self::Error> {
585+
if args.world.remove_resource::<T>().is_some() {
575586
Ok(())
576587
} else {
577588
Err(RemoveResourceError {
@@ -584,10 +595,11 @@ impl<T: Component> FallibleCommand for RemoveResource<T> {
584595
#[cfg(test)]
585596
#[allow(clippy::float_cmp, clippy::approx_constant)]
586597
mod tests {
598+
use super::{CommandError, Despawn};
587599
use crate::{
588600
component::{ComponentDescriptor, StorageType},
589601
entity::Entity,
590-
system::{CommandQueue, Commands},
602+
system::{CommandQueue, Commands, In, IntoSystem},
591603
world::World,
592604
};
593605
use std::sync::{
@@ -731,9 +743,12 @@ mod tests {
731743

732744
let mut try_despawn = |e| {
733745
let invoked_clone = invoked.clone();
734-
commands.entity(e).despawn().on_failure(move |_| {
735-
invoked_clone.fetch_add(1, Ordering::Relaxed);
736-
});
746+
commands.entity(e).despawn().on_failure(
747+
Box::new(move |_: In<CommandError<Despawn>>| {
748+
invoked_clone.fetch_add(1, Ordering::Relaxed);
749+
})
750+
.system(),
751+
);
737752
};
738753

739754
try_despawn(invalid_entity);

crates/bevy_ecs/src/system/system_param.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -529,8 +529,11 @@ impl<'a> SystemParam for Commands<'a> {
529529
unsafe impl SystemParamState for CommandQueue {
530530
type Config = ();
531531

532-
fn init(_world: &mut World, _system_state: &mut SystemState, _config: Self::Config) -> Self {
533-
Default::default()
532+
fn init(_world: &mut World, system_state: &mut SystemState, _config: Self::Config) -> Self {
533+
Self {
534+
commands: vec![],
535+
system_name: system_state.name.clone(),
536+
}
534537
}
535538

536539
fn apply(&mut self, world: &mut World) {

0 commit comments

Comments
 (0)