bevy
bevy copied to clipboard
Ability to undo once! macros
What problem does this solve or what need does it fill?
Currently if you use the once!
macro for logging something once, it will only log once. This is intended behavior.
However, in some cases you may want to undo the once!
condition. For example: If you want to create an error message every time when a condition is first started.
What solution would you like?
Not quite sure honestly, one solution is to add another condition that resets the internal SHOULD_FIRE
variable:
macro_rules! undo_once {
($expression:expr, $condition:expr) => {{
use ::std::sync::atomic::{AtomicBool, Ordering};
static SHOULD_FIRE: AtomicBool = AtomicBool::new(true);
if SHOULD_FIRE.swap($condition, Ordering::Relaxed) {
$expression;
}
}};
}
What alternative(s) have you considered?
Handling the variable myself.
The undo
portion is a little confusing to me. It sounds more like we want to detect a transition of a particular condition from false
to true
and only log on that edge. Is my understanding of that correct? Maybe we add a condition parameter directly on the once!
macro?
Maybe we add a condition parameter directly on the
once!
macro?
Yeah that's probably a better idea.
We should also decide if having $condition
be true
causes the $expression
to be called every call or only the first time it's true
.
I can find many ways to use this feature, for example, if you have somehow a message that could be dynamic (for example, the error reports some entity), we could have the warn/error be trigged everytime the message changes, but don't trigger at all if the message doesn't change.
We should also decide if having
$condition
betrue
causes the$expression
to be called every call or only the first time it'strue
.
If we do this, it's actually equivalent to writing an if statement without the involvement of once!
at all 😅
What about this?
macro_rules! once {
($expression:expr, $reset:expr) => {{
use ::std::sync::atomic::{AtomicBool, Ordering};
static SHOULD_FIRE: AtomicBool = AtomicBool::new(true);
let reset = $reset;
if !reset && SHOULD_FIRE.swap(false, Ordering::Relaxed) {
$expression;
} else if reset {
SHOULD_FIRE.swap(true, Ordering::Relaxed);
}
}};
}
This runs the $expression
the first time it's called, then when $reset
is set to true
then back to false
, the $expression
could be called once again.
This runs the
$expression
the first time it's called, then when$reset
is set totrue
then back tofalse
, the$expression
could be called once again.
I think we want to instead activate on false
to true
rather than true
to false
(where first run starts false
).
That makes it a bit easier to work with for something like "I only want this to fire when a collider starts a collision" or "I only want this to fire when my mana first hits zero".