mod into_handler;
pub use self::into_handler::IntoHandler;
use super::{BoxedFPC, FangProcCaller};
use super::{SendOnThreaded, SendOnThreadedFuture, SendSyncOnThreaded};
use crate::{Request, Response};
use std::pin::Pin;
#[cfg(feature = "openapi")]
use crate::openapi;
pub struct Handler {
#[allow(dead_code/* read only in router */)]
pub(crate) proc: BoxedFPC,
#[cfg(feature = "openapi")]
pub(crate) openapi_operation: openapi::Operation,
}
const _: () = {
impl std::fmt::Debug for Handler {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("{handler}")
}
}
};
impl Handler {
pub(crate) fn new(
proc: impl Fn(&mut Request) -> Pin<Box<dyn SendOnThreadedFuture<Response> + '_>>
+ SendSyncOnThreaded
+ 'static,
#[cfg(feature = "openapi")] openapi_operation: openapi::Operation,
) -> Self {
struct HandlerProc<F>(F);
const _: () = {
impl<F> FangProcCaller for HandlerProc<F>
where
F: Fn(&mut Request) -> Pin<Box<dyn SendOnThreadedFuture<Response> + '_>>
+ SendSyncOnThreaded
+ 'static,
{
fn call_bite<'b>(
&'b self,
req: &'b mut Request,
) -> Pin<Box<dyn SendOnThreadedFuture<Response> + 'b>> {
unsafe { std::mem::transmute((self.0)(req)) }
}
}
};
Self {
proc: BoxedFPC::from_proc(HandlerProc(proc)),
#[cfg(feature = "openapi")]
openapi_operation,
}
}
#[cfg(feature = "openapi")]
#[cfg(feature = "__rt__")]
pub(crate) fn to_dummy_owned_for_openapi(&self) -> Self {
Self::new(
|_| Box::pin(async { Response::OK() }),
self.openapi_operation.clone(),
)
}
}
#[cfg(not(feature = "__rt_threaded__"))]
const _: () = {
unsafe impl Send for Handler {}
unsafe impl Sync for Handler {}
};
#[cfg(feature = "__rt__")]
impl Handler {
pub(crate) fn default_not_found() -> Self {
Handler::new(
|_| Box::pin(async { Response::NotFound() }),
#[cfg(feature = "openapi")]
openapi::Operation::with(openapi::Responses::new([(
404,
openapi::Response::when("default not found"),
)])),
)
}
pub(crate) fn default_options_with(available_methods: Vec<&'static str>) -> Self {
let available_methods = {
let mut methods = available_methods;
if methods.contains(&"GET") {
methods.push("HEAD")
}
methods.push("OPTIONS");
methods
};
let available_methods_str: &'static str = available_methods.join(", ").leak();
Handler::new(
move |req| {
#[cfg(debug_assertions)]
{
assert_eq!(req.method, crate::Method::OPTIONS);
}
let response = match req.headers.access_control_request_method() {
Some(method) => {
let response = if available_methods.contains(&method) {
crate::Response::NotImplemented()
} else {
crate::Response::BadRequest()
};
response
.with_headers(|h| h.access_control_allow_methods(available_methods_str))
}
None => {
crate::Response::NotFound()
}
};
Box::pin(core::future::ready(response))
},
#[cfg(feature = "openapi")]
openapi::Operation::with(openapi::Responses::new([
])),
)
}
}
#[cfg(feature = "openapi")]
impl Handler {
pub fn map_openapi_operation(
mut self,
map: impl FnOnce(openapi::Operation) -> openapi::Operation,
) -> Self {
self.openapi_operation = map(self.openapi_operation);
self
}
}