-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Description
What problem does this solve or what need does it fill?
I recently ran into a use case where I wanted an observer to "consume" an event because the underlying data is big and/or not cloneable. I can guarantee that this is the only observer that will ever listen to this event.
So I made a generic solution that I'm calling SingleEvent
(or maybe UniqueEvent
? ExclusiveEvent
?).
What solution would you like?
I propose a new SingleEvent
trait, along with SingleTrigger
and add_single_observer
:
trait SingleEvent: 'static + Send + Sync { }
A "single" observer takes SingleTrigger
as its trigger type:
impl SingleEvent for Foo {}
fn my_single_observer(trigger: SingleTrigger<OnFoo>) {
let mut data = trigger.event().consume().unwrap();
// Data is mine now! :D
}
Single observers are registered via add_single_observer
:
app.add_single_observer(my_single_observer)
This function should panic or raise errors if another observer is already registered for this event.
User invokes the event using trigger_single
:
commands.trigger_single(Foo);
A SingleTrigger<T>
is just a type alias:
type SingleTrigger<T> = Trigger<OnSingleEvent<T>>
And OnSingleEvent
is just a Mutex
:
#[derive(Event)]
pub struct OnSingleEvent<E: SingleEvent>(Mutex<Option<E>>);
I've released the full implementation of my proposed solution under my own public crate:
https://github.com/Zeenobit/moonshine_util/blob/main/src/event.rs
However, I believe it'd be better if this was part of Bevy proper:
- We could enforce "single" observer registration more robustly
- I'm using a dummy plugin as a "registry" in my solution, and the user could easily bypass this check.
- We could maybe unify the API a bit to maybe use the same
trigger()
method to trigger single and regular events alike. - We could extend the feature to support single triggers on entities too (my solution only support world events).
- It's a powerful tool for library authors since it allows them to "consume" user data from observers without relying on third party crates
What alternative(s) have you considered?
N/A
Additional context
See here for a usage of this pattern in moonshine-save
:
https://github.com/Zeenobit/moonshine_save/blob/9f7f533086cae8bf6851ff8acfd142018b7f966e/src/save.rs#L206