bevy_ecs/error/
command_handling.rs

1use core::{any::type_name, fmt};
2
3use crate::{
4    entity::Entity,
5    never::Never,
6    system::{entity_command::EntityCommandError, Command, EntityCommand},
7    world::{error::EntityMutableFetchError, World},
8};
9
10use super::{default_error_handler, BevyError, ErrorContext};
11
12/// Takes a [`Command`] that returns a Result and uses a given error handler function to convert it into
13/// a [`Command`] that internally handles an error if it occurs and returns `()`.
14pub trait HandleError<Out = ()> {
15    /// Takes a [`Command`] that returns a Result and uses a given error handler function to convert it into
16    /// a [`Command`] that internally handles an error if it occurs and returns `()`.
17    fn handle_error_with(self, error_handler: fn(BevyError, ErrorContext)) -> impl Command;
18    /// Takes a [`Command`] that returns a Result and uses the default error handler function to convert it into
19    /// a [`Command`] that internally handles an error if it occurs and returns `()`.
20    fn handle_error(self) -> impl Command
21    where
22        Self: Sized,
23    {
24        self.handle_error_with(default_error_handler())
25    }
26}
27
28impl<C, T, E> HandleError<Result<T, E>> for C
29where
30    C: Command<Result<T, E>>,
31    E: Into<BevyError>,
32{
33    fn handle_error_with(self, error_handler: fn(BevyError, ErrorContext)) -> impl Command {
34        move |world: &mut World| match self.apply(world) {
35            Ok(_) => {}
36            Err(err) => (error_handler)(
37                err.into(),
38                ErrorContext::Command {
39                    name: type_name::<C>().into(),
40                },
41            ),
42        }
43    }
44}
45
46impl<C> HandleError<Never> for C
47where
48    C: Command<Never>,
49{
50    fn handle_error_with(self, _error_handler: fn(BevyError, ErrorContext)) -> impl Command {
51        move |world: &mut World| {
52            self.apply(world);
53        }
54    }
55}
56
57impl<C> HandleError for C
58where
59    C: Command,
60{
61    #[inline]
62    fn handle_error_with(self, _error_handler: fn(BevyError, ErrorContext)) -> impl Command {
63        self
64    }
65    #[inline]
66    fn handle_error(self) -> impl Command
67    where
68        Self: Sized,
69    {
70        self
71    }
72}
73
74/// Passes in a specific entity to an [`EntityCommand`], resulting in a [`Command`] that
75/// internally runs the [`EntityCommand`] on that entity.
76///
77// NOTE: This is a separate trait from `EntityCommand` because "result-returning entity commands" and
78// "non-result returning entity commands" require different implementations, so they cannot be automatically
79// implemented. And this isn't the type of implementation that we want to thrust on people implementing
80// EntityCommand.
81pub trait CommandWithEntity<Out> {
82    /// Passes in a specific entity to an [`EntityCommand`], resulting in a [`Command`] that
83    /// internally runs the [`EntityCommand`] on that entity.
84    fn with_entity(self, entity: Entity) -> impl Command<Out> + HandleError<Out>;
85}
86
87impl<C> CommandWithEntity<Result<(), EntityMutableFetchError>> for C
88where
89    C: EntityCommand,
90{
91    fn with_entity(
92        self,
93        entity: Entity,
94    ) -> impl Command<Result<(), EntityMutableFetchError>>
95           + HandleError<Result<(), EntityMutableFetchError>> {
96        move |world: &mut World| -> Result<(), EntityMutableFetchError> {
97            let entity = world.get_entity_mut(entity)?;
98            self.apply(entity);
99            Ok(())
100        }
101    }
102}
103
104impl<C, T, Err> CommandWithEntity<Result<T, EntityCommandError<Err>>> for C
105where
106    C: EntityCommand<Result<T, Err>>,
107    Err: fmt::Debug + fmt::Display + Send + Sync + 'static,
108{
109    fn with_entity(
110        self,
111        entity: Entity,
112    ) -> impl Command<Result<T, EntityCommandError<Err>>> + HandleError<Result<T, EntityCommandError<Err>>>
113    {
114        move |world: &mut World| {
115            let entity = world.get_entity_mut(entity)?;
116            self.apply(entity)
117                .map_err(EntityCommandError::CommandFailed)
118        }
119    }
120}