Last active
August 18, 2020 23:03
-
-
Save aboglioli/693b17be13d5ed82805340d452cebae1 to your computer and use it in GitHub Desktop.
Basic EventBus in Rust. Playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=b0b32172f43549e47e46113cb2d1d786
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::cell::{Cell, RefCell}; | |
use std::collections::HashMap; | |
use std::fmt::Debug; | |
use std::rc::Rc; | |
#[derive(Debug)] | |
pub struct Error; | |
pub trait Event: Debug { | |
fn code(&self) -> &str; | |
fn payload(&self) -> Vec<u8>; | |
} | |
pub trait EventPublisher { | |
fn publish(&self, topic: &str, event: Box<dyn Event>) -> Result<(), Error>; | |
} | |
pub type Subscription = Box<dyn FnMut(&dyn Event) -> Result<(), Error>>; | |
pub trait EventSubscriber { | |
fn subscribe(&self, topic: &str, cb: Subscription) -> Result<(), Error>; | |
} | |
pub struct InMemEventBus { | |
subscriptions: RefCell<HashMap<String, Vec<Subscription>>>, | |
notified: Cell<u32>, | |
} | |
impl InMemEventBus { | |
pub fn new() -> InMemEventBus { | |
InMemEventBus { | |
subscriptions: RefCell::new(HashMap::new()), | |
notified: Cell::new(0), | |
} | |
} | |
pub fn notified(&self) -> u32 { | |
self.notified.get() | |
} | |
pub fn reset_counter(&self) { | |
self.notified.set(0); | |
} | |
} | |
impl Default for InMemEventBus { | |
fn default() -> Self { | |
Self::new() | |
} | |
} | |
impl EventPublisher for InMemEventBus { | |
fn publish(&self, topic: &str, event: Box<dyn Event>) -> Result<(), Error> { | |
let mut count = 0; | |
if let Some(subs) = self.subscriptions.borrow_mut().get_mut(topic) { | |
for sub in subs.iter_mut() { | |
sub(event.as_ref())?; | |
count += 1; | |
} | |
} | |
self.notified.set(self.notified.get() + count); | |
Ok(()) | |
} | |
} | |
impl EventSubscriber for InMemEventBus { | |
fn subscribe(&self, topic: &str, cb: Subscription) -> Result<(), Error> { | |
if let Some(subs) = self.subscriptions.borrow_mut().get_mut(topic) { | |
subs.push(cb); | |
return Ok(()); | |
} | |
self.subscriptions | |
.borrow_mut() | |
.insert(topic.to_owned(), vec![cb]); | |
Ok(()) | |
} | |
} | |
#[derive(Debug)] | |
struct Ent1Created; | |
impl Event for Ent1Created { | |
fn code(&self) -> &str { | |
"ent1.created" | |
} | |
fn payload(&self) -> Vec<u8> { | |
b"ent1.created".to_vec() | |
} | |
} | |
#[derive(Debug)] | |
struct Ent1Updated; | |
impl Event for Ent1Updated { | |
fn code(&self) -> &str { | |
"ent1.updated" | |
} | |
fn payload(&self) -> Vec<u8> { | |
b"ent1.updated".to_vec() | |
} | |
} | |
#[derive(Debug)] | |
struct Ent2Created; | |
impl Event for Ent2Created { | |
fn code(&self) -> &str { | |
"ent2.created" | |
} | |
fn payload(&self) -> Vec<u8> { | |
b"ent2.created".to_vec() | |
} | |
} | |
fn main() -> Result<(), Error> { | |
let eb = InMemEventBus::new(); | |
let calls = Rc::new(Cell::new(0)); | |
let call = Rc::clone(&calls); | |
eb.subscribe( | |
"ent1.created", | |
Box::new(move |event| { | |
call.set(call.get() + 1); | |
assert_eq!(event.code(), "ent1.created"); | |
Ok(()) | |
}), | |
)?; | |
let call = Rc::clone(&calls); | |
eb.subscribe( | |
"ent1.created", | |
Box::new(move |event| { | |
println!("{}", event.code()); | |
call.set(call.get() + 1); | |
Ok(()) | |
}), | |
)?; | |
let call = Rc::clone(&calls); | |
eb.subscribe( | |
"ent1.updated", | |
Box::new(move |event| { | |
println!("{}", event.code()); | |
call.set(call.get() + 1); | |
assert_eq!(event.code(), "ent1.updated"); | |
Ok(()) | |
}), | |
)?; | |
let call = Rc::clone(&calls); | |
eb.subscribe( | |
"ent2.created", | |
Box::new(move |event| { | |
println!("{}", event.code()); | |
call.set(call.get() + 1); | |
assert_eq!(event.code(), "ent2.created"); | |
Ok(()) | |
}), | |
)?; | |
eb.publish("ent1.created", Box::new(Ent1Created)).unwrap(); | |
assert_eq!(calls.get(), 2); | |
assert_eq!(eb.notified(), 2); | |
eb.reset_counter(); | |
calls.set(0); | |
eb.publish("ent1.created", Box::new(Ent1Created)).unwrap(); | |
eb.publish("ent1.updated", Box::new(Ent1Updated)).unwrap(); | |
eb.publish("ent2.created", Box::new(Ent2Created)).unwrap(); | |
assert_eq!(calls.get(), 4); | |
assert_eq!(eb.notified(), 4); | |
Ok(()) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::cell::{Cell, RefCell}; | |
use std::collections::HashMap; | |
use std::fmt::Debug; | |
use std::rc::Rc; | |
#[derive(Debug)] | |
pub struct Error; | |
pub trait Event: Debug { | |
fn code(&self) -> &str; | |
fn payload(&self) -> Vec<u8>; | |
} | |
pub struct InMemEventBus<'a> { | |
subscriptions: | |
RefCell<HashMap<String, Vec<Box<dyn FnMut(&dyn Event) + 'a>>>>, | |
notified: Cell<u32>, | |
} | |
impl<'a> InMemEventBus<'a> { | |
pub fn new() -> Self { | |
InMemEventBus { | |
subscriptions: RefCell::new(HashMap::new()), | |
notified: Cell::new(0), | |
} | |
} | |
pub fn notified(&self) -> u32 { | |
self.notified.get() | |
} | |
pub fn reset_counter(&self) { | |
self.notified.set(0); | |
} | |
} | |
pub trait EventPublisher { | |
fn publish(&self, topic: &str, event: &dyn Event) -> Result<(), Error>; | |
} | |
impl<'a> EventPublisher for InMemEventBus<'a> { | |
fn publish(&self, topic: &str, event: &dyn Event) -> Result<(), Error> { | |
let mut count = 0; | |
if let Some(subs) = self.subscriptions.borrow_mut().get_mut(topic) { | |
for sub in subs.iter_mut() { | |
sub(event); | |
count += 1; | |
} | |
} | |
self.notified.set(self.notified.get() + count); | |
Ok(()) | |
} | |
} | |
pub trait EventSubscriber<'a> { | |
fn subscribe( | |
&self, | |
topic: &str, | |
cb: Box<dyn FnMut(&dyn Event) + 'a>, | |
) -> Result<(), Error>; | |
} | |
impl<'a> EventSubscriber<'a> for InMemEventBus<'a> { | |
fn subscribe( | |
&self, | |
topic: &str, | |
cb: Box<dyn FnMut(&dyn Event) + 'a>, | |
) -> Result<(), Error> { | |
if let Some(subs) = self.subscriptions.borrow_mut().get_mut(topic) { | |
subs.push(cb); | |
return Ok(()); | |
} | |
self.subscriptions | |
.borrow_mut() | |
.insert(topic.to_owned(), vec![cb]); | |
Ok(()) | |
} | |
} | |
#[derive(Debug)] | |
struct Ent1Created; | |
impl Event for Ent1Created { | |
fn code(&self) -> &str { | |
"ent1.created" | |
} | |
fn payload(&self) -> Vec<u8> { | |
b"ent1.created".to_vec() | |
} | |
} | |
#[derive(Debug)] | |
struct Ent1Updated; | |
impl Event for Ent1Updated { | |
fn code(&self) -> &str { | |
"ent1.updated" | |
} | |
fn payload(&self) -> Vec<u8> { | |
b"ent1.updated".to_vec() | |
} | |
} | |
#[derive(Debug)] | |
struct Ent2Created; | |
impl Event for Ent2Created { | |
fn code(&self) -> &str { | |
"ent2.created" | |
} | |
fn payload(&self) -> Vec<u8> { | |
b"ent2.created".to_vec() | |
} | |
} | |
fn main() -> Result<(), Error> { | |
let mut v = 0; | |
{ | |
let eb = InMemEventBus::new(); | |
let mut cb: Box<dyn FnMut(&dyn Event)> = Box::new(|event| { | |
v += 2; | |
}); | |
eb.subscribe("ent1.created", cb)?; | |
eb.publish("ent1.created", &Ent1Created).unwrap(); | |
} | |
println!("{}", v); | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment