Add events that can be consumed, or can only be read once
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
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`:
```rust
trait SingleEvent: 'static + Send + Sync { }
```
A "single" observer takes `SingleTrigger` as its trigger type:
```rust
impl SingleEvent for Foo {}
fn my_single_observer(trigger: SingleTrigger) {
let mut data = trigger.event().consume().unwrap();
// Data is mine now! :D
}
```
Single observers are registered via `add_single_observer`:
```rust
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`:
```rust
commands.trigger_single(Foo);
```
A `SingleTrigger` is just a type alias:
```rust
type SingleTrigger = Trigger>
```
And `OnSingleEvent` is just a `Mutex`:
```rust
#[derive(Event)]
pub struct OnSingleEvent(Mutex>);
```
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
Contributor guide
Assessment
This issue has not been assessed yet.