Skip to content

Instantly share code, notes, and snippets.

@durka
Forked from anonymous/playground.rs
Last active August 29, 2015 14:23
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 durka/22d5d3f2ef2063948ee8 to your computer and use it in GitHub Desktop.
Save durka/22d5d3f2ef2063948ee8 to your computer and use it in GitHub Desktop.
How to construct a closure as an Iron Handler while capturing a Sender
//! Shows how to construct a closure that captures a Sender while still implementing Sync
//! This is nontrivial because you can't directly share a Sender across threads, so a Mutex is required
use std::sync::mpsc::{channel, Sender};
use std::sync::Mutex;
use std::thread;
/// Something to send across threads
#[derive(Debug)]
enum Message { A, B }
/// Stub out some of Iron's types
struct Request;
struct Response;
struct IronError;
type IronResult<T> = Result<T, IronError>;
/// Iron's Handler trait with the impl for a closure
trait Handler: Send + Sync {
fn handle(&self, &mut Request) -> IronResult<Response>;
}
impl<F> Handler for F where F: Send + Sync + Fn(&mut Request) -> IronResult<Response> {
fn handle(&self, req: &mut Request) -> IronResult<Response> {
(*self)(req)
}
}
/// This function is called on the Iron thread, and it returns a boxed closure for use as a Handler
fn make_handler(tx: Sender<Message>) -> Box<Handler> {
// quite a dance is required to make a Handler from a closure
// first, we have to box the Handler because you can't return closures
// second, we can't capture `tx` because that makes the closure !Sync
// to solve this, we wrap the Sender in a Mutex, which _is_ Sync, and capture that
// there may be performance implications
let mtx = Mutex::new(tx);
Box::new(move |req: &mut Request| { mtx.lock().unwrap().send(Message::A); Ok(Response) })
}
/// Entry point to the Iron thread: constructs a handler and calls it
fn iron_setup(tx: Sender<Message>) {
let handler = make_handler(tx); // make me a request handler!
handler.handle(&mut Request); // let's just pretend to be a web client...
}
fn main() {
let (tx, rx) = channel::<Message>(); // a channel for communicating with the Iron thread
thread::spawn(move || iron_setup(tx.clone())); // fire off the Iron thread!
println!("{:?}", rx.recv()); // wait for a response and print it
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment