use {
crate::{
endpoint::{ApplyContext, ApplyError, Endpoint},
error::Error,
extractor::Extractor,
generic::{Combine, Func},
handler::AllowedMethods,
util::{Chain, Never, TryInto},
},
futures01::IntoFuture,
http::Method,
};
pub fn any() -> Builder {
Builder::allow_any()
}
pub fn allow_only(methods: impl TryInto<AllowedMethods>) -> super::Result<Builder> {
Builder::allow_only(methods)
}
macro_rules! define_builder_with_allowing_sigle_method {
($(
$(#[$m:meta])*
$name:ident => $METHOD:ident,
)*) => {$(
$(#[$m])*
pub fn $name() -> Builder {
Builder {
extractor: (),
allowed_methods: Some(Method::$METHOD.into()),
}
}
)*}
}
define_builder_with_allowing_sigle_method! {
get => GET,
post => POST,
put => PUT,
delete => DELETE,
head => HEAD,
options => OPTIONS,
connect => CONNECT,
patch => PATCH,
trace => TRACE,
}
pub fn get_or_head() -> Builder {
Builder::allow_only(vec![Method::GET, Method::HEAD]).expect("should be valid methods")
}
#[derive(Debug)]
pub struct Builder<E: Extractor = ()> {
extractor: E,
allowed_methods: Option<AllowedMethods>,
}
impl Builder {
pub fn allow_any() -> Self {
Self {
extractor: (),
allowed_methods: None,
}
}
pub fn allow_only(methods: impl TryInto<AllowedMethods>) -> super::Result<Self> {
Ok(Self {
extractor: (),
allowed_methods: methods.try_into().map(Some).map_err(super::Error::custom)?,
})
}
}
impl<E> Builder<E>
where
E: Extractor,
{
pub fn extract<E2>(self, other: E2) -> Builder<Chain<E, E2>>
where
E2: Extractor,
E::Output: Combine<E2::Output>,
{
Builder {
extractor: Chain::new(self.extractor, other),
allowed_methods: self.allowed_methods,
}
}
pub fn call<T, F>(
self,
f: F,
) -> impl Endpoint<
T,
Output = F::Out,
Error = E::Error,
Future = self::call::CallFuture<E, F, T>, >
where
T: Combine<E::Output>,
F: Func<<T as Combine<E::Output>>::Out> + Clone,
{
let apply_fn = {
let allowed_methods = self.allowed_methods.clone();
let extractor = self.extractor;
move |args: T, cx: &mut ApplyContext<'_, '_>| {
if allowed_methods
.as_ref()
.map_or(false, |methods| !methods.contains(cx.method()))
{
return Err((args, ApplyError::method_not_allowed()));
}
Ok(self::call::CallFuture {
extract: extractor.extract(),
f: f.clone(),
args: Some(args),
})
}
};
crate::endpoint::endpoint(apply_fn, self.allowed_methods)
}
pub fn call_async<T, F, R>(
self,
f: F,
) -> impl Endpoint<
T,
Output = R::Item,
Error = Error,
Future = self::call_async::CallAsyncFuture<E, F, R, T>, >
where
T: Combine<E::Output>,
F: Func<<T as Combine<E::Output>>::Out, Out = R> + Clone,
R: IntoFuture,
R::Error: Into<Error>,
{
let apply_fn = {
let allowed_methods = self.allowed_methods.clone();
let extractor = self.extractor;
move |args: T, cx: &mut ApplyContext<'_, '_>| {
if allowed_methods
.as_ref()
.map_or(false, |methods| !methods.contains(cx.method()))
{
return Err((args, ApplyError::method_not_allowed()));
}
Ok(self::call_async::CallAsyncFuture {
state: self::call_async::State::First(extractor.extract()),
f: f.clone(),
args: Some(args),
})
}
};
crate::endpoint::endpoint(apply_fn, self.allowed_methods)
}
}
impl<E> Builder<E>
where
E: Extractor<Output = ()>,
{
pub fn reply<R>(
self,
output: R,
) -> impl Endpoint<
(), Output = R,
Error = E::Error,
Future = self::call::CallFuture<E, impl Func<(), Out = R>, ()>, >
where
R: Clone,
{
self.call(move || output.clone())
}
}
#[inline]
pub fn call<T, F>(
f: F,
) -> impl Endpoint<
T, Output = F::Out,
Error = Never,
Future = self::call::CallFuture<(), F, T>, >
where
T: Combine<()>,
F: Func<<T as Combine<()>>::Out> + Clone,
{
any().call(f)
}
pub fn call_async<T, F, R>(
f: F,
) -> impl Endpoint<
T,
Output = R::Item,
Error = Error,
Future = self::call_async::CallAsyncFuture<(), F, R, T>, >
where
T: Combine<()>,
F: Func<<T as Combine<()>>::Out, Out = R> + Clone,
R: IntoFuture,
R::Error: Into<Error>,
{
any().call_async(f)
}
#[inline]
pub fn reply<R>(
output: R,
) -> impl Endpoint<
(), Output = R,
Error = Never,
Future = self::call::CallFuture<(), impl Func<(), Out = R>, ()>,
>
where
R: Clone,
{
any().reply(output)
}
mod call {
use crate::{
extractor::Extractor,
future::{Async, Poll, TryFuture},
generic::{Combine, Func},
input::Input,
};
#[allow(missing_debug_implementations)]
pub struct CallFuture<E: Extractor, F, T> {
pub(super) extract: E::Extract,
pub(super) f: F,
pub(super) args: Option<T>,
}
impl<E, F, T> TryFuture for CallFuture<E, F, T>
where
E: Extractor,
F: Func<<T as Combine<E::Output>>::Out>,
T: Combine<E::Output>,
{
type Ok = F::Out;
type Error = E::Error;
fn poll_ready(&mut self, input: &mut Input<'_>) -> Poll<Self::Ok, Self::Error> {
let args2 = futures01::try_ready!(self.extract.poll_ready(input));
let args = self
.args
.take()
.expect("the future has already been polled.");
Ok(Async::Ready(self.f.call(args.combine(args2))))
}
}
}
mod call_async {
use {
crate::{
error::Error,
extractor::Extractor,
future::{Poll, TryFuture},
generic::{Combine, Func},
input::Input,
},
futures01::{Future, IntoFuture},
};
#[allow(missing_debug_implementations)]
pub(super) enum State<Fut1, Fut2> {
First(Fut1),
Second(Fut2),
}
#[allow(missing_debug_implementations)]
pub struct CallAsyncFuture<E: Extractor, F, R: IntoFuture, T> {
pub(super) state: State<E::Extract, R::Future>,
pub(super) f: F,
pub(super) args: Option<T>,
}
impl<E, F, R, T> TryFuture for CallAsyncFuture<E, F, R, T>
where
E: Extractor,
F: Func<<T as Combine<E::Output>>::Out, Out = R>,
R: IntoFuture,
R::Error: Into<Error>,
T: Combine<E::Output>,
{
type Ok = R::Item;
type Error = Error;
fn poll_ready(&mut self, input: &mut Input<'_>) -> Poll<Self::Ok, Self::Error> {
loop {
self.state = match self.state {
State::First(ref mut extract) => {
let args2 =
futures01::try_ready!(extract.poll_ready(input).map_err(Into::into));
let args = self
.args
.take()
.expect("the future has already been polled.");
State::Second(self.f.call(args.combine(args2)).into_future())
}
State::Second(ref mut action) => return action.poll().map_err(Into::into),
};
}
}
}
}