#![warn(missing_docs)]
#[cfg(test)]
#[macro_use]
extern crate maplit;
pub use http::{self, Response};
pub use lambda_runtime::{self, Context};
use lambda_runtime::{Error, Handler as LambdaHandler};
mod body;
pub mod ext;
pub mod request;
#[doc(hidden)]
pub mod response;
mod strmap;
pub use crate::{body::Body, ext::RequestExt, response::IntoResponse, strmap::StrMap};
use crate::{
request::{LambdaRequest, RequestOrigin},
response::LambdaResponse,
};
use std::{
future::Future,
pin::Pin,
task::{Context as TaskContext, Poll},
};
pub type Request = http::Request<Body>;
pub trait Handler: Sized {
type Error;
type Response: IntoResponse;
type Fut: Future<Output = Result<Self::Response, Self::Error>> + Send + 'static;
fn call(&self, event: Request, context: Context) -> Self::Fut;
}
pub fn handler<H: Handler>(handler: H) -> Adapter<H> {
Adapter { handler }
}
impl<F, R, Fut> Handler for F
where
F: Fn(Request, Context) -> Fut,
R: IntoResponse,
Fut: Future<Output = Result<R, Error>> + Send + 'static,
{
type Response = R;
type Error = Error;
type Fut = Fut;
fn call(&self, event: Request, context: Context) -> Self::Fut {
(self)(event, context)
}
}
#[doc(hidden)]
pub struct TransformResponse<R, E> {
request_origin: RequestOrigin,
fut: Pin<Box<dyn Future<Output = Result<R, E>> + Send>>,
}
impl<R, E> Future for TransformResponse<R, E>
where
R: IntoResponse,
{
type Output = Result<LambdaResponse, E>;
fn poll(mut self: Pin<&mut Self>, cx: &mut TaskContext) -> Poll<Self::Output> {
match self.fut.as_mut().poll(cx) {
Poll::Ready(result) => Poll::Ready(
result.map(|resp| LambdaResponse::from_response(&self.request_origin, resp.into_response())),
),
Poll::Pending => Poll::Pending,
}
}
}
pub struct Adapter<H: Handler> {
handler: H,
}
impl<H: Handler> Handler for Adapter<H> {
type Response = H::Response;
type Error = H::Error;
type Fut = H::Fut;
fn call(&self, event: Request, context: Context) -> Self::Fut {
self.handler.call(event, context)
}
}
impl<H: Handler> LambdaHandler<LambdaRequest<'_>, LambdaResponse> for Adapter<H> {
type Error = H::Error;
type Fut = TransformResponse<H::Response, Self::Error>;
fn call(&self, event: LambdaRequest<'_>, context: Context) -> Self::Fut {
let request_origin = event.request_origin();
let fut = Box::pin(self.handler.call(event.into(), context));
TransformResponse { request_origin, fut }
}
}