Last active
December 19, 2023 09:50
-
-
Save ilopX/13a8ff76ab48ea42984d580d5b8cc4bf to your computer and use it in GitHub Desktop.
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::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