Skip to content

Instantly share code, notes, and snippets.

@l0s
Created May 1, 2022 18:16
Show Gist options
  • Select an option

  • Save l0s/9ea897bb9a8b89ab999fa0c75a8d2989 to your computer and use it in GitHub Desktop.

Select an option

Save l0s/9ea897bb9a8b89ab999fa0c75a8d2989 to your computer and use it in GitHub Desktop.
Simple pluggable request handler mechanism
use rayon::{ThreadPool, ThreadPoolBuilder};
#[derive(Copy, Clone)]
pub struct Request {
request_id: u8,
}
pub struct Response {
response_id: u8,
}
pub struct Failure;
pub trait RequestHandler: Sync + Send {
fn handle_request(&self, request: &Request) -> Result<Response, Failure>;
}
impl<F> RequestHandler for F
where F: Fn(&Request) -> Result<Response, Failure> + Sync + Send {
fn handle_request(&self, request: &Request) -> Result<Response, Failure> {
self(request)
}
}
struct Server {
handler: Box<dyn RequestHandler>,
pool: ThreadPool,
}
impl Server {
fn with_handler(handler: Box<dyn RequestHandler>) -> Server {
let builder = ThreadPoolBuilder::new();
let pool = builder.build().unwrap();
Server {
handler,
pool,
}
}
}
impl Server {
pub fn run(&self) {
self.pool.scope(|scope| {
for request_id in 0..8u8 { // simulate reading infinite network events
let request = Request { request_id };
scope.spawn(move |_| { // pass each event to a worker
if let Ok(response) = self.handler.handle_request(&request) {
eprintln!("response_id: {}", response.response_id);
}
});
}
});
}
}
#[cfg(test)]
mod tests {
use std::sync::atomic::{AtomicU8, Ordering};
use crate::handler::{Failure, Request, RequestHandler, Response, Server};
#[test]
fn stateless_closure() {
let handler = |request: &Request| -> Result<Response, Failure> {
Ok(Response {
response_id: request.request_id,
})
};
let handler = Box::new(handler);
let server = Server::with_handler(handler);
server.run();
}
// #[test]
// fn stateful_closure() {
// let counter = AtomicU8::new(0);
// let response_handler = |_request: &Request| -> Result<Response, Failure> { // `counter` captured here
// Ok(Response {
// response_id: counter.fetch_add(1, Ordering::Relaxed), // error[E0597]: `counter` does not live long enough
// })
// };
// let handler = Box::new(response_handler);
// let server = Server::with_handler(handler); // cast requires that `counter` is borrowed for `'static`
//
// server.run();
// } // `counter` dropped here while still borrowed
#[test]
fn stateless_trait() {
struct Handler;
impl RequestHandler for Handler {
fn handle_request(&self, request: &Request) -> Result<Response, Failure> {
Ok(Response { response_id: request.request_id })
}
}
let handler = Box::new(Handler {});
let server = Server::with_handler(handler);
server.run();
}
#[test]
fn stateful_trait() {
#[derive(Default)]
struct Handler {
counter: AtomicU8,
}
impl RequestHandler for Handler {
fn handle_request(&self, _request: &Request) -> Result<Response, Failure> {
Ok(Response { response_id: self.counter.fetch_add(1, Ordering::Relaxed) })
}
}
let handler = Box::new(Handler::default());
let server = Server::with_handler(handler);
server.run();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment