#error #bevy #macro #traits #error-logging #log-error #debugging

bevy_mod_sysfail

使用sysfail宏属性装饰你的bevy系统以处理失败

10个版本 (主要破坏)

7.0.0 2024年2月18日
6.0.0 2024年1月29日
5.0.0 2023年11月4日
4.3.0 2023年10月13日
0.1.0 2022年9月7日

#42 in 游戏开发

Download history • Rust 包仓库 178/week @ 2024-03-11 • Rust 包仓库 144/week @ 2024-03-18 • Rust 包仓库 96/week @ 2024-03-25 • Rust 包仓库 205/week @ 2024-04-01 • Rust 包仓库 100/week @ 2024-04-08 • Rust 包仓库 147/week @ 2024-04-15 • Rust 包仓库 194/week @ 2024-04-22 • Rust 包仓库 129/week @ 2024-04-29 • Rust 包仓库 105/week @ 2024-05-06 • Rust 包仓库 133/week @ 2024-05-13 • Rust 包仓库 206/week @ 2024-05-20 • Rust 包仓库 131/week @ 2024-05-27 • Rust 包仓库 180/week @ 2024-06-03 • Rust 包仓库 186/week @ 2024-06-10 • Rust 包仓库 166/week @ 2024-06-17 • Rust 包仓库 201/week @ 2024-06-24 • Rust 包仓库

每月下载量755
用于9库(8 直接)

Apache-2.0

39KB
184

Bevy系统错误处理

Bevy tracking Latest version Apache 2.0 Documentation

使用sysfail宏属性装饰你的bevy系统以处理失败。

之前

use bevy::prelude::*;
use bevy::utils::Duration;

use thiserror::Error;

#[derive(Error, Debug)]
enum GizmoError {
    #[error("A Gizmo error")]
    Error,
}

#[derive(Debug, PartialEq, Eq, Hash, SystemSet, Clone)]
enum TransformGizmoSystem { Drag, Place }

fn main() {
    let mut app = App::new();
    app.add_plugins(bevy::time::TimePlugin)
        .add_systems(Update, (
            drag_gizmo
                .pipe(print_gizmo_error)
                .in_set(TransformGizmoSystem::Drag),
            delete_gizmo
                .pipe(|In(_)| {})
                .after(TransformGizmoSystem::Place),
            place_gizmo
                .pipe(print_gizmo_error)
                .in_set(TransformGizmoSystem::Place)
                .after(TransformGizmoSystem::Drag),
        ));
    app.update();
}

fn print_gizmo_error(
    In(result): In<Result<(), Box<dyn std::error::Error>>>,
    mut last_error_occurence: Local<Option<Duration>>,
    time: Res<Time>,
) {
  // error boilerplate, may include
  // - avoiding printing multiple times the same error
  // - Formatting and chosing the log level
}

fn drag_gizmo(time: Res<Time>) -> Result<(), Box<dyn std::error::Error>> {
    println!("drag time is: {}", time.elapsed_seconds());
    let _ = Err(GizmoError::Error)?;
    println!("This will never print");
    Ok(())
}

fn place_gizmo() -> Result<(), Box<dyn std::error::Error>> {
    let () = Result::<(), &'static str>::Ok(())?;
    println!("this line should actually show up");
    let _ = Err("Ah, some creative use of info logging I see")?;
    Ok(())
}

fn delete_gizmo(time: Res<Time>) -> Option<()> {
    println!("delete time is: {}", time.elapsed_seconds());
    let _ = None?;
    println!("This will never print");
    Some(())
}

之后

use bevy::prelude::*;
use bevy_mod_sysfail::prelude::*;

use thiserror::Error;

#[derive(Error, Debug)]
enum GizmoError {
    #[error("A Gizmo error")]
    Error,
}

fn main() {
    let mut app = App::new();
    app.add_plugins(bevy::time::TimePlugin)
        .add_systems(Update, (
            drag_gizmo,
            delete_gizmo.after(place_gizmo),
            place_gizmo.after(drag_gizmo)
        ));
    app.update();
}

#[sysfail]
fn drag_gizmo(time: Res<Time>) {
    println!("drag time is: {}", time.elapsed_seconds());
    let _ = Err(GizmoError::Error)?;
    println!("This will never print");
}

#[sysfail(Log<&'static str, Info>)]
fn place_gizmo() {
    let () = Result::<(), &'static str>::Ok(())?;
    println!("this line should actually show up");
    let _ = Err("Ah, some creative use of info logging I see")?;
}

#[sysfail(Ignore)]
fn delete_gizmo(time: Res<Time>) {
    println!("delete time is: {}", time.elapsed_seconds());
    let _ = Err(342_i32)?;
    println!("This will never print");
}

sysfail属性

sysfail是一个属性宏,可以应用于系统以定义错误处理。与pipe不同,这直接在定义位置进行,而不是在添加到应用时进行。因此,可以一目了然地看到系统中正在发生什么类型的错误处理,它还允许使用系统名称作为系统依赖指定中的标签。

sysfail(E)系统返回类型为Result<(), E>的值。返回类型由宏添加,因此不要自己添加!

E是实现了Failure特质的类型。bevy_mod_sysfail导出了一些实现了Failure的类型

  • Log<Err, Lvl = Warn>:将Err记录到跟踪日志器。
    • 第一种类型参数 Err 实现了 Dedup 特性。您可以为自定义类型实现 Dedup,但您始终可以使用已实现 Dedup 的类型,如 anyhow::ErrorBox<dyn std::error::Error>&'static str
    • 第二种类型参数指定了日志级别。它是可选的,默认为 Warn
  • LogSimply:与 Log 类似,但没有去重。
  • Emit<Ev>:当系统返回 Err 时,会发出 Ev bevy Event
  • Ignore:忽略错误,就像什么都没发生一样。

示例用法

use bevy::prelude::*;
use bevy_mod_sysfail::prelude::*;
use thiserror::Error;

// -- Log a value --

#[derive(Error, Debug)]
enum MyCustomError {
    #[error("A Custom error")]
    Error,
}

// Equivalent to #[sysfail(Log<Box<dyn std::error::Error>>)]
#[sysfail]
fn generic_failure() { /* ... */ }

#[sysfail(Log<&'static str>)]
fn log_a_str_message() {
    let _ = Err("Yep, just like that")?;
}

#[sysfail(Log<anyhow::Error>)]
fn log_an_anyhow_error() {
    let _ = Err(MyCustomError::Error)?;
}

#[sysfail(LogSimply<MyCustomError, Trace>)]
fn log_trace_on_failure() { /* ... */ }

#[sysfail(LogSimply<MyCustomError, Error>)]
fn log_error_on_failure() { /* ... */ }

// -- Emit an event --
use bevy::app::AppExit;

#[derive(Event)]
enum ChangeMenu {
    Main,
    Tools,
}

#[sysfail(Emit<ChangeMenu>)]
fn change_menu() { /* ... */ }

#[sysfail(Emit<AppExit>)]
fn quit_app_on_error() { /* ... */ }

// -- Ignore all errors --

#[sysfail(Ignore)]
fn do_not_care_about_failure() { /* ... */ }

独占系统

对于独占系统,使用 #[exclusive_sysfail] 宏。请注意,只有 Failure<Param = ()> 与独占系统一起工作。这排除了 Log,所以请确保使用 LogSimply

自定义处理

bevy_mod_sysfail 不仅限于预定义的 Failure 集合,您可以通过自行实现来自定义。请参阅 自定义错误示例

变更日志

请参阅 变更日志

版本矩阵

bevy 最新支持版本
0.13 7.0.0
0.12 6.0.0
0.11 4.3.0
0.10 2.0.0
0.9 1.1.0
0.8 0.1.0

许可证

版权所有 © 2022 Nicola Papale

本软件根据 Apache 2.0 许可证授权。

依赖关系

~8–36MB
~533K SLoC