starbase_events
An async event emitter for the starbase
application framework. This crate works quite differently
than other event systems, as subscribers can mutate event data. Because of this, we cannot use
message channels, and must take extra precaution to satisfy Send
+ Sync
requirements.
Creating events
Events must derive Event
or implement the Event
trait.
use Event;
use Project;
;
Event data
Events can optionally contain data, which is passed to and can be mutated by subscribers. By default
the value is a unit type (()
), but can be customized with #[event]
for derived events, or
type Data
when implemented manually.
use Event;
use PathBuf;
;
// OR
;
Creating emitters
An Emitter
is in charge of managing subscribers, and dispatching an event to each subscriber,
while taking into account the execution flow and once subscribers.
Every event will require its own emitter instance.
use Emitter;
let project_created = new;
let cache_check: = new;
Using subscribers
Subscribers are async functions that are registered into an emitter, and are executed when the
emitter emits an event. They are passed the event object as a Arc<T>
, and the event's data as
Arc<RwLock<T::Data>>
, allowing for the event to referenced immutably, and its data to be accessed
mutably or immutably.
use ;
async
emitter.on.await; // Runs multiple times
emitter.once.await; // Only runs once
Furthermore, we provide a #[subscriber]
function attribute that streamlines the function
implementation. For example, the above subscriber can be rewritten as:
async
When using #[subscriber]
, the following benefits apply:
- The return type is optional.
- The return value is optional if
EventState::Continue
. - Using
mut event
or&mut Event
will acquire a write lock on data, otherwise a read lock. - Omitting the event parameter will not acquire any lock.
- The name of the parameter is for the data, while the event is simply
event
.
Controlling the event flow
Subscribers can control the event execution flow by returning EventState
, which supports the
following variants:
Continue
- Continues to the next subscriber (default).Stop
- Stops after this subscriber, discarding subsequent subscribers.
async
async
Emitting and handling results
When an event is emitted, subscribers are executed sequentially in the same thread so that each subscriber can mutate the event if necessary. Because of this, events do not support references/lifetimes for inner values, and instead must own everything.
An event can be emitted with the emit()
method, which requires an owned event (and owned inner
data).
let data = emitter.emit.await?;
Emitting returns the event data after all modifications.