mirror of
https://github.com/actix/actix-extras.git
synced 2025-06-25 09:59:21 +02:00
allow to use fn with multiple arguments with .with()/.with_async()
This commit is contained in:
@ -12,6 +12,7 @@ use resource::Resource;
|
||||
use router::{ResourceDef, Router};
|
||||
use scope::Scope;
|
||||
use server::{HttpHandler, HttpHandlerTask, IntoHttpHandler, Request};
|
||||
use with::WithFactory;
|
||||
|
||||
/// Application
|
||||
pub struct HttpApplication<S = ()> {
|
||||
@ -249,7 +250,7 @@ where
|
||||
/// ```
|
||||
pub fn route<T, F, R>(mut self, path: &str, method: Method, f: F) -> App<S>
|
||||
where
|
||||
F: Fn(T) -> R + 'static,
|
||||
F: WithFactory<T, S, R>,
|
||||
R: Responder + 'static,
|
||||
T: FromRequest<S> + 'static,
|
||||
{
|
||||
|
@ -332,7 +332,7 @@ impl<T: fmt::Display> fmt::Display for Form<T> {
|
||||
/// |r| {
|
||||
/// r.method(http::Method::GET)
|
||||
/// // register form handler and change form extractor configuration
|
||||
/// .with_config(index, |cfg| {cfg.limit(4096);})
|
||||
/// .with_config(index, |cfg| {cfg.0.limit(4096);})
|
||||
/// },
|
||||
/// );
|
||||
/// }
|
||||
@ -427,7 +427,7 @@ impl<S: 'static> FromRequest<S> for Bytes {
|
||||
/// let app = App::new().resource("/index.html", |r| {
|
||||
/// r.method(http::Method::GET)
|
||||
/// .with_config(index, |cfg| { // <- register handler with extractor params
|
||||
/// cfg.limit(4096); // <- limit size of the payload
|
||||
/// cfg.0.limit(4096); // <- limit size of the payload
|
||||
/// })
|
||||
/// });
|
||||
/// }
|
||||
|
@ -172,7 +172,7 @@ where
|
||||
/// let app = App::new().resource("/index.html", |r| {
|
||||
/// r.method(http::Method::POST)
|
||||
/// .with_config(index, |cfg| {
|
||||
/// cfg.limit(4096) // <- change json extractor configuration
|
||||
/// cfg.0.limit(4096) // <- change json extractor configuration
|
||||
/// .error_handler(|err, req| { // <- create custom error response
|
||||
/// error::InternalError::from_response(
|
||||
/// err, HttpResponse::Conflict().finish()).into()
|
||||
|
@ -13,6 +13,7 @@ use middleware::Middleware;
|
||||
use pred;
|
||||
use route::Route;
|
||||
use router::ResourceDef;
|
||||
use with::WithFactory;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct RouteId(usize);
|
||||
@ -217,7 +218,7 @@ impl<S: 'static> Resource<S> {
|
||||
/// ```
|
||||
pub fn with<T, F, R>(&mut self, handler: F)
|
||||
where
|
||||
F: Fn(T) -> R + 'static,
|
||||
F: WithFactory<T, S, R>,
|
||||
R: Responder + 'static,
|
||||
T: FromRequest<S> + 'static,
|
||||
{
|
||||
|
27
src/route.rs
27
src/route.rs
@ -16,7 +16,7 @@ use middleware::{
|
||||
Started as MiddlewareStarted,
|
||||
};
|
||||
use pred::Predicate;
|
||||
use with::{With, WithAsync};
|
||||
use with::{WithAsyncFactory, WithFactory};
|
||||
|
||||
/// Resource route definition
|
||||
///
|
||||
@ -166,15 +166,15 @@ impl<S: 'static> Route<S> {
|
||||
/// ```
|
||||
pub fn with<T, F, R>(&mut self, handler: F)
|
||||
where
|
||||
F: Fn(T) -> R + 'static,
|
||||
F: WithFactory<T, S, R> + 'static,
|
||||
R: Responder + 'static,
|
||||
T: FromRequest<S> + 'static,
|
||||
{
|
||||
self.h(With::new(handler, <T::Config as Default>::default()));
|
||||
self.h(handler.create());
|
||||
}
|
||||
|
||||
/// Set handler function. Same as `.with()` but it allows to configure
|
||||
/// extractor.
|
||||
/// extractor. Configuration closure accepts config objects as tuple.
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate bytes;
|
||||
@ -192,21 +192,21 @@ impl<S: 'static> Route<S> {
|
||||
/// let app = App::new().resource("/index.html", |r| {
|
||||
/// r.method(http::Method::GET)
|
||||
/// .with_config(index, |cfg| { // <- register handler
|
||||
/// cfg.limit(4096); // <- limit size of the payload
|
||||
/// cfg.0.limit(4096); // <- limit size of the payload
|
||||
/// })
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
pub fn with_config<T, F, R, C>(&mut self, handler: F, cfg_f: C)
|
||||
where
|
||||
F: Fn(T) -> R + 'static,
|
||||
F: WithFactory<T, S, R>,
|
||||
R: Responder + 'static,
|
||||
T: FromRequest<S> + 'static,
|
||||
C: FnOnce(&mut T::Config),
|
||||
{
|
||||
let mut cfg = <T::Config as Default>::default();
|
||||
cfg_f(&mut cfg);
|
||||
self.h(With::new(handler, cfg));
|
||||
self.h(handler.create_with_config(cfg));
|
||||
}
|
||||
|
||||
/// Set async handler function, use request extractor for parameters.
|
||||
@ -240,17 +240,18 @@ impl<S: 'static> Route<S> {
|
||||
/// ```
|
||||
pub fn with_async<T, F, R, I, E>(&mut self, handler: F)
|
||||
where
|
||||
F: Fn(T) -> R + 'static,
|
||||
F: WithAsyncFactory<T, S, R, I, E>,
|
||||
R: Future<Item = I, Error = E> + 'static,
|
||||
I: Responder + 'static,
|
||||
E: Into<Error> + 'static,
|
||||
T: FromRequest<S> + 'static,
|
||||
{
|
||||
self.h(WithAsync::new(handler, <T::Config as Default>::default()));
|
||||
self.h(handler.create());
|
||||
}
|
||||
|
||||
/// Set async handler function, use request extractor for parameters.
|
||||
/// This method allows to configure extractor.
|
||||
/// This method allows to configure extractor. Configuration closure
|
||||
/// accepts config objects as tuple.
|
||||
///
|
||||
/// ```rust
|
||||
/// # extern crate bytes;
|
||||
@ -275,14 +276,14 @@ impl<S: 'static> Route<S> {
|
||||
/// "/{username}/index.html", // <- define path parameters
|
||||
/// |r| r.method(http::Method::GET)
|
||||
/// .with_async_config(index, |cfg| {
|
||||
/// cfg.limit(4096);
|
||||
/// cfg.0.limit(4096);
|
||||
/// }),
|
||||
/// ); // <- use `with` extractor
|
||||
/// }
|
||||
/// ```
|
||||
pub fn with_async_config<T, F, R, I, E, C>(&mut self, handler: F, cfg: C)
|
||||
where
|
||||
F: Fn(T) -> R + 'static,
|
||||
F: WithAsyncFactory<T, S, R, I, E>,
|
||||
R: Future<Item = I, Error = E> + 'static,
|
||||
I: Responder + 'static,
|
||||
E: Into<Error> + 'static,
|
||||
@ -291,7 +292,7 @@ impl<S: 'static> Route<S> {
|
||||
{
|
||||
let mut extractor_cfg = <T::Config as Default>::default();
|
||||
cfg(&mut extractor_cfg);
|
||||
self.h(WithAsync::new(handler, extractor_cfg));
|
||||
self.h(handler.create_with_config(extractor_cfg));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ use pred::Predicate;
|
||||
use resource::{DefaultResource, Resource};
|
||||
use scope::Scope;
|
||||
use server::Request;
|
||||
use with::WithFactory;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub(crate) enum ResourceId {
|
||||
@ -398,7 +399,7 @@ impl<S: 'static> Router<S> {
|
||||
|
||||
pub(crate) fn register_route<T, F, R>(&mut self, path: &str, method: Method, f: F)
|
||||
where
|
||||
F: Fn(T) -> R + 'static,
|
||||
F: WithFactory<T, S, R>,
|
||||
R: Responder + 'static,
|
||||
T: FromRequest<S> + 'static,
|
||||
{
|
||||
|
@ -17,6 +17,7 @@ use pred::Predicate;
|
||||
use resource::{DefaultResource, Resource};
|
||||
use router::{ResourceDef, Router};
|
||||
use server::Request;
|
||||
use with::WithFactory;
|
||||
|
||||
/// Resources scope
|
||||
///
|
||||
@ -222,7 +223,7 @@ impl<S: 'static> Scope<S> {
|
||||
/// ```
|
||||
pub fn route<T, F, R>(mut self, path: &str, method: Method, f: F) -> Scope<S>
|
||||
where
|
||||
F: Fn(T) -> R + 'static,
|
||||
F: WithFactory<T, S, R>,
|
||||
R: Responder + 'static,
|
||||
T: FromRequest<S> + 'static,
|
||||
{
|
||||
|
156
src/with.rs
156
src/with.rs
@ -7,24 +7,74 @@ use handler::{AsyncResult, AsyncResultItem, FromRequest, Handler, Responder};
|
||||
use httprequest::HttpRequest;
|
||||
use httpresponse::HttpResponse;
|
||||
|
||||
pub(crate) struct With<T, S, F, R>
|
||||
trait FnWith<T, R>: 'static {
|
||||
fn call_with(self: &Self, T) -> R;
|
||||
}
|
||||
|
||||
impl<T, R, F: Fn(T) -> R + 'static> FnWith<T, R> for F {
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(boxed_local))]
|
||||
fn call_with(self: &Self, arg: T) -> R {
|
||||
(*self)(arg)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait WithFactory<T, S, R>: 'static
|
||||
where T: FromRequest<S>,
|
||||
R: Responder,
|
||||
{
|
||||
fn create(self) -> With<T, S, R>;
|
||||
|
||||
fn create_with_config(self, T::Config) -> With<T, S, R>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait WithAsyncFactory<T, S, R, I, E>: 'static
|
||||
where T: FromRequest<S>,
|
||||
R: Future<Item=I, Error=E>,
|
||||
I: Responder,
|
||||
E: Into<Error>,
|
||||
{
|
||||
fn create(self) -> WithAsync<T, S, R, I, E>;
|
||||
|
||||
fn create_with_config(self, T::Config) -> WithAsync<T, S, R, I, E>;
|
||||
}
|
||||
|
||||
// impl<T1, T2, T3, S, F, R> WithFactory<(T1, T2, T3), S, R> for F
|
||||
// where F: Fn(T1, T2, T3) -> R + 'static,
|
||||
// T1: FromRequest<S> + 'static,
|
||||
// T2: FromRequest<S> + 'static,
|
||||
// T3: FromRequest<S> + 'static,
|
||||
// R: Responder + 'static,
|
||||
// S: 'static,
|
||||
// {
|
||||
// fn create(self) -> With<(T1, T2, T3), S, R> {
|
||||
// With::new(move |(t1, t2, t3)| (self)(t1, t2, t3), (
|
||||
// T1::Config::default(), T2::Config::default(), T3::Config::default()))
|
||||
// }
|
||||
|
||||
// fn create_with_config(self, cfg: (T1::Config, T2::Config, T3::Config,)) -> With<(T1, T2, T3), S, R> {
|
||||
// With::new(move |(t1, t2, t3)| (self)(t1, t2, t3), cfg)
|
||||
// }
|
||||
// }
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct With<T, S, R>
|
||||
where
|
||||
F: Fn(T) -> R,
|
||||
T: FromRequest<S>,
|
||||
S: 'static,
|
||||
{
|
||||
hnd: Rc<F>,
|
||||
hnd: Rc<FnWith<T, R>>,
|
||||
cfg: Rc<T::Config>,
|
||||
_s: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<T, S, F, R> With<T, S, F, R>
|
||||
impl<T, S, R> With<T, S, R>
|
||||
where
|
||||
F: Fn(T) -> R,
|
||||
T: FromRequest<S>,
|
||||
S: 'static,
|
||||
{
|
||||
pub fn new(f: F, cfg: T::Config) -> Self {
|
||||
pub fn new<F: Fn(T) -> R + 'static>(f: F, cfg: T::Config) -> Self {
|
||||
With {
|
||||
cfg: Rc::new(cfg),
|
||||
hnd: Rc::new(f),
|
||||
@ -33,9 +83,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, F, R> Handler<S> for With<T, S, F, R>
|
||||
impl<T, S, R> Handler<S> for With<T, S, R>
|
||||
where
|
||||
F: Fn(T) -> R + 'static,
|
||||
R: Responder + 'static,
|
||||
T: FromRequest<S> + 'static,
|
||||
S: 'static,
|
||||
@ -60,24 +109,22 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
struct WithHandlerFut<T, S, F, R>
|
||||
struct WithHandlerFut<T, S, R>
|
||||
where
|
||||
F: Fn(T) -> R,
|
||||
R: Responder,
|
||||
T: FromRequest<S> + 'static,
|
||||
S: 'static,
|
||||
{
|
||||
started: bool,
|
||||
hnd: Rc<F>,
|
||||
hnd: Rc<FnWith<T, R>>,
|
||||
cfg: Rc<T::Config>,
|
||||
req: HttpRequest<S>,
|
||||
fut1: Option<Box<Future<Item = T, Error = Error>>>,
|
||||
fut2: Option<Box<Future<Item = HttpResponse, Error = Error>>>,
|
||||
}
|
||||
|
||||
impl<T, S, F, R> Future for WithHandlerFut<T, S, F, R>
|
||||
impl<T, S, R> Future for WithHandlerFut<T, S, R>
|
||||
where
|
||||
F: Fn(T) -> R,
|
||||
R: Responder + 'static,
|
||||
T: FromRequest<S> + 'static,
|
||||
S: 'static,
|
||||
@ -108,7 +155,7 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
let item = match (*self.hnd)(item).respond_to(&self.req) {
|
||||
let item = match self.hnd.as_ref().call_with(item).respond_to(&self.req) {
|
||||
Ok(item) => item.into(),
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
@ -124,30 +171,29 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WithAsync<T, S, F, R, I, E>
|
||||
#[doc(hidden)]
|
||||
pub struct WithAsync<T, S, R, I, E>
|
||||
where
|
||||
F: Fn(T) -> R,
|
||||
R: Future<Item = I, Error = E>,
|
||||
I: Responder,
|
||||
E: Into<E>,
|
||||
T: FromRequest<S>,
|
||||
S: 'static,
|
||||
{
|
||||
hnd: Rc<F>,
|
||||
hnd: Rc<FnWith<T, R>>,
|
||||
cfg: Rc<T::Config>,
|
||||
_s: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<T, S, F, R, I, E> WithAsync<T, S, F, R, I, E>
|
||||
impl<T, S, R, I, E> WithAsync<T, S, R, I, E>
|
||||
where
|
||||
F: Fn(T) -> R,
|
||||
R: Future<Item = I, Error = E>,
|
||||
I: Responder,
|
||||
E: Into<Error>,
|
||||
T: FromRequest<S>,
|
||||
S: 'static,
|
||||
{
|
||||
pub fn new(f: F, cfg: T::Config) -> Self {
|
||||
pub fn new<F: Fn(T) -> R + 'static>(f: F, cfg: T::Config) -> Self {
|
||||
WithAsync {
|
||||
cfg: Rc::new(cfg),
|
||||
hnd: Rc::new(f),
|
||||
@ -156,9 +202,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, F, R, I, E> Handler<S> for WithAsync<T, S, F, R, I, E>
|
||||
impl<T, S, R, I, E> Handler<S> for WithAsync<T, S, R, I, E>
|
||||
where
|
||||
F: Fn(T) -> R + 'static,
|
||||
R: Future<Item = I, Error = E> + 'static,
|
||||
I: Responder + 'static,
|
||||
E: Into<Error> + 'static,
|
||||
@ -186,9 +231,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
struct WithAsyncHandlerFut<T, S, F, R, I, E>
|
||||
struct WithAsyncHandlerFut<T, S, R, I, E>
|
||||
where
|
||||
F: Fn(T) -> R,
|
||||
R: Future<Item = I, Error = E> + 'static,
|
||||
I: Responder + 'static,
|
||||
E: Into<Error> + 'static,
|
||||
@ -196,7 +240,7 @@ where
|
||||
S: 'static,
|
||||
{
|
||||
started: bool,
|
||||
hnd: Rc<F>,
|
||||
hnd: Rc<FnWith<T, R>>,
|
||||
cfg: Rc<T::Config>,
|
||||
req: HttpRequest<S>,
|
||||
fut1: Option<Box<Future<Item = T, Error = Error>>>,
|
||||
@ -204,9 +248,8 @@ where
|
||||
fut3: Option<Box<Future<Item = HttpResponse, Error = Error>>>,
|
||||
}
|
||||
|
||||
impl<T, S, F, R, I, E> Future for WithAsyncHandlerFut<T, S, F, R, I, E>
|
||||
impl<T, S, R, I, E> Future for WithAsyncHandlerFut<T, S, R, I, E>
|
||||
where
|
||||
F: Fn(T) -> R,
|
||||
R: Future<Item = I, Error = E> + 'static,
|
||||
I: Responder + 'static,
|
||||
E: Into<Error> + 'static,
|
||||
@ -257,7 +300,64 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
self.fut2 = Some((*self.hnd)(item));
|
||||
self.fut2 = Some(self.hnd.as_ref().call_with(item));
|
||||
self.poll()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
macro_rules! with_factory_tuple ({$(($n:tt, $T:ident)),+} => {
|
||||
impl<$($T,)+ State, Func, Res> WithFactory<($($T,)+), State, Res> for Func
|
||||
where Func: Fn($($T,)+) -> Res + 'static,
|
||||
$($T: FromRequest<State> + 'static,)+
|
||||
Res: Responder + 'static,
|
||||
State: 'static,
|
||||
{
|
||||
fn create(self) -> With<($($T,)+), State, Res> {
|
||||
With::new(move |($($n,)+)| (self)($($n,)+), ($($T::Config::default(),)+))
|
||||
}
|
||||
|
||||
fn create_with_config(self, cfg: ($($T::Config,)+)) -> With<($($T,)+), State, Res> {
|
||||
With::new(move |($($n,)+)| (self)($($n,)+), cfg)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
macro_rules! with_async_factory_tuple ({$(($n:tt, $T:ident)),+} => {
|
||||
impl<$($T,)+ State, Func, Res, Item, Err> WithAsyncFactory<($($T,)+), State, Res, Item, Err> for Func
|
||||
where Func: Fn($($T,)+) -> Res + 'static,
|
||||
$($T: FromRequest<State> + 'static,)+
|
||||
Res: Future<Item=Item, Error=Err>,
|
||||
Item: Responder + 'static,
|
||||
Err: Into<Error>,
|
||||
State: 'static,
|
||||
{
|
||||
fn create(self) -> WithAsync<($($T,)+), State, Res, Item, Err> {
|
||||
WithAsync::new(move |($($n,)+)| (self)($($n,)+), ($($T::Config::default(),)+))
|
||||
}
|
||||
|
||||
fn create_with_config(self, cfg: ($($T::Config,)+)) -> WithAsync<($($T,)+), State, Res, Item, Err> {
|
||||
WithAsync::new(move |($($n,)+)| (self)($($n,)+), cfg)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
with_factory_tuple!((a, A));
|
||||
with_factory_tuple!((a, A), (b, B));
|
||||
with_factory_tuple!((a, A), (b, B), (c, C));
|
||||
with_factory_tuple!((a, A), (b, B), (c, C), (d, D));
|
||||
with_factory_tuple!((a, A), (b, B), (c, C), (d, D), (e, E));
|
||||
with_factory_tuple!((a, A), (b, B), (c, C), (d, D), (e, E), (f, F));
|
||||
with_factory_tuple!((a, A), (b, B), (c, C), (d, D), (e, E), (f, F), (g, G));
|
||||
with_factory_tuple!((a, A), (b, B), (c, C), (d, D), (e, E), (f, F), (g, G), (h, H));
|
||||
with_factory_tuple!((a, A), (b, B), (c, C), (d, D), (e, E), (f, F), (g, G), (h, H), (i, I));
|
||||
|
||||
with_async_factory_tuple!((a, A));
|
||||
with_async_factory_tuple!((a, A), (b, B));
|
||||
with_async_factory_tuple!((a, A), (b, B), (c, C));
|
||||
with_async_factory_tuple!((a, A), (b, B), (c, C), (d, D));
|
||||
with_async_factory_tuple!((a, A), (b, B), (c, C), (d, D), (e, E));
|
||||
with_async_factory_tuple!((a, A), (b, B), (c, C), (d, D), (e, E), (f, F));
|
||||
with_async_factory_tuple!((a, A), (b, B), (c, C), (d, D), (e, E), (f, F), (g, G));
|
||||
with_async_factory_tuple!((a, A), (b, B), (c, C), (d, D), (e, E), (f, F), (g, G), (h, H));
|
||||
with_async_factory_tuple!((a, A), (b, B), (c, C), (d, D), (e, E), (f, F), (g, G), (h, H), (i, I));
|
||||
|
Reference in New Issue
Block a user