{"id":15023212,"url":"https://github.com/nicopap/bevy_mod_sysfail","last_synced_at":"2025-10-13T06:31:49.894Z","repository":{"id":58809530,"uuid":"533908976","full_name":"nicopap/bevy_mod_sysfail","owner":"nicopap","description":"Decorate your bevy system with the sysfail macro attribute to make them handle cleanly failure mods.","archived":false,"fork":false,"pushed_at":"2024-07-30T19:56:44.000Z","size":89,"stargazers_count":25,"open_issues_count":3,"forks_count":7,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-22T13:08:47.202Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nicopap.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["nicopap"]}},"created_at":"2022-09-07T19:21:51.000Z","updated_at":"2024-11-15T14:41:55.000Z","dependencies_parsed_at":"2023-10-13T17:58:51.822Z","dependency_job_id":"ce273111-6fde-4c1f-80db-b0149d130770","html_url":"https://github.com/nicopap/bevy_mod_sysfail","commit_stats":{"total_commits":29,"total_committers":1,"mean_commits":29.0,"dds":0.0,"last_synced_commit":"d65f72a848385a4f19369d3f009d601371aa1b7e"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicopap%2Fbevy_mod_sysfail","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicopap%2Fbevy_mod_sysfail/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicopap%2Fbevy_mod_sysfail/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicopap%2Fbevy_mod_sysfail/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nicopap","download_url":"https://codeload.github.com/nicopap/bevy_mod_sysfail/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":236309837,"owners_count":19128391,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-24T19:58:50.480Z","updated_at":"2025-10-13T06:31:44.574Z","avatar_url":"https://github.com/nicopap.png","language":"Rust","funding_links":["https://github.com/sponsors/nicopap"],"categories":[],"sub_categories":[],"readme":"## Bevy system error handling \n\n[![Bevy tracking](https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue)](https://github.com/bevyengine/bevy/blob/main/docs/plugins_guidelines.md#main-branch-tracking)\n[![Latest version](https://img.shields.io/crates/v/bevy_mod_sysfail.svg)](https://crates.io/crates/bevy_mod_sysfail)\n[![Apache 2.0](https://img.shields.io/badge/license-Apache-blue.svg)](./LICENSE)\n[![Documentation](https://docs.rs/bevy_mod_sysfail/badge.svg)](https://docs.rs/bevy_mod_sysfail/)\n\nDecorate your bevy system with the [`sysfail`] macro attribute to handle failure.\n\n#### Before\n\n```rust,no_run\nuse bevy::prelude::*;\nuse bevy::utils::Duration;\n\nuse thiserror::Error;\n\n#[derive(Error, Debug)]\nenum GizmoError {\n    #[error(\"A Gizmo error\")]\n    Error,\n}\n\n#[derive(Debug, PartialEq, Eq, Hash, SystemSet, Clone)]\nenum TransformGizmoSystem { Drag, Place }\n\nfn main() {\n    let mut app = App::new();\n    app.add_plugins(bevy::time::TimePlugin)\n        .add_systems(Update, (\n            drag_gizmo\n                .pipe(print_gizmo_error)\n                .in_set(TransformGizmoSystem::Drag),\n            delete_gizmo\n                .pipe(|In(_)| {})\n                .after(TransformGizmoSystem::Place),\n            place_gizmo\n                .pipe(print_gizmo_error)\n                .in_set(TransformGizmoSystem::Place)\n                .after(TransformGizmoSystem::Drag),\n        ));\n    app.update();\n}\n\nfn print_gizmo_error(\n    In(result): In\u003cResult\u003c(), Box\u003cdyn std::error::Error\u003e\u003e\u003e,\n    mut last_error_occurence: Local\u003cOption\u003cDuration\u003e\u003e,\n    time: Res\u003cTime\u003e,\n) {\n  // error boilerplate, may include\n  // - avoiding printing multiple times the same error\n  // - Formatting and chosing the log level\n}\n\nfn drag_gizmo(time: Res\u003cTime\u003e) -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    println!(\"drag time is: {}\", time.elapsed_seconds());\n    let _ = Err(GizmoError::Error)?;\n    println!(\"This will never print\");\n    Ok(())\n}\n\nfn place_gizmo() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let () = Result::\u003c(), \u0026'static str\u003e::Ok(())?;\n    println!(\"this line should actually show up\");\n    let _ = Err(\"Ah, some creative use of info logging I see\")?;\n    Ok(())\n}\n\nfn delete_gizmo(time: Res\u003cTime\u003e) -\u003e Option\u003c()\u003e {\n    println!(\"delete time is: {}\", time.elapsed_seconds());\n    let _ = None?;\n    println!(\"This will never print\");\n    Some(())\n}\n```\n\n#### After\n\n```rust,no_run\nuse bevy::prelude::*;\nuse bevy_mod_sysfail::prelude::*;\n\nuse thiserror::Error;\n\n#[derive(Error, Debug)]\nenum GizmoError {\n    #[error(\"A Gizmo error\")]\n    Error,\n}\n\nfn main() {\n    let mut app = App::new();\n    app.add_plugins(bevy::time::TimePlugin)\n        .add_systems(Update, (\n            drag_gizmo,\n            delete_gizmo.after(place_gizmo),\n            place_gizmo.after(drag_gizmo)\n        ));\n    app.update();\n}\n\n#[sysfail]\nfn drag_gizmo(time: Res\u003cTime\u003e) {\n    println!(\"drag time is: {}\", time.elapsed_seconds());\n    let _ = Err(GizmoError::Error)?;\n    println!(\"This will never print\");\n}\n\n#[sysfail(Log\u003c\u0026'static str, Info\u003e)]\nfn place_gizmo() {\n    let () = Result::\u003c(), \u0026'static str\u003e::Ok(())?;\n    println!(\"this line should actually show up\");\n    let _ = Err(\"Ah, some creative use of info logging I see\")?;\n}\n\n#[sysfail(Ignore)]\nfn delete_gizmo(time: Res\u003cTime\u003e) {\n    println!(\"delete time is: {}\", time.elapsed_seconds());\n    let _ = Err(342_i32)?;\n    println!(\"This will never print\");\n}\n```\n\n### `sysfail` attribute\n\n[`sysfail`] is an attribute macro you can slap on top of your systems to define\nthe handling of errors. Unlike `pipe`, this is done directly at the definition\nsite, and not when adding to the app. As a result, it's easy to see at a glance\nwhat kind of error handling is happening in the system, it also allows using\nthe system name as a label in system dependency specification.\n\n`sysfail(E)` systems return a value of type `Result\u003c(), E\u003e`. The return type\nis added by the macro, so do not add it yourself!\n\n`E` is a type that implements the `Failure` trait. `bevy_mod_sysfail` exports\nseveral types that implement `Failure`:\n\n- [`Log\u003cErr, Lvl = Warn\u003e`][`Log`]: Will log `Err` to the tracing logger.\n   - The first type parameter `Err` implements the [`Dedup`] trait. You can\n     implement `Dedup` for your own types, but you can always use the\n     `anyhow::Error`, `Box\u003cdyn std::error::Error\u003e` and `\u0026'static str` types,\n     as those already implement `Dedup`.\n   - The second type parameter specifies the level of the log. It is optional\n     and by default it is `Warn`\n- [`LogSimply`]: Is similar to `Log`, but without deduplication.\n- [`Emit\u003cEv\u003e`][`Emit`]: Will emit the `Ev` bevy [`Event`] whenever the system returns an `Err`\n- [`Ignore`]: Ignore errors, do as if nothing happened.\n\nExample usages:\n\n```rust\nuse bevy::prelude::*;\nuse bevy_mod_sysfail::prelude::*;\nuse thiserror::Error;\n\n// -- Log a value --\n\n#[derive(Error, Debug)]\nenum MyCustomError {\n    #[error(\"A Custom error\")]\n    Error,\n}\n\n// Equivalent to #[sysfail(Log\u003cBox\u003cdyn std::error::Error\u003e\u003e)]\n#[sysfail]\nfn generic_failure() { /* ... */ }\n\n#[sysfail(Log\u003c\u0026'static str\u003e)]\nfn log_a_str_message() {\n    let _ = Err(\"Yep, just like that\")?;\n}\n\n#[sysfail(Log\u003canyhow::Error\u003e)]\nfn log_an_anyhow_error() {\n    let _ = Err(MyCustomError::Error)?;\n}\n\n#[sysfail(LogSimply\u003cMyCustomError, Trace\u003e)]\nfn log_trace_on_failure() { /* ... */ }\n\n#[sysfail(LogSimply\u003cMyCustomError, Error\u003e)]\nfn log_error_on_failure() { /* ... */ }\n\n// -- Emit an event --\nuse bevy::app::AppExit;\n\n#[derive(Event)]\nenum ChangeMenu {\n    Main,\n    Tools,\n}\n\n#[sysfail(Emit\u003cChangeMenu\u003e)]\nfn change_menu() { /* ... */ }\n\n#[sysfail(Emit\u003cAppExit\u003e)]\nfn quit_app_on_error() { /* ... */ }\n\n// -- Ignore all errors --\n\n#[sysfail(Ignore)]\nfn do_not_care_about_failure() { /* ... */ }\n```\n\n### Exclusive systems\n\nFor exclusive systems, use the `#[exclusive_sysfail]` macro. Note that only\n`Failure\u003cParam = ()\u003e` work with exclusive systems. This excludes `Log`, so\nmake sure to use `LogSimply` instead.\n\n### Custom handling\n\n`bevy_mod_sysfail` is not limited to the predefined set of `Failure`s, you can\ndefine your own by implementing it yourself.\nSee the [custom_failure example] for sample code.\n\n### Change log\n\nSee the [CHANGELOG].\n\n### Version Matrix\n\n| bevy | latest supporting version      |\n|------|--------|\n| 0.13 | 7.0.0 |\n| 0.12 | 6.0.0 |\n| 0.11 | 4.3.0 |\n| 0.10 | 2.0.0 |\n| 0.9  | 1.1.0 |\n| 0.8  | 0.1.0 |\n\n## License\n\nCopyright © 2022 Nicola Papale\n\nThis software is licensed under Apache 2.0.\n\n[CHANGELOG]: https://github.com/nicopap/bevy_mod_sysfail/blob/v7.0.0/CHANGELOG.md\n[custom_failure example]: https://github.com/nicopap/bevy_mod_sysfail/blob/v7.0.0/examples/custom_failure.rs\n[`Dedup`]: https://docs.rs/bevy_mod_sysfail/7.0.0/bevy_mod_sysfail/trait.Dedup.html\n[`Failure`]: https://docs.rs/bevy_mod_sysfail/7.0.0/bevy_mod_sysfail/trait.Failure.html\n[`sysfail`]: https://docs.rs/bevy_mod_sysfail/7.0.0/bevy_mod_sysfail/attr.sysfail.html\n[`Emit`]: https://docs.rs/bevy_mod_sysfail/7.0.0/bevy_mod_sysfail/prelude/struct.Emit.html\n[`Log`]: https://docs.rs/bevy_mod_sysfail/7.0.0/bevy_mod_sysfail/prelude/struct.Log.html\n[`LogSimply`]: https://docs.rs/bevy_mod_sysfail/7.0.0/bevy_mod_sysfail/prelude/struct.LogSimply.html\n[`Ignore`]: https://docs.rs/bevy_mod_sysfail/7.0.0/bevy_mod_sysfail/prelude/struct.Ignore.html\n[`Event`]: https://docs.rs/bevy/0.12/bevy/ecs/event/trait.Event.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicopap%2Fbevy_mod_sysfail","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnicopap%2Fbevy_mod_sysfail","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicopap%2Fbevy_mod_sysfail/lists"}