@@ -12,9 +12,9 @@ use crate::{
12
12
entity:: Entity ,
13
13
event:: { Event , Events } ,
14
14
observer:: TriggerTargets ,
15
- result:: Result ,
15
+ result:: { Error , Result } ,
16
16
schedule:: ScheduleLabel ,
17
- system:: { CommandError , IntoSystem , Resource , SystemId , SystemInput } ,
17
+ system:: { error_handler , IntoSystem , Resource , SystemId , SystemInput } ,
18
18
world:: { FromWorld , SpawnBatchIter , World } ,
19
19
} ;
20
20
@@ -45,91 +45,57 @@ use crate::{
45
45
/// commands.queue(AddToCounter(42));
46
46
/// }
47
47
/// ```
48
- ///
49
- /// # Note on Generic
50
- ///
51
- /// The `Marker` generic is necessary to allow multiple blanket implementations
52
- /// of `Command` for closures, like so:
53
- /// ```ignore (This would conflict with the real implementations)
54
- /// impl Command for FnOnce(&mut World)
55
- /// impl Command<Result> for FnOnce(&mut World) -> Result
56
- /// ```
57
- /// Without the generic, Rust would consider the two implementations to be conflicting.
58
- ///
59
- /// The type used for `Marker` has no connection to anything else in the implementation.
60
- pub trait Command < Marker = ( ) > : Send + ' static {
48
+ pub trait Command < T = ( ) > : Send + ' static {
61
49
/// Applies this command, causing it to mutate the provided `world`.
62
50
///
63
51
/// This method is used to define what a command "does" when it is ultimately applied.
64
52
/// Because this method takes `self`, you can store data or settings on the type that implements this trait.
65
53
/// This data is set by the system or other source of the command, and then ultimately read in this method.
66
- fn apply ( self , world : & mut World ) -> Result ;
67
-
68
- /// Applies this command and converts any resulting error into a [`CommandError`].
69
- ///
70
- /// Overwriting this method allows an implementor to return a `CommandError` directly
71
- /// and avoid erasing the error's type.
72
- fn apply_internal ( self , world : & mut World ) -> Result < ( ) , CommandError >
73
- where
74
- Self : Sized ,
75
- {
76
- match self . apply ( world) {
77
- Ok ( _) => Ok ( ( ) ) ,
78
- Err ( error) => Err ( CommandError :: CommandFailed ( error) ) ,
79
- }
80
- }
81
-
82
- /// Returns a new [`Command`] that, when applied, will apply the original command
83
- /// and pass any resulting error to the provided `error_handler`.
84
- fn with_error_handling (
85
- self ,
86
- error_handler : Option < fn ( & mut World , CommandError ) > ,
87
- ) -> impl Command
88
- where
89
- Self : Sized ,
90
- {
91
- move |world : & mut World | {
92
- if let Err ( error) = self . apply_internal ( world) {
93
- // TODO: Pass the error to the global error handler if `error_handler` is `None`.
94
- let error_handler = error_handler. unwrap_or ( |_, error| panic ! ( "{error}" ) ) ;
95
- error_handler ( world, error) ;
96
- }
97
- }
98
- }
54
+ fn apply ( self , world : & mut World ) -> T ;
99
55
}
100
56
101
- impl < F > Command for F
57
+ impl < F , T > Command < T > for F
102
58
where
103
- F : FnOnce ( & mut World ) + Send + ' static ,
59
+ F : FnOnce ( & mut World ) -> T + Send + ' static ,
104
60
{
105
- fn apply ( self , world : & mut World ) -> Result {
106
- self ( world) ;
107
- Ok ( ( ) )
61
+ fn apply ( self , world : & mut World ) -> T {
62
+ self ( world)
108
63
}
109
64
}
110
65
111
- impl < F > Command < Result > for F
112
- where
113
- F : FnOnce ( & mut World ) -> Result + Send + ' static ,
114
- {
115
- fn apply ( self , world : & mut World ) -> Result {
116
- self ( world)
66
+ /// Takes a [`Command`] that returns a Result and uses a given error handler function to convert it into
67
+ /// a [`Command`] that internally handles an error if it occurs and returns `()`.
68
+ pub trait HandleError {
69
+ /// Takes a [`Command`] that returns a Result and uses a given error handler function to convert it into
70
+ /// a [`Command`] that internally handles an error if it occurs and returns `()`.
71
+ fn handle_error_with ( self , error_handler : fn ( & mut World , Error ) ) -> impl Command ;
72
+ /// Takes a [`Command`] that returns a Result and uses the default error handler function to convert it into
73
+ /// a [`Command`] that internally handles an error if it occurs and returns `()`.
74
+ fn handle_error ( self ) -> impl Command
75
+ where
76
+ Self : Sized ,
77
+ {
78
+ self . handle_error_with ( error_handler:: default ( ) )
117
79
}
118
80
}
119
81
120
- /// Necessary to avoid erasing the type of the `CommandError` in
121
- /// [`EntityCommand::with_entity`](crate::system::EntityCommand::with_entity).
122
- impl < F > Command < ( Result , CommandError ) > for F
123
- where
124
- F : FnOnce ( & mut World ) -> Result < ( ) , CommandError > + Send + ' static ,
125
- {
126
- fn apply ( self , world : & mut World ) -> Result {
127
- self ( world) ?;
128
- Ok ( ( ) )
82
+ impl < C : Command < Result > > HandleError for C {
83
+ fn handle_error_with ( self , error_handler : fn ( & mut World , Error ) ) -> impl Command {
84
+ move |world : & mut World | match self . apply ( world) {
85
+ Ok ( _) => { }
86
+ Err ( err) => ( error_handler) ( world, err) ,
87
+ }
129
88
}
89
+ }
130
90
131
- fn apply_internal ( self , world : & mut World ) -> Result < ( ) , CommandError > {
132
- self ( world)
91
+ /// Takes a [`Command`] that returns a [`Result`] with an error that can be converted into the [`Error`] type
92
+ /// and returns a [`Command`] that internally converts that error to [`Error`] (if it occurs).
93
+ pub fn map_command_err < T , E : Into < Error > > (
94
+ command : impl Command < Result < T , E > > ,
95
+ ) -> impl Command < Result < T , Error > > {
96
+ move |world : & mut World | match command. apply ( world) {
97
+ Ok ( result) => Ok ( result) ,
98
+ Err ( err) => Err ( err. into ( ) ) ,
133
99
}
134
100
}
135
101
0 commit comments