-
-
Save nwin/db3138f6d421bf2e6189 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
#![feature(std_misc)] | |
#![allow(raw_pointer_derive)] | |
#![feature(box_syntax)] | |
use std::mem; | |
use std::sync::{Arc, Mutex}; | |
use std::sync::mpsc::{Sender, Receiver, channel}; | |
use std::thread::spawn; | |
use std::thunk::Invoke; | |
struct Listener(Box<for<'r> Invoke<(&'r AsyncResponseListener)> + Send>); | |
impl Listener { | |
fn new<F: FnOnce(&AsyncResponseListener) + Send + 'static>(f: F) -> Listener { Listener(box f) } | |
} | |
trait AsyncResponseTarget { | |
fn invoke_with_listener(&self, f: Listener); | |
} | |
trait AsyncResponseListener { | |
fn foo(&self); | |
} | |
fn resource_task(rx: Receiver<Box<AsyncResponseTarget+Send>>) { | |
let target = rx.recv().unwrap(); | |
target.invoke_with_listener(Listener::new(move |listener| { | |
listener.foo(); | |
})); | |
} | |
struct FooContext { | |
foo_ptr: *const MainThreadFoo, | |
} | |
unsafe impl Send for FooContext {} | |
impl AsyncResponseListener for FooContext { | |
fn foo(&self) { | |
let foo = unsafe { &*self.foo_ptr }; | |
println!("n is {}", foo.n); | |
} | |
} | |
impl Drop for FooContext { | |
fn drop(&mut self) { | |
let _foo: Box<MainThreadFoo> = unsafe { mem::transmute(self.foo_ptr) }; | |
} | |
} | |
struct OffThreadListener { | |
main_thread_foo: Arc<Mutex<FooContext>>, | |
main_tx: Sender<Box<Runnable+Send>>, | |
} | |
impl AsyncResponseTarget for OffThreadListener { | |
fn invoke_with_listener(&self, f: Listener) { | |
self.main_tx.send(Box::new(MainThreadInvoke { | |
foo: self.main_thread_foo.clone(), | |
f: f, | |
})).unwrap(); | |
} | |
} | |
trait Runnable { | |
fn handler(self: Box<Self>); | |
} | |
struct MainThreadInvoke { | |
foo: Arc<Mutex<FooContext>>, | |
f: Listener, | |
} | |
impl<'a> Runnable for MainThreadInvoke { | |
fn handler(self: Box<Self>) { | |
let this = *self; | |
let foo = this.foo.lock().unwrap(); | |
let Listener(f) = this.f; | |
f.invoke(&*foo); | |
} | |
} | |
struct MainThreadFoo { | |
n: u64, | |
_n2: u64, | |
} | |
fn main() { | |
let (resource_tx, resource_rx) = channel(); | |
let (main_tx, main_rx) = channel(); | |
spawn(move || { | |
resource_task(resource_rx); | |
}); | |
let foo = Box::new(MainThreadFoo { n: 1337, _n2: 0 }); | |
let foo_context = FooContext { | |
foo_ptr: unsafe { mem::transmute(foo) }, | |
}; | |
let listener = OffThreadListener { | |
main_thread_foo: Arc::new(Mutex::new(foo_context)), | |
main_tx: main_tx, | |
}; | |
resource_tx.send(Box::new(listener)).unwrap(); | |
while let Ok(runnable) = main_rx.recv() { | |
runnable.handler(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment