Skip to content

Instantly share code, notes, and snippets.

@ilopX
Last active December 19, 2023 09:50
Show Gist options
  • Save ilopX/13a8ff76ab48ea42984d580d5b8cc4bf to your computer and use it in GitHub Desktop.
Save ilopX/13a8ff76ab48ea42984d580d5b8cc4bf to your computer and use it in GitHub Desktop.
use std::any::{Any, TypeId};
use std::cell::RefCell;
use std::collections::{BTreeMap, VecDeque};
use std::mem;
use std::rc::Rc;
struct FirstEvent {
int_val: u32,
}
struct SecondEvent {
string_val: String,
}
struct ThirdEvent {
string_val: String,
}
struct ThisEventNotBeCall {}
impl Event for FirstEvent {}
impl Event for SecondEvent {}
impl Event for ThirdEvent {}
impl Event for ThisEventNotBeCall {}
fn main() {
let string_result = RefCell::new(String::new());
let mut events = Events::new();
let listener = events.listen::<ThisEventNotBeCall>(|_, _| {
string_result.borrow_mut().push_str("some text");
});
events.listen::<FirstEvent>(|first_event, events| {
let new_val = first_event.int_val + 1;
events.send(SecondEvent {
string_val: new_val.to_string(),
});
});
events.listen::<SecondEvent>(|second_event, events| {
let new_val = format!("{} second", second_event.string_val);
events.send(ThirdEvent {
string_val: new_val,
});
});
events.listen::<ThirdEvent>(|third_event, _| {
let new_val = format!("{} third\n", third_event.string_val);
string_result.borrow_mut().push_str(&new_val);
});
events.remove_listener(listener);
events.send(ThisEventNotBeCall {});
events.send(FirstEvent { int_val: 0 });
assert_eq!("1 second third\n", string_result.borrow().as_str());
println!("{}", string_result.borrow());
}
#[cfg(test)]
mod tests {
use crate::{Event, Events};
use std::cell::{Cell, RefCell};
#[test]
fn add_listener_and_send() {
let result = Cell::new(false);
let mut events = Events::new();
events.listen::<bool>(|val, _| result.set(**val));
events.send(true);
assert_eq!(result.get(), true);
}
#[test]
fn listen_and_send_and_check_event_args() {
let result = RefCell::new(0);
let mut events = Events::new();
struct SomeEvent(u32);
impl Event for SomeEvent {}
events.listen::<SomeEvent>(|first_event, _| {
result.replace(first_event.0);
});
events.send(SomeEvent(123456));
assert_eq!(*result.borrow(), 123456);
}
#[test]
fn listen_and_remove_listener_and_send() {
let result = Cell::new(false);
let mut events = Events::new();
let listener = events.listen::<u32>(|_, _| {
result.replace(true);
});
events.remove_listener(listener);
events.send(100);
assert_eq!(result.get(), false);
}
#[test]
fn send_from_other_event() {
let result = RefCell::new(String::from(""));
let mut events = Events::new();
events.listen::<String>(|event, events| {
result.borrow_mut().push_str(event);
events.send(true);
});
events.listen::<bool>(|event, events| {
let mut result = result.borrow_mut();
result.push_str(&event.to_string());
result.push_str(", ");
events.send(100);
});
events.listen::<u32>(|event, _| {
let mut result = result.borrow_mut();
result.push_str(&event.to_string());
});
events.send("Hello, ".to_string());
assert_eq!(*result.borrow(), "Hello, true, 100");
}
#[test]
fn looping_send() {
let result = RefCell::new(vec![]);
let mut events = Events::new();
struct Foo;
impl Event for Foo {}
struct Bar;
impl Event for Bar {}
events.listen::<Foo>(|_, events| {
result.borrow_mut().push("foo");
events.send(Bar);
});
events.listen::<Bar>(|_, events| {
let mut result = result.borrow_mut();
result.push("bar");
if result.len() < 6 {
events.send(Foo);
}
});
events.send(Foo);
assert_eq!(
*result.borrow(),
vec!["foo", "bar", "foo", "bar", "foo", "bar"]
);
}
#[test]
fn several_identical_events() {
let counter = Cell::new(1);
let mut events = Events::new();
events.listen::<bool>(|_, _| counter.set(counter.get() + 1));
events.listen::<bool>(|_, _| counter.set(counter.get() + 1));
events.listen::<bool>(|_, _| counter.set(counter.get() + 1));
events.send(true);
}
impl Event for bool {}
impl Event for u32 {}
impl Event for String {}
}
trait Event: Any {}
struct Events {
events: Rc<RefCell<_Events>>,
}
impl Events {
pub fn new() -> Self {
Self {
events: Rc::new(RefCell::new(_Events::new())),
}
}
pub fn listen<T: Event>(&self, listener_fun: impl FnMut(&Box<T>, &mut EventPool)) -> Listener {
let new_listener = Listener::new(self.events.clone(), listener_fun);
self.events.borrow_mut().listen(new_listener)
}
pub fn remove_listener(&self, mut listener: Listener) {
self.events.borrow_mut().detach_parent(&mut listener);
}
pub fn send(&self, event: impl Event) {
self.events.borrow_mut().send(event);
}
}
struct _Events {
listeners: BTreeMap<TypeId, Vec<Listener>>,
}
impl _Events {
pub fn new() -> Self {
Self {
listeners: Default::default(),
}
}
pub fn listen(&mut self, new_listener: Listener) -> Listener {
self.add_listener(new_listener.clone());
new_listener
}
fn add_listener(&mut self, new_listener: Listener) {
let key = new_listener.rc.borrow().event_type.clone();
match self.listeners.get_mut(&key) {
Some(list) => list.push(new_listener),
None => {
let new_list = vec![new_listener];
self.listeners.insert(key, new_list);
}
}
}
fn detach_parent(&mut self, listener: &mut Listener) {
self.listeners
.entry(listener.rc.borrow().event_type.clone())
.and_modify(|list| {
list.retain(|n| n != listener);
});
}
pub fn send(&mut self, event: impl Event) {
let mut event_pool = EventPool::from(event);
while let Some(event) = event_pool.pop() {
self.call_listeners(event, &mut event_pool);
}
}
fn call_listeners(&mut self, event: Box<dyn Event>, mut event_pool: &mut EventPool) {
let key = (*event).type_id();
if let Some(listeners) = self.listeners.get(&key) {
for listener in listeners {
listener.notify(&event, &mut event_pool);
}
}
}
}
type ListenerFunAny = Box<dyn FnMut(&Box<dyn Event>, &mut EventPool)>;
struct ListenerRc {
event_type: TypeId,
rc_parent: Option<Rc<RefCell<_Events>>>,
fun: ListenerFunAny,
}
struct Listener {
rc: Rc<RefCell<ListenerRc>>,
}
impl Listener {
pub fn new<T: Event>(
rc_parent: Rc<RefCell<_Events>>,
new_listener: impl FnMut(&Box<T>, &mut EventPool),
) -> Self {
let rc = ListenerRc {
rc_parent: Some(rc_parent),
event_type: TypeId::of::<T>(),
fun: Self::convert(new_listener),
};
Self {
rc: Rc::new(RefCell::new(rc)),
}
}
fn notify(&self, arg: &Box<dyn Event>, list_events: &mut EventPool) {
(self.rc.borrow_mut().fun)(arg, list_events);
}
fn remove_me(&mut self) {
let parent = self.rc.borrow_mut().rc_parent.take().unwrap();
parent.borrow_mut().detach_parent(self);
}
fn convert<T: Event>(listener: impl FnMut(&Box<T>, &mut EventPool)) -> ListenerFunAny {
let new_listener = Box::new(listener);
unsafe {
mem::transmute::<Box<dyn FnMut(&Box<T>, &mut EventPool)>, ListenerFunAny>(new_listener)
}
}
}
impl Clone for Listener {
fn clone(&self) -> Self {
let is_second_clone_exists = Rc::strong_count(&self.rc) == 2;
if is_second_clone_exists {
panic!("");
}
Self {
rc: self.rc.clone(),
}
}
}
impl PartialEq for Listener {
fn eq(&self, other: &Self) -> bool {
Rc::ptr_eq(&self.rc, &other.rc)
}
}
struct EventPool {
events: VecDeque<Box<dyn Event>>,
}
impl EventPool {
fn new() -> Self {
Self {
events: Default::default(),
}
}
fn from(event: impl Event) -> Self {
let mut events = VecDeque::<Box<dyn Event>>::new();
events.push_back(Box::new(event));
Self {
events,
..EventPool::new()
}
}
fn send(&mut self, event: impl Event) {
let event = Box::new(event);
self.events.push_back(event);
}
fn pop(&mut self) -> Option<Box<dyn Event>> {
self.events.pop_front()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment