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

Basic Example

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

trait BasicSignal {}

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

// ---

struct MyNode;
impl Node<MyAnchor, ()> for MyNode {
    fn register_emits(_: &MyAnchor) -> () { () }

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

// ---

let mut hub = MyAnchor::new();
let item = hub.subscribe(|_| MyNode);
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:

  • Slots
  • Anchors
  • Nodes

Slots

A slot is a container for item(s) that listen to that particular slot. Any signal emission on said slot will notify all items in that slot.

In this documentation slot denotes both Slot and Single.

Anchor

An anchor contains all slots in a system. It also contains a Manager and implements Anchor. We register new Nodes to an anchor, and these nodes will themselves choose which slots to listen or emit to. Only anchors can be subscribed to.

Nodes

A node implements Node which contains the functions:

These specify the signals to emit and listen to. Any struct can be a node. Nodes are constructed by first constructing the emitter structure as specified by register_emits. This structure is then provided to the Anchor::subscribe create function.

When talking about the nodes subscribed (as per register_listens) to a slot, the term subscriber may be used.

Example with Emitter

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

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

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

struct MyAnchor {
    basic_slot_1: Slot<dyn BasicSignal>,
    basic_slot_2: Slot<dyn BasicSignal>,
    mng: Rc<RefCell<Manager>>,
}
impl MyAnchor {
    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 MyAnchor {
    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 register_emits.

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

// ---

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

struct MyNode { emits: MyEmitter }
impl Node<MyAnchor, MyEmitter> for MyNode {
    // Indicate which slots we want to use.
    fn register_emits(hub: &MyAnchor) -> MyEmitter {
        MyEmitter {
            basic_slot_2: hub.basic_slot_2.clone(),
        }
    }

    fn register_listens(hub: &mut MyAnchor, item: Rc<RefCell<Self>>) {
        hub.basic_slot_1.register(item);
    }
    const NAME: &'static str = "MyNode";
}

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

// ---

let mut hub = MyAnchor::new();
// The type annotation is not needed, but shown here to show what to expect.
let item = hub.subscribe(|emits: MyEmitter| MyNode { emits });
hub.basic_slot_1.emit(BasicSignal::basic);
hub.unsubscribe(&item);

Structs

Grapher

Wrapper around a Manager that generates a graph.

Manager

Inspects how various Nodes use slots.

Single

Single slot containing T.

Slot

List of Nodes to a signal T.

Traits

Anchor

A collection of slots to which Nodes can subscribe.

Node

Describes a subscriber that can subscribe to Anchor.