[−][src]Crate revent
Mutable aliasing free event system for Rust.
What is an event system?
An event system is a system where an object can create an event, and any other object (including the one generating the event itself) can listen and react to this event and update its state.
Why do we want this?
It allows us to decouple objects that need to uphold some invariant with respect to each other.
Take for instance a video player. If it loads a video then it should probably update the
run-time of that video in the GUI. So the video loader can emit an event of the type
VideoLoaded
which the GUI listens to and updates its state.
The alternative is to somehow encode this ad-hoc, by calling an update function for the GUI inside the video loader. This becomes unwieldy in large programs.
Example of basic usage
use revent::{down, Event, EventStore, Notifiable}; use std::any::TypeId; struct MyNotifiable; impl Notifiable for MyNotifiable { fn notify(&mut self, event: &dyn Event, _: &mut EventStore) { println!("I am notified"); if event.type_id() == TypeId::of::<u32>() { println!("This is a u32"); // Do something useful... } // Downcasting using the utility down function if let Some(value) = down::<u32>(event) { println!("Access to the u32 value: {}", value); } } } let mut mn = MyNotifiable { }; mn.with_notify(|this, store| { store.emit(123u32); });
The order in which events are processed is FIFO (first-in, first-out). Meaning that emitting an event guarantees that events emitted before will be run before.
More information
This library imagines a program or library using revent
to be a nested structure of structs,
many of which implement Notifiable. If a struct wishes to notify itself and its
sub-structures, it should use self.notify
. If it wishes to notify parents to the Nth degree
it should EventStore::emit into an EventStore
.
// An example of direct self-notification use revent::{Event, EventStore, Notifiable}; use std::any::TypeId; struct MyNotifiable; impl Notifiable for MyNotifiable { fn notify(&mut self, event: &dyn Event, _: &mut EventStore) { println!("Notified"); } } impl MyNotifiable { pub fn do_something(&mut self) { self.with_notify(|this, store| { // We need a store here because `notify` takes one, to which it itself can add // events. this.notify(&0u32, store); }); } } let mut mn = MyNotifiable { }; mn.do_something();
The following shows how substructures can emit events to super-structures without themselves being Notifiable.
// An example of emitting notifications to some super-structure. use revent::{Event, EventStore, Notifiable}; use std::any::TypeId; struct MyNotifiable { substructure: Substructure, } impl Notifiable for MyNotifiable { fn notify(&mut self, event: &dyn Event, store: &mut EventStore) { println!("Notified"); } } impl MyNotifiable { pub fn do_something(&mut self) { self.with_notify(|this, store| { this.substructure.do_substructure_thing(store); }); } } struct Substructure; impl Substructure { pub fn do_substructure_thing(&mut self, store: &mut EventStore) { store.emit(0u32); } } let mut mn = MyNotifiable { substructure: Substructure { }, }; mn.do_something();
Downsides
Emitting events into the EventStore
does not immediately execute an event. This is
unfortunately the way it is due to Rusts aliasing rules: We simply cannot hold a
super-structure while also mutably borring a field of that struct. We thus must accumulate
events into a buffer (EventStore
) and execute this store when control returns to the
super-structure.
Structs
EventStore | Event storage. Events are EventStore::emitted into this structure. |
Traits
Event | A generic event. Implemented for all types. |
Notifiable | Main trait of this crate to implement on structures. |
Functions
down | Shorthand version for downcasting an Event. |