use std::sync::Mutex;
use {Rocket, Request, Response, Data};
use fairing::{Fairing, Kind, Info};
pub struct AdHoc {
name: &'static str,
kind: AdHocKind,
}
enum AdHocKind {
Attach(Mutex<Option<Box<dyn FnOnce(Rocket) -> Result<Rocket, Rocket> + Send + 'static>>>),
Launch(Mutex<Option<Box<dyn FnOnce(&Rocket) + Send + 'static>>>),
Request(Box<dyn Fn(&mut Request, &Data) + Send + Sync + 'static>),
Response(Box<dyn Fn(&Request, &mut Response) + Send + Sync + 'static>),
}
impl AdHoc {
pub fn on_attach<F>(name: &'static str, f: F) -> AdHoc
where F: FnOnce(Rocket) -> Result<Rocket, Rocket> + Send + 'static
{
AdHoc { name, kind: AdHocKind::Attach(Mutex::new(Some(Box::new(f)))) }
}
pub fn on_launch<F>(name: &'static str, f: F) -> AdHoc
where F: FnOnce(&Rocket) + Send + 'static
{
AdHoc { name, kind: AdHocKind::Launch(Mutex::new(Some(Box::new(f)))) }
}
pub fn on_request<F>(name: &'static str, f: F) -> AdHoc
where F: Fn(&mut Request, &Data) + Send + Sync + 'static
{
AdHoc { name, kind: AdHocKind::Request(Box::new(f)) }
}
pub fn on_response<F>(name: &'static str, f: F) -> AdHoc
where F: Fn(&Request, &mut Response) + Send + Sync + 'static
{
AdHoc { name, kind: AdHocKind::Response(Box::new(f)) }
}
}
impl Fairing for AdHoc {
fn info(&self) -> Info {
let kind = match self.kind {
AdHocKind::Attach(_) => Kind::Attach,
AdHocKind::Launch(_) => Kind::Launch,
AdHocKind::Request(_) => Kind::Request,
AdHocKind::Response(_) => Kind::Response,
};
Info { name: self.name, kind }
}
fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> {
if let AdHocKind::Attach(ref mutex) = self.kind {
let mut opt = mutex.lock().expect("AdHoc::Attach lock");
let f = opt.take().expect("internal error: `on_attach` one-call invariant broken");
f(rocket)
} else {
Ok(rocket)
}
}
fn on_launch(&self, rocket: &Rocket) {
if let AdHocKind::Launch(ref mutex) = self.kind {
let mut opt = mutex.lock().expect("AdHoc::Launch lock");
let f = opt.take().expect("internal error: `on_launch` one-call invariant broken");
f(rocket)
}
}
fn on_request(&self, request: &mut Request, data: &Data) {
if let AdHocKind::Request(ref callback) = self.kind {
callback(request, data)
}
}
fn on_response(&self, request: &Request, response: &mut Response) {
if let AdHocKind::Response(ref callback) = self.kind {
callback(request, response)
}
}
}