#pub-sub #events #publish #event-bus #subscribe #bus #message

psbus

Generic Publish / Subscribe model for application messaging

1 unstable release

0.1.0 Aug 22, 2020

#2233 in Asynchronous

MIT license

46KB
632 lines

psbus

Generic Publish / Subscribe model for application messaging

NOTE: This module was heavily inspired by Lakelezz's (now dormant) hey_listen: https://github.com/Lakelezz/hey_listen

psbus allows for any application to implement their own Publish/Subscribe model for easy messaging. psbus currently supports the following use cases:

  • Single-threaded event dispatch
  • Single-threaded + prioritized event dispatch
  • Thread-safe / synchronized event dispatch
  • Thread-safe / synchronized + prioritized event dispatch

Installation

Add this to your Cargo.toml:

[dependencies]
psbus = "0.1.0"

Example

Aside from type name differences, the usage is consistent across the board for dispatchers. This example uses a single-threaded, non-prioritized dispatch model.

use psbus::{types::BusRequest, rc::{Event, Subscriber, Publisher, EventBus}};
use std::rc::Rc;

// Define the categories into which your events will fall
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub enum TestEventType {
    Variant1,
    Variant2,
}

// Define the events themselves, note that you can use bare, tuple or struct enums all the same!
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub enum TestEvent {
    ButtonPressed(u32),
    SomeOtherEvent,
}

// Implement the Event trait for your custom event
impl Event<TestEventType> for TestEvent {
    fn category(&self) -> TestEventType {
        match self {
            TestEvent::ButtonPressed(_) => TestEventType::Variant1,
            TestEvent::SomeOtherEvent => TestEventType::Variant2,
            // And more...
        }
    }
}

// Now lets make a test Subscriber...
pub struct TestSubscriber {
    id: Uuid,
}
impl Subscriber<TestEventType, TestEvent> for TestSubscriber {
    fn id(&self) -> &Uuid {
        &self.id
    }

    // ! Although we get a TestEvent enum, it is guaranteed to be only of the TestEventType that we are subscribed to
    fn on_event(&self, event: &ThermiteEvent) -> BusRequest {
        println!("Subscriber {} received event: {:?}", self.id, event);
        // What do we want to tell the bus to do after this subscriber is processed? For now, nothing... see crate::types::BusRequest for more actions
        BusRequest::NoActionNeeded
    }
}

// And a test Publisher...
pub struct TestPublisher {}
impl Publisher<TestEventType, TestEvent> for TestPublisher {
    // You can override the `publish_event` method here if you really want to...
}

// And finally, we define our EventBus type
pub type TestEventBus = EventBus<TestEventType, TestEvent>;

fn main() {
    // Again, what you wrap these datastructures with completely depends on your use case.
    let subscriber = Rc::new(TestSubscriber { id: Uuid::default() });
    let publisher = Rc::new(TestPublisher {});
    let bus = Rc::new(RefCell::new(TestEventBus::default()));

    // Subscribe our subscriber to receive any event falling under the `Variant1` category
    bus.try_borrow_mut().expect("Couldn't borrow event bus as mutable").subscribe(&subscriber, TestEventType::Variant1);

    // Publish an event to be received by the subscriber (NOTE: Call site here may vary depending on how you wrap your datastructures)
    publisher.publish_event(&TestEvent::ButtonPressed(1), &mut bus.try_borrow_mut().expect("Couldn't borrow event bus as mutable"));
}

Dependencies

~245KB