Skip to content

Commit fde7361

Browse files
committed
Updated attribute for release opt-in warnings and debug opt-out warnings
Warnings are enabled for all events in debug mode only by default.
1 parent e84ec4b commit fde7361

File tree

2 files changed

+64
-15
lines changed

2 files changed

+64
-15
lines changed

crates/bevy_ecs/macros/src/event.rs

+43-10
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use bevy_macro_utils::Symbol;
1+
use bevy_macro_utils::{get_lit_str, Symbol};
22
use proc_macro::TokenStream;
33
use quote::{quote, ToTokens};
44
use syn::{parse_macro_input, parse_quote, DeriveInput, Error, Path, Result};
@@ -17,39 +17,72 @@ pub fn derive_event(input: TokenStream) -> TokenStream {
1717
Err(e) => return e.into_compile_error().into(),
1818
};
1919

20-
let warn_missed = attrs.warn_missed;
20+
let missed = attrs.missed;
21+
22+
let warn_missed = match missed {
23+
Missed::Ignore => quote! { const WARN_MISSED: bool = false; },
24+
Missed::DebugWarn => quote! {
25+
#[cfg(debug_assertions)]
26+
const WARN_MISSED: bool = true;
27+
#[cfg(not(debug_assertions))]
28+
const WARN_MISSED: bool = false;
29+
},
30+
Missed::Warn => quote! { const WARN_MISSED:bool = true; },
31+
};
2132

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

2536
TokenStream::from(quote! {
2637
impl #impl_generics #bevy_ecs_path::event::Event for #struct_name #type_generics #where_clause {
27-
const WARN_MISSED: bool = #warn_missed;
38+
#warn_missed
2839
}
2940
})
3041
}
3142

3243
struct Attrs {
33-
warn_missed: bool,
44+
missed: Missed,
45+
}
46+
47+
enum Missed {
48+
Ignore,
49+
DebugWarn,
50+
Warn,
3451
}
3552

3653
pub const EVENT: Symbol = Symbol("event");
37-
pub const WARN_MISSED: &str = "warn_missed";
54+
pub const MISSED: Symbol = Symbol("missed");
55+
56+
const IGNORE: &str = "ignore";
57+
const DEBUG_WARN: &str = "debug_warn";
58+
const WARN: &str = "warn";
3859

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

42-
let mut attrs = Attrs { warn_missed: false };
63+
let mut attrs = Attrs {
64+
missed: Missed::DebugWarn,
65+
};
4366

4467
for meta in meta_items {
4568
use syn::{
46-
Meta::Path,
69+
Meta::NameValue,
4770
NestedMeta::{Lit, Meta},
4871
};
4972
match meta {
50-
Meta(Path(m)) => {
51-
if m.is_ident(WARN_MISSED) {
52-
attrs.warn_missed = true;
73+
Meta(NameValue(m)) if m.path == MISSED => {
74+
attrs.missed = match get_lit_str(MISSED, &m.lit)?.value().as_str() {
75+
IGNORE => Missed::Ignore,
76+
DEBUG_WARN => Missed::DebugWarn,
77+
WARN => Missed::Warn,
78+
e => {
79+
return Err(Error::new_spanned(
80+
m.lit,
81+
format!(
82+
"Invalid missed event behaviour `{e}`, expected '{IGNORE}', '{DEBUG_WARN}', or '{WARN}'.",
83+
),
84+
))
85+
}
5386
}
5487
}
5588
Meta(meta_item) => {

crates/bevy_ecs/src/event.rs

+21-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ use std::{fmt, hash::Hash, iter::Chain, marker::PhantomData, slice::Iter};
1212
/// Events must be thread-safe.
1313
pub trait Event: Send + Sync + 'static {
1414
/// Whether a warning is emitted if an event is sent but never read
15+
#[cfg(debug_assertions)]
16+
const WARN_MISSED: bool = true;
17+
#[cfg(not(debug_assertions))]
1518
const WARN_MISSED: bool = false;
1619
}
1720

@@ -130,13 +133,26 @@ struct EventInstance<E: Event> {
130133
/// # Missed events
131134
///
132135
/// Obscure bugs may arise if an [`EventReader`] does not read all events before they are cleared.
133-
/// To emit a warning when this happens, annotate the event with `#[event(warn_missed)]`.
136+
/// By default, a warning will be emitted in debug mode, but will be silently ignored in release mode.
137+
///
138+
/// This behaviour can be overridden with an additional attribute.
134139
/// ```
135140
/// # use bevy_ecs::event::{Event, Events};
136141
/// #
142+
/// // This event will not emit warnings when one is missed.
143+
/// #[derive(Event)]
144+
/// #[event(missed = "ignore")]
145+
/// struct EventA;
146+
///
147+
/// // This event will emit only emit warnings if one is missed in debug mode.
148+
/// #[derive(Event)]
149+
/// #[event(missed = "debug_warn")]
150+
/// struct EventB;
151+
///
152+
/// // This event will always emit warnings when one is missed.
137153
/// #[derive(Event)]
138-
/// #[event(warn_missed)]
139-
/// struct MyEvent;
154+
/// #[event(missed = "warn")]
155+
/// struct EventC;
140156
/// ```
141157
#[derive(Debug, Resource)]
142158
pub struct Events<E: Event> {
@@ -362,9 +378,9 @@ impl<E: Event> ManualEventReader<E> {
362378
// otherwise read all events in the buffer
363379
let missed = self.missed_events(events);
364380
if missed > 0 {
365-
let plural = if missed == 1 { "event" } else { "events" };
381+
let event_noun = if missed == 1 { "event" } else { "events" };
366382
let type_name = std::any::type_name::<E>();
367-
warn!("Missed {missed} `{type_name}` {plural}.");
383+
warn!("Missed {missed} `{type_name}` {event_noun}.");
368384
}
369385
}
370386

0 commit comments

Comments
 (0)