use std::{future::Future, pin::Pin};
use http::{HeaderValue, StatusCode};
use crate::server::{NgynContext, ToBytes};
pub(crate) type Handler = dyn Fn(&mut NgynContext) -> Box<dyn ToBytes> + Send + Sync + 'static;
pub(crate) type AsyncHandler = dyn for<'a, 'b> Fn(
&'a mut NgynContext,
) -> Pin<Box<dyn Future<Output = Box<dyn ToBytes>> + Send + 'a>>
+ Send
+ Sync;
pub enum RouteHandler {
Sync(Box<Handler>),
Async(Box<AsyncHandler>),
}
impl From<Box<AsyncHandler>> for RouteHandler {
fn from(f: Box<AsyncHandler>) -> Self {
RouteHandler::Async(f)
}
}
impl<F: Fn(&mut NgynContext) -> Box<dyn ToBytes> + Send + Sync + 'static> From<F> for RouteHandler {
fn from(f: F) -> Self {
RouteHandler::Sync(Box::new(f))
}
}
pub fn handler<S: ToBytes + 'static>(
f: impl Fn(&mut NgynContext) -> S + Send + Sync + 'static,
) -> Box<Handler> {
Box::new(move |ctx: &mut NgynContext| {
let body = f(ctx);
Box::new(body) as Box<dyn ToBytes>
})
}
pub fn async_handler<S: ToBytes + 'static, Fut: Future<Output = S> + Send + 'static>(
f: impl Fn(&mut NgynContext) -> Fut + Send + Sync + 'static,
) -> Box<AsyncHandler> {
Box::new(move |ctx: &mut NgynContext| {
let fut = f(ctx);
Box::pin(async move { Box::new(fut.await) as Box<dyn ToBytes> })
})
}
pub fn async_wrap(
f: impl for<'a, 'b> Fn(
&'a mut NgynContext,
) -> Pin<Box<dyn Future<Output = Box<dyn ToBytes>> + Send + 'a>>
+ Send
+ Sync
+ 'static,
) -> Box<AsyncHandler> {
Box::new(f)
}
pub fn not_implemented() -> Box<Handler> {
Box::new(|ctx: &mut NgynContext| {
*ctx.response_mut().status_mut() = StatusCode::NOT_IMPLEMENTED;
Box::new(()) as Box<dyn ToBytes>
})
}
pub fn redirect_to(location: &'static str) -> Box<Handler> {
Box::new(|ctx: &mut NgynContext| {
ctx.response_mut()
.headers_mut()
.insert("Location", HeaderValue::from_str(location).unwrap());
*ctx.response_mut().status_mut() = StatusCode::SEE_OTHER;
Box::new(()) as Box<dyn ToBytes>
})
}
pub fn redirect_temporary(location: &'static str) -> Box<Handler> {
Box::new(|ctx: &mut NgynContext| {
ctx.response_mut()
.headers_mut()
.insert("Location", HeaderValue::from_str(location).unwrap());
*ctx.response_mut().status_mut() = StatusCode::TEMPORARY_REDIRECT;
Box::new(()) as Box<dyn ToBytes>
})
}
pub fn redirect_permanent(location: &'static str) -> Box<Handler> {
Box::new(|ctx: &mut NgynContext| {
ctx.response_mut()
.headers_mut()
.insert("Location", HeaderValue::from_str(location).unwrap());
*ctx.response_mut().status_mut() = StatusCode::MOVED_PERMANENTLY;
Box::new(()) as Box<dyn ToBytes>
})
}
pub fn redirect_found(location: &'static str) -> Box<Handler> {
Box::new(|ctx: &mut NgynContext| {
ctx.response_mut()
.headers_mut()
.insert("Location", HeaderValue::from_str(location).unwrap());
*ctx.response_mut().status_mut() = StatusCode::FOUND;
Box::new(()) as Box<dyn ToBytes>
})
}