[][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.