Skip to content

Commit

Permalink
Updated attribute for release opt-in warnings and debug opt-out warnings
Browse files Browse the repository at this point in the history
Warnings are enabled for all events in debug mode only by default.
  • Loading branch information
CatThingy committed Jan 9, 2023
1 parent e84ec4b commit fde7361
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 15 deletions.
53 changes: 43 additions & 10 deletions crates/bevy_ecs/macros/src/event.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use bevy_macro_utils::Symbol;
use bevy_macro_utils::{get_lit_str, Symbol};
use proc_macro::TokenStream;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, parse_quote, DeriveInput, Error, Path, Result};
Expand All @@ -17,39 +17,72 @@ pub fn derive_event(input: TokenStream) -> TokenStream {
Err(e) => return e.into_compile_error().into(),
};

let warn_missed = attrs.warn_missed;
let missed = attrs.missed;

let warn_missed = match missed {
Missed::Ignore => quote! { const WARN_MISSED: bool = false; },
Missed::DebugWarn => quote! {
#[cfg(debug_assertions)]
const WARN_MISSED: bool = true;
#[cfg(not(debug_assertions))]
const WARN_MISSED: bool = false;
},
Missed::Warn => quote! { const WARN_MISSED:bool = true; },
};

let struct_name = &ast.ident;
let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();

TokenStream::from(quote! {
impl #impl_generics #bevy_ecs_path::event::Event for #struct_name #type_generics #where_clause {
const WARN_MISSED: bool = #warn_missed;
#warn_missed
}
})
}

struct Attrs {
warn_missed: bool,
missed: Missed,
}

enum Missed {
Ignore,
DebugWarn,
Warn,
}

pub const EVENT: Symbol = Symbol("event");
pub const WARN_MISSED: &str = "warn_missed";
pub const MISSED: Symbol = Symbol("missed");

const IGNORE: &str = "ignore";
const DEBUG_WARN: &str = "debug_warn";
const WARN: &str = "warn";

fn parse_event_attr(ast: &DeriveInput) -> Result<Attrs> {
let meta_items = bevy_macro_utils::parse_attrs(ast, EVENT)?;

let mut attrs = Attrs { warn_missed: false };
let mut attrs = Attrs {
missed: Missed::DebugWarn,
};

for meta in meta_items {
use syn::{
Meta::Path,
Meta::NameValue,
NestedMeta::{Lit, Meta},
};
match meta {
Meta(Path(m)) => {
if m.is_ident(WARN_MISSED) {
attrs.warn_missed = true;
Meta(NameValue(m)) if m.path == MISSED => {
attrs.missed = match get_lit_str(MISSED, &m.lit)?.value().as_str() {
IGNORE => Missed::Ignore,
DEBUG_WARN => Missed::DebugWarn,
WARN => Missed::Warn,
e => {
return Err(Error::new_spanned(
m.lit,
format!(
"Invalid missed event behaviour `{e}`, expected '{IGNORE}', '{DEBUG_WARN}', or '{WARN}'.",
),
))
}
}
}
Meta(meta_item) => {
Expand Down
26 changes: 21 additions & 5 deletions crates/bevy_ecs/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ use std::{fmt, hash::Hash, iter::Chain, marker::PhantomData, slice::Iter};
/// Events must be thread-safe.
pub trait Event: Send + Sync + 'static {
/// Whether a warning is emitted if an event is sent but never read
#[cfg(debug_assertions)]
const WARN_MISSED: bool = true;
#[cfg(not(debug_assertions))]
const WARN_MISSED: bool = false;
}

Expand Down Expand Up @@ -130,13 +133,26 @@ struct EventInstance<E: Event> {
/// # Missed events
///
/// Obscure bugs may arise if an [`EventReader`] does not read all events before they are cleared.
/// To emit a warning when this happens, annotate the event with `#[event(warn_missed)]`.
/// By default, a warning will be emitted in debug mode, but will be silently ignored in release mode.
///
/// This behaviour can be overridden with an additional attribute.
/// ```
/// # use bevy_ecs::event::{Event, Events};
/// #
/// // This event will not emit warnings when one is missed.
/// #[derive(Event)]
/// #[event(missed = "ignore")]
/// struct EventA;
///
/// // This event will emit only emit warnings if one is missed in debug mode.
/// #[derive(Event)]
/// #[event(missed = "debug_warn")]
/// struct EventB;
///
/// // This event will always emit warnings when one is missed.
/// #[derive(Event)]
/// #[event(warn_missed)]
/// struct MyEvent;
/// #[event(missed = "warn")]
/// struct EventC;
/// ```
#[derive(Debug, Resource)]
pub struct Events<E: Event> {
Expand Down Expand Up @@ -362,9 +378,9 @@ impl<E: Event> ManualEventReader<E> {
// otherwise read all events in the buffer
let missed = self.missed_events(events);
if missed > 0 {
let plural = if missed == 1 { "event" } else { "events" };
let event_noun = if missed == 1 { "event" } else { "events" };
let type_name = std::any::type_name::<E>();
warn!("Missed {missed} `{type_name}` {plural}.");
warn!("Missed {missed} `{type_name}` {event_noun}.");
}
}

Expand Down

0 comments on commit fde7361

Please sign in to comment.