1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
use lunatic::function::reference::Fn as FnPtr;
use lunatic::function::FuncRef;
use serde::de::DeserializeOwned;
use serde::Serialize;
use crate::extract::{FromOwnedRequest, FromRequest};
use crate::response::IntoResponse;
use crate::{RequestContext, Response};
/// Implemented for process-safe [`Handlers`](Handler).
///
/// Submillisecond handles every request in a separate lunatic process, and
/// lunatic's processes are sandboxed. This means that no memory is shared
/// between the request handler and the rest of the app. This introduces an
/// additional limitation on what can be a [`Handler`].
///
/// Two kinds of types are safe to be used as handlers:
/// - Static functions
/// - Serializable and clonable objects
///
/// ### Static functions
///
/// This type is obvious. Non-capturing functions are generated during compile
/// time and are shared between all processes, so they can be easily used as
/// handlers. In fact, the [`router!`](crate::router) macro will in the end just
/// generate a function that will be used as a handler and invoke other handlers
/// depending on the request values.
///
/// ### Serializable and clonable objects
///
/// Everything else needs to be passed somehow to the memory of the handler
/// process. This means that we need to clone the value for every incoming
/// request, serialize it and send it to the process handling the request.
pub trait ProcessSafeHandler<Kind, Arg, Ret> {
/// A handler is only safe if it can be cloned and safely sent between
/// processes.
type SafeHandler: Handler<Arg, Ret> + Clone + Serialize + DeserializeOwned;
/// Turn type into a safe handler.
fn safe_handler(self) -> Self::SafeHandler;
}
/// Marker type for functions that satisfy [`ProcessSafeHandler`].
pub struct Function;
/// Marker type for objects that satisfy [`ProcessSafeHandler`].
pub struct Object;
impl<T, Arg, Ret> ProcessSafeHandler<Function, Arg, Ret> for T
where
T: FnPtr<T> + Copy,
FuncRef<T>: Handler<Arg, Ret>,
{
type SafeHandler = FuncRef<T>;
fn safe_handler(self) -> Self::SafeHandler {
FuncRef::new(self)
}
}
impl<T, Arg, Ret> ProcessSafeHandler<Object, Arg, Ret> for T
where
T: Clone + Handler<Arg, Ret> + Serialize + DeserializeOwned,
{
type SafeHandler = T;
fn safe_handler(self) -> Self::SafeHandler {
self
}
}
impl<T, Arg, Ret> Handler<Arg, Ret> for FuncRef<T>
where
T: FnPtr<T> + Copy + Handler<Arg, Ret>,
{
fn handle(&self, req: RequestContext) -> Response {
self.get().handle(req)
}
}
/// A handler is implemented for any function which takes any number of
/// [extractors](crate::extract), and returns any type that implements
/// [`IntoResponse`].
///
/// To avoid unnecessary clones, the [`RequestContext`], [`http::Request`],
/// [`String`], [`Vec<u8>`], [`Params`](crate::params::Params) extractors (and
/// any other types which implement [`FromOwnedRequest`] directly) should be
/// placed as the first argument, and cannot be used together in a single
/// handler.
///
/// A maximum of 16 extractor arguments may be added for a single handler.
///
/// # Handler examples
///
/// ```
/// fn index() -> &'static str {
/// "Hello, submillisecond"
/// }
///
/// use submillisecond::extract::Path;
/// use submillisecond::http::status::FOUND;
///
/// fn headers(Path(id): Path<String>) -> (StatusCode, String) {
/// (FOUND, id)
/// }
/// ```
///
/// # Middleware example
///
/// ```
/// use submillisecond::RequestContent;
/// use submillisecond::response::Response;
///
/// fn logging_layer(req: RequestContext) -> Response {
/// println!("Incoming request start");
/// let res = req.next_handler();
/// println!("Incoming request end");
/// res
/// }
/// ```
pub trait Handler<Arg = (), Ret = ()> {
/// Handles the request, returning a response.
fn handle(&self, req: RequestContext) -> Response;
/// Initializes handler, useful for spawning processes on startup.
fn init(&self) {}
}
impl<F, R> Handler<(), R> for F
where
F: Fn() -> R,
R: IntoResponse,
{
fn handle(&self, _req: RequestContext) -> Response {
self().into_response()
}
}
macro_rules! impl_handler {
( $arg1: ident $(, $( $args: ident ),*)? ) => {
#[allow(unused_parens)]
impl<F, $arg1, $( $( $args, )*)? R> Handler<($arg1$(, $( $args, )*)?), R> for F
where
F: Fn($arg1$(, $( $args, )*)?) -> R,
$arg1: FromOwnedRequest,
$( $( $args: FromRequest, )* )?
R: IntoResponse,
{
#[allow(unused_mut, unused_variables)]
fn handle(&self, mut req: RequestContext) -> Response {
paste::paste! {
$($(
let [< $args:lower >] = match <$args as FromRequest>::from_request(&mut req) {
Ok(e) => e,
Err(err) => return err.into_response(),
};
)*)?
let e1 = match <$arg1 as FromOwnedRequest>::from_owned_request(req) {
Ok(e) => e,
Err(err) => return err.into_response(),
};
self(e1 $(, $( [< $args:lower >] ),*)?).into_response()
}
}
}
};
}
all_the_tuples!(impl_handler);