Skip to content

Instantly share code, notes, and snippets.

@Lisoph
Created September 14, 2018 10:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Lisoph/6ea530d22ca585a5bfa3d61463b1882c to your computer and use it in GitHub Desktop.
Save Lisoph/6ea530d22ca585a5bfa3d61463b1882c to your computer and use it in GitHub Desktop.
Generic event container inspired by delegate / event in C#
use std::cell::UnsafeCell;
use std::marker::PhantomData;
type EventReceiver<'a, A, R> = Box<dyn (FnMut(A) -> R + 'a)>;
struct Event<'a, A, R> {
receivers: Vec<UnsafeCell<EventReceiver<'a, A, R>>>,
_m: PhantomData<&'a ()>,
}
impl<'a, A, R> Event<'a, A, R> {
fn new() -> Self {
Self {
receivers: Vec::new(),
_m: PhantomData,
}
}
fn add(&mut self, receiver: impl (FnMut(A) -> R + 'a)) {
self.receivers.push(UnsafeCell::new(Box::new(receiver)));
}
fn call<'b>(&'b self, args: A) -> Calls<'a, 'b, A, R> {
Calls {
event: self,
cur: 0,
args,
}
}
}
struct Calls<'a, 'b, A, R>
where
'a: 'b,
A: 'b,
R: 'b,
{
event: &'b Event<'a, A, R>,
cur: usize,
args: A,
}
impl<'a, 'b, A, R> Iterator for Calls<'a, 'b, A, R>
where
'a: 'b,
A: Clone,
{
type Item = R;
fn next(&mut self) -> Option<Self::Item> {
if let Some(cell) = self.event.receivers.get(self.cur) {
self.cur += 1;
let r = unsafe { &mut *cell.get() };
Some((**r)(self.args.clone()))
} else {
None
}
}
}
fn main() {
let mut foos = Vec::new();
{
let mut evt = Event::new();
evt.add(|_| {
println!("Hello, world!");
1
});
evt.add(|_| {
foos.push("kek");
2
});
evt.add(|n| {
println!("-- {}", n);
n
});
for ret in evt.call(123) {
println!(":: {}", ret);
}
}
for f in foos.into_iter() {
println!("FOO: {}", f);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment