-
-
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
This file contains hidden or 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
//! 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