[][src]Crate revent

Synchronous event system.

What is an event system?

An event system is a set of slots which contain objects. A signal is emitted on a slot, which will call each object in the slot. Invoked objects can then send more signals to different slots.

Synchronous

Revent's events are synchronous, meaning that emitting an event will immediately process all handlers in a slot. Once the function call returns, it is guaranteed that all listeners have been called.

Example

use revent::{Anchor, Manager, Named, Slot, Subscriber};
use std::{cell::RefCell, rc::Rc};

trait BasicSignal {}

struct Hub {
    basic_slot: Slot<dyn BasicSignal>,
    mng: Rc<RefCell<Manager>>,
}
impl Hub {
    fn new() -> Self {
        let mng = Rc::new(RefCell::new(Manager::default()));
        Self {
            basic_slot: Slot::new("basic_slot", mng.clone()),
            mng,
        }
    }
}
impl Anchor for Hub {
    fn manager(&self) -> &Rc<RefCell<Manager>> {
        &self.mng
    }
}

// ---

struct MySubscriber;
impl Subscriber<Hub> for MySubscriber {
    type Emitter = ();

    fn register(hub: &mut Hub, item: Rc<RefCell<Self>>) {
        hub.basic_slot.register(item);
    }
}
impl Named for MySubscriber {
    const NAME: &'static str = "MySubscriber";
}
impl BasicSignal for MySubscriber {}

// ---

let mut hub = Hub::new();
let item = hub.subscribe(|_| MySubscriber);
hub.basic_slot.emit(|x| {
    println!("Called for each subscriber");
});
hub.unsubscribe(&item);

Mutable cycles

Revent performs cycle detection in subscribe and ensures that no system exists in which we can create double mutable borrows.

Core Concepts

An event system based on revent has 3 core concepts:

  • Anchors
  • Emitters
  • Subscribers

Anchor

An anchor contains all event Slots and Singles in the system. It also contains a Manager and implements Anchor. We register new Subscribers to an anchor, and the subscribers will themselves choose which slots/singles to listen or emit to. Only anchors can be subscribed to.

Subscriber

Subscribers are classes that implement Subscriber<A: Anchor>. They specify their interest in signals to listen to by fn register. They specify their singles/slots to emit to via type Emitter.

Emitter

Each subscriber has an associated Emitter. An emitter contains a list of singles and slots based on the Anchor of its subscriber. Emitters simply implement Emit for Anchor which clones singles and slots from a particular anchor to the emitter itself.

Example with Emitter

use revent::{Anchor, Emit, Manager, Named, Slot, Subscriber};
use std::{cell::RefCell, rc::Rc};

// First let's crate a hub (Anchor) that contains two signals.

trait BasicSignal {
    fn basic(&mut self);
}

struct Hub {
    basic_slot_1: Slot<dyn BasicSignal>,
    basic_slot_2: Slot<dyn BasicSignal>,
    mng: Rc<RefCell<Manager>>,
}
impl Hub {
    fn new() -> Self {
        let mng = Rc::new(RefCell::new(Manager::default()));
        Self {
            basic_slot_1: Slot::new("basic_slot_1", mng.clone()),
            basic_slot_2: Slot::new("basic_slot_2", mng.clone()),
            mng,
        }
    }
}
impl Anchor for Hub {
    fn manager(&self) -> &Rc<RefCell<Manager>> {
        &self.mng
    }
}

// ---

// Now we define our emitter structure, this one contains only `basic_slot_2`, which indicates
// that we want to emit only to this slot for the subscribers using it as their emitter.

struct MyEmitter {
    basic_slot_2: Slot<dyn BasicSignal>,
}

impl Emit<Hub> for MyEmitter {
    fn create(item: &Hub) -> Self {
        Self {
            basic_slot_2: item.basic_slot_2.clone(),
        }
    }
}

// ---

// Create a subscriber that uses MyEmitter (emits on `basic_slot_2`), and listens on
// `basic_slot_1`.

struct MySubscriber { emitter: MyEmitter }
impl Subscriber<Hub> for MySubscriber {
    // Indicate which emitter we want to use.
    type Emitter = MyEmitter;

    fn register(hub: &mut Hub, item: Rc<RefCell<Self>>) {
        hub.basic_slot_1.register(item);
    }
}
impl Named for MySubscriber {
    const NAME: &'static str = "MySubscriber";
}

// Whenever we get a basic signal we pass it to the emitter.
impl BasicSignal for MySubscriber {
    fn basic(&mut self) {
        self.emitter.basic_slot_2.emit(|_| println!("Hello world"));
    }
}

// ---

let mut hub = Hub::new();
let item = hub.subscribe(|emitter| MySubscriber { emitter });
hub.basic_slot_1.emit(BasicSignal::basic);
hub.unsubscribe(&item);

Structs

Grapher

Wrapper around a Manager that generates a graph.

Manager

Inspects how various Subscribers use Slots.

Single

Single Subscriber to a signal T.

Slot

List of Subscribers to a signal T.

Traits

Anchor

A collection of Slots and Singles to which Subscribers can subscribe.

Emit

An emitter for a specific Anchor.

Named

Attach a name to a type.

Subscriber

Describes a subscriber that can subscribe to Anchor.