Skip to content

Commit

Permalink
Add exclusive_sysfail
Browse files Browse the repository at this point in the history
  • Loading branch information
nicopap committed Dec 6, 2023
1 parent 0717d6a commit 2fa5078
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 9 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Major **Breaking** release.
- Added example showing how to extend with your own behavior the `Failure` trait.
- Added the system name to the log message's "target" field (by default, this is
the bit of text before the "ERROR" colored text)
- Added `#[exclusive_sysfail]`, works like `#[sysfail]` but is fully supported
by exclusive systems. It only supports `Failure`s where `Param = ()`

# `4.1.0`

Expand Down
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ CLIPPY_ARGS=-- -D clippy::all -D clippy::pedantic -D clippy::nursery \

check:
cargo check --examples

run:
cargo run --example custom_failure
cargo run --example all_attributes

pre-hook:
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps
cargo clippy --workspace $(CLIPPY_ARGS)
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,12 @@ fn quit_app_on_error() { /* ... */ }
fn do_not_care_about_failure() { /* ... */ }
```

### Exclusive systems

For exclusive systems, use the `#[exclusive_sysfail]` macro. Note that only
`Failure<Param = ()>` work with exclusive systems. This excludes `Log`, so
make sure to use `LogSimply` instead.

### Custom handling

`bevy_mod_sysfail` is not limited to the predefined set of `Failure`s, you can
Expand Down
15 changes: 14 additions & 1 deletion examples/all_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ impl Dedup for GizmoError {
fn main() {
let mut app = App::new();
app.add_plugins((MinimalPlugins, bevy::log::LogPlugin::default()))
.add_systems(Update, (drag_gizmo, (delete_gizmo, place_gizmo)).chain());
.add_systems(
Update,
(drag_gizmo, exclusive_system, (delete_gizmo, place_gizmo)).chain(),
);
app.update();
app.update();
}

Expand All @@ -40,6 +44,15 @@ fn place_gizmo() {
let _ = Err("Ah, some creative use of info logging I see")?;
}

#[exclusive_sysfail(LogSimply<anyhow::Error, Error>)]
fn exclusive_system(_: &mut World, mut has_printed: Local<bool>) {
if *has_printed {
return Ok(());
}
*has_printed = true;
let _ = Err(anyhow::anyhow!("We simply logged this error"))?;
}

/// This also has some doc
#[sysfail(Ignore)]
fn delete_gizmo(time: Res<Time>, mut query: Query<&mut Transform>, foos: Query<Entity, With<Foo>>) {
Expand Down
21 changes: 16 additions & 5 deletions macros_impl/src/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ use syn::parse_quote;

pub struct FnConfig {
pub error_type: syn::Type,
pub exclusive: bool,
}
impl FnConfig {
pub fn new() -> Self {
Self {
error_type: parse_quote![
::bevy_mod_sysfail::prelude::Log<::std::boxed::Box<dyn ::std::error::Error>>
],
exclusive: false,
}
}
}
Expand Down Expand Up @@ -67,20 +69,29 @@ fn sysfail_inner(config: &FnConfig, mut function: syn::ItemFn) -> syn::Result<To
} else {
quote!(None)
};
let extra_param = (!config.exclusive) .then(||
quote!(__sysfail_params: #prefix::StaticSystemParam<<#ret_type as #prefix::Failure>::Param>)
);
let check_exclusive = if config.exclusive {
quote! {
fn Failure_has_UnitParam<F: Failure<Param=()>>() -> F::Param {}
let param_items = Failure_has_UnitParam::<#ret_type>();
}
} else {
quote!(let param_items = __sysfail_params.into_inner();)
};
Ok(quote! {
#(#attrs)*
#vis fn #fn_ident <#params_gen> (
#params
__sysfail_params: #prefix::StaticSystemParam<<#ret_type as #prefix::Failure>::Param>
) #where_gen {
#vis fn #fn_ident <#params_gen> (#params #extra_param) #where_gen {
use ::bevy_mod_sysfail::Failure;
let mut inner_system = move || -> ::core::result::Result<(), #ret_type> {
#(#body)*;
return ::core::result::Result::Ok(());
};
if let Err(err) = inner_system() {
static CALLSITE: Option<#prefix::DefaultCallsite> = #callsite;
err.handle_error(__sysfail_params.into_inner(), CALLSITE.as_ref());
#check_exclusive
err.handle_error(param_items, CALLSITE.as_ref());
}
}
})
Expand Down
14 changes: 14 additions & 0 deletions macros_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ mod generate;

/// `sysfail` is an attribute macro you can slap on top of your systems to define
/// the handling of errors.
///
/// See [`macro@exclusive_sysfail`] for **exclusive systems** handling.
#[proc_macro_attribute]
pub fn sysfail(attrs: TokenStream1, input: TokenStream1) -> TokenStream1 {
let mut config = generate::FnConfig::new();
Expand All @@ -16,3 +18,15 @@ pub fn sysfail(attrs: TokenStream1, input: TokenStream1) -> TokenStream1 {
let input = parse_macro_input!(input as syn::ItemFn);
generate::sysfail(&config, input).into()
}
/// Similar to [`macro@sysfail`] but allows usage on **exclusive systems**.
#[proc_macro_attribute]
pub fn exclusive_sysfail(attrs: TokenStream1, input: TokenStream1) -> TokenStream1 {
let mut config = generate::FnConfig::new();
config.exclusive = true;

if !attrs.is_empty() {
config.error_type = parse_macro_input!(attrs as syn::Type);
}
let input = parse_macro_input!(input as syn::ItemFn);
generate::sysfail(&config, input).into()
}
6 changes: 4 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ use bevy_ecs::system::SystemParam;

/// See the [`crate`]-level documentation for usage and examples.
pub use bevy_mod_sysfail_macros::sysfail;

/// See the [`crate`]-level documentation for usage and examples.
pub use bevy_mod_sysfail_macros::exclusive_sysfail;
pub use bevy_utils::tracing::{Callsite, Level};
pub use dedup::Dedup;
pub use log_levels::LogLevelModifier;
Expand All @@ -35,8 +38,7 @@ pub mod prelude {
pub use crate::log::Log;
pub use crate::log_levels::{Debug, Error, Info, Trace, Warn};
pub use crate::log_simple::LogSimply;
pub use crate::sysfail;
pub use crate::Failure;
pub use crate::{exclusive_sysfail, sysfail, Failure};
}

/// Symbols for the `sysfail` attribute macro.
Expand Down

0 comments on commit 2fa5078

Please sign in to comment.