bevy_ecs/error/
command_handling.rs

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