-
-
Notifications
You must be signed in to change notification settings - Fork 6
/
custom_failure.rs
99 lines (88 loc) · 3.12 KB
/
custom_failure.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/// Define a custom [`Failure`] implementation.
///
/// This uses the [`bevy_debug_text_overlay`] crate to print on screen the text
/// of the error message.
///
/// Note that you would usually use the `screen_print!` macro from `bevy_debug_text_overlay`,
/// but here, we need special handling so that each individual system has its
/// own "slot" in the `bevy_debug_text_overlay` history, but also to display
/// the correct file/line number in the text showing up on screen.
///
/// A `Failure` implementation that doesn't care about the origin of an error
/// doesn't need to care about this though.
use std::fmt;
use std::marker::PhantomData;
use bevy::prelude::*;
use bevy_mod_sysfail::prelude::*;
use bevy_mod_sysfail::{Callsite, Level, LogLevelModifier};
use thiserror::Error;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(bevy_debug_text_overlay::OverlayPlugin { font_size: 23.0, ..default() })
.add_systems(Startup, setup)
.add_systems(Update, (print_generic, print_specialized))
.run();
}
#[derive(Error, Debug)]
enum CustomError {
#[error("A Zoob error")]
Zoob,
#[error("Do the bonzo!")]
Bonzo,
#[error("The Zartrub was located at {0:#?}")]
Zartrub(Transform),
}
pub struct ScreenLog<T, Lvl = Info>(pub T, PhantomData<fn(Lvl)>);
impl<U: From<T>, T: fmt::Debug, L> From<T> for ScreenLog<U, L> {
fn from(t: T) -> Self {
Self(t.into(), PhantomData)
}
}
impl<T: fmt::Display, Lvl: LogLevelModifier> Failure for ScreenLog<T, Lvl> {
type Param = ();
const LEVEL: Level = Lvl::LEVEL;
fn handle_error(self, _: (), callsite: Option<&'static impl Callsite>) {
use bevy_debug_text_overlay::{InvocationSiteKey, COMMAND_CHANNELS};
let metadata = callsite.unwrap().metadata();
let key = InvocationSiteKey {
file: metadata.file().unwrap(),
line: metadata.line().unwrap(),
column: 0,
};
let color = match *metadata.level() {
Level::ERROR => Color::RED,
Level::WARN => Color::ORANGE,
Level::DEBUG => Color::BLUE,
Level::TRACE => Color::PURPLE,
_ => Color::GREEN,
};
COMMAND_CHANNELS.refresh_text(key, || format!("{}", self.0), 1., Some(color));
}
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
}
// Usage:
#[sysfail(ScreenLog<CustomError, Warn>)]
fn print_specialized(time: Res<Time>) {
let delta = time.delta_seconds_f64();
let current_time = time.elapsed_seconds_f64();
let at_interval = |t: f64| current_time % t < delta;
if at_interval(6.) {
let transform = Transform::from_translation(Vec3::splat(current_time as f32));
let _ = Err(CustomError::Zartrub(transform))?;
}
}
#[sysfail(ScreenLog<anyhow::Error>)]
fn print_generic(time: Res<Time>) {
let delta = time.delta_seconds_f64();
let current_time = time.elapsed_seconds_f64();
let at_interval = |t: f64| current_time % t < delta;
if at_interval(3.) {
let _ = Err(CustomError::Zoob)?;
}
if at_interval(5.) {
let _ = Err(CustomError::Bonzo)?;
}
}