Skip to content

Commit ac6f084

Browse files
committed
first pass at command error handling
1 parent 653c103 commit ac6f084

File tree

4 files changed

+503
-62
lines changed

4 files changed

+503
-62
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
use crate::world::World;
2+
use std::{
3+
fmt::Debug,
4+
ops::{Deref, DerefMut},
5+
};
6+
7+
use super::{fallible::*, Command};
8+
9+
pub trait AddCommand {
10+
fn add_command(&mut self, command: impl Command);
11+
}
12+
13+
pub struct FallibleCommandConfig<'a, C, T>
14+
where
15+
C: FallibleCommand,
16+
C::Error: Debug,
17+
T: AddCommand,
18+
{
19+
command: Option<C>,
20+
inner: &'a mut T,
21+
}
22+
23+
impl<'a, C, T> Deref for FallibleCommandConfig<'a, C, T>
24+
where
25+
C: FallibleCommand,
26+
C::Error: Debug,
27+
T: AddCommand,
28+
{
29+
type Target = T;
30+
31+
#[inline]
32+
fn deref(&self) -> &Self::Target {
33+
self.inner
34+
}
35+
}
36+
37+
impl<'a, C, T> DerefMut for FallibleCommandConfig<'a, C, T>
38+
where
39+
C: FallibleCommand,
40+
C::Error: Debug,
41+
T: AddCommand,
42+
{
43+
#[inline]
44+
fn deref_mut(&mut self) -> &mut Self::Target {
45+
self.inner
46+
}
47+
}
48+
49+
/// Similar to [`FallibleCommandConfig`] however does not
50+
/// implement [`DerefMut`] nor return `&mut T` of the underlying
51+
/// Commands type.
52+
pub struct FinalFallibleCommandConfig<'a, C, T>
53+
where
54+
C: FallibleCommand,
55+
C::Error: Debug,
56+
T: AddCommand,
57+
{
58+
command: Option<C>,
59+
inner: &'a mut T,
60+
}
61+
62+
macro_rules! impl_fallible_commands {
63+
($name:ident, $returnty:ty, $func:ident) => {
64+
impl<'a, C, T> $name<'a, C, T>
65+
where
66+
C: FallibleCommand,
67+
C::Error: Debug,
68+
T: AddCommand,
69+
{
70+
#[inline]
71+
pub(crate) fn new(command: C, inner: &'a mut T) -> Self {
72+
Self {
73+
command: Some(command),
74+
inner,
75+
}
76+
}
77+
78+
#[inline]
79+
#[allow(dead_code)]
80+
fn return_inner(&mut self) -> &mut T {
81+
self.inner
82+
}
83+
84+
#[inline]
85+
#[allow(dead_code)]
86+
fn return_unit(&mut self) {}
87+
}
88+
89+
impl<'a, C, T> $name<'a, C, T>
90+
where
91+
C: FallibleCommand,
92+
C::Error: Debug,
93+
T: AddCommand,
94+
{
95+
pub fn on_failure<'this, H>(&'this mut self, error_handler: H) -> $returnty
96+
where
97+
H: FnOnce(C::Error, &mut World) + Send + Sync + 'static,
98+
{
99+
let command = self.command.take().unwrap();
100+
self.inner.add_command(FallibleCommandWrapper {
101+
command,
102+
error_handler,
103+
});
104+
self.$func()
105+
}
106+
107+
pub fn ignore<'this>(&'this mut self) -> $returnty {
108+
let command = self.command.take().unwrap();
109+
self.inner
110+
.add_command(IgnoreFallibleCommandWrapper(command));
111+
self.$func()
112+
}
113+
114+
// this is the default
115+
pub fn log_on_failure<'this>(&'this mut self) -> $returnty {
116+
let command = self.command.take().unwrap();
117+
self.inner
118+
.add_command(LoggingFallibleCommandWrapper(command));
119+
self.$func()
120+
}
121+
122+
pub fn panic_on_failure<'this>(&'this mut self) -> $returnty {
123+
let command = self.command.take().unwrap();
124+
self.inner
125+
.add_command(PanickingFallibleCommandWrapper(command));
126+
self.$func()
127+
}
128+
}
129+
130+
impl<'a, C, T> Drop for $name<'a, C, T>
131+
where
132+
C: FallibleCommand,
133+
C::Error: Debug,
134+
T: AddCommand,
135+
{
136+
fn drop(&mut self) {
137+
if let Some(command) = self.command.take() {
138+
self.inner
139+
.add_command(LoggingFallibleCommandWrapper(command));
140+
}
141+
}
142+
}
143+
};
144+
}
145+
146+
impl_fallible_commands!(FinalFallibleCommandConfig, (), return_unit);
147+
impl_fallible_commands!(FallibleCommandConfig, &mut T, return_inner);
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use super::Command;
2+
use crate::world::World;
3+
use bevy_utils::tracing::error;
4+
use std::fmt::Debug;
5+
6+
pub trait FallibleCommand: Send + Sync + 'static {
7+
type Error;
8+
9+
fn try_write(self, world: &mut World) -> Result<(), Self::Error>;
10+
}
11+
12+
pub trait InfallibleCommand: Send + Sync + 'static {
13+
fn write(self, world: &mut World);
14+
}
15+
16+
pub(crate) struct IgnoreFallibleCommandWrapper<C: FallibleCommand>(pub(crate) C);
17+
18+
impl<C> Command for IgnoreFallibleCommandWrapper<C>
19+
where
20+
C: FallibleCommand,
21+
{
22+
fn write(self: Box<Self>, world: &mut World) {
23+
let _ = self.0.try_write(world);
24+
}
25+
}
26+
27+
pub(crate) struct LoggingFallibleCommandWrapper<C: FallibleCommand>(pub(crate) C);
28+
29+
impl<C> Command for LoggingFallibleCommandWrapper<C>
30+
where
31+
C: FallibleCommand,
32+
C::Error: Debug,
33+
{
34+
fn write(self: Box<Self>, world: &mut World) {
35+
if let Err(err) = self.0.try_write(world) {
36+
error!("Commands failed with error: {:?}", err);
37+
}
38+
}
39+
}
40+
41+
pub(crate) struct PanickingFallibleCommandWrapper<C: FallibleCommand>(pub(crate) C);
42+
43+
impl<C> Command for PanickingFallibleCommandWrapper<C>
44+
where
45+
C: FallibleCommand,
46+
C::Error: Debug,
47+
{
48+
fn write(self: Box<Self>, world: &mut World) {
49+
if let Err(err) = self.0.try_write(world) {
50+
panic!("Commands failed with error: {:?}", err);
51+
}
52+
}
53+
}
54+
55+
pub(crate) struct FallibleCommandWrapper<C, E>
56+
where
57+
C: FallibleCommand,
58+
E: FnOnce(C::Error, &mut World) + Send + Sync + 'static,
59+
{
60+
pub(crate) command: C,
61+
pub(crate) error_handler: E,
62+
}
63+
64+
impl<C, E> Command for FallibleCommandWrapper<C, E>
65+
where
66+
C: FallibleCommand,
67+
E: FnOnce(C::Error, &mut World) + Send + Sync + 'static,
68+
{
69+
fn write(self: Box<Self>, world: &mut World) {
70+
let FallibleCommandWrapper {
71+
command,
72+
error_handler,
73+
} = *self;
74+
75+
if let Err(e) = command.try_write(world) {
76+
(error_handler)(e, world);
77+
}
78+
}
79+
}
80+
81+
pub(crate) struct InfallibleCommandWrapper<C>
82+
where
83+
C: InfallibleCommand,
84+
{
85+
pub(crate) command: C,
86+
}
87+
88+
impl<C> Command for InfallibleCommandWrapper<C>
89+
where
90+
C: InfallibleCommand,
91+
{
92+
fn write(self: Box<Self>, world: &mut World) {
93+
self.command.write(world);
94+
}
95+
}

0 commit comments

Comments
 (0)