mirror of https://github.com/fafhrd91/actix-web
optimize Route guards
This commit is contained in:
parent
1c95fc2654
commit
b187851a32
43
src/guard.rs
43
src/guard.rs
|
@ -38,6 +38,9 @@ use actix_http::RequestHead;
|
||||||
pub trait Guard {
|
pub trait Guard {
|
||||||
/// Check if request matches predicate
|
/// Check if request matches predicate
|
||||||
fn check(&self, request: &RequestHead) -> bool;
|
fn check(&self, request: &RequestHead) -> bool;
|
||||||
|
|
||||||
|
/// Clone self into a new boxed guard.
|
||||||
|
fn clone_guard(&self) -> Box<dyn Guard>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create guard object for supplied function.
|
/// Create guard object for supplied function.
|
||||||
|
@ -58,29 +61,37 @@ pub trait Guard {
|
||||||
/// ```
|
/// ```
|
||||||
pub fn fn_guard<F>(f: F) -> impl Guard
|
pub fn fn_guard<F>(f: F) -> impl Guard
|
||||||
where
|
where
|
||||||
F: Fn(&RequestHead) -> bool,
|
F: Fn(&RequestHead) -> bool + Clone + 'static,
|
||||||
{
|
{
|
||||||
FnGuard(f)
|
FnGuard(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FnGuard<F: Fn(&RequestHead) -> bool>(F);
|
struct FnGuard<F: Fn(&RequestHead) -> bool + Clone>(F);
|
||||||
|
|
||||||
impl<F> Guard for FnGuard<F>
|
impl<F> Guard for FnGuard<F>
|
||||||
where
|
where
|
||||||
F: Fn(&RequestHead) -> bool,
|
F: Fn(&RequestHead) -> bool + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn check(&self, head: &RequestHead) -> bool {
|
fn check(&self, head: &RequestHead) -> bool {
|
||||||
(self.0)(head)
|
(self.0)(head)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clone_guard(&self) -> Box<dyn Guard> {
|
||||||
|
Box::new(FnGuard(self.0.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> Guard for F
|
impl<F> Guard for F
|
||||||
where
|
where
|
||||||
F: Fn(&RequestHead) -> bool,
|
F: Fn(&RequestHead) -> bool + Clone + 'static,
|
||||||
{
|
{
|
||||||
fn check(&self, head: &RequestHead) -> bool {
|
fn check(&self, head: &RequestHead) -> bool {
|
||||||
(self)(head)
|
(self)(head)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clone_guard(&self) -> Box<dyn Guard> {
|
||||||
|
Box::new(FnGuard(self.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return guard that matches if any of supplied guards.
|
/// Return guard that matches if any of supplied guards.
|
||||||
|
@ -120,6 +131,10 @@ impl Guard for AnyGuard {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clone_guard(&self) -> Box<dyn Guard> {
|
||||||
|
Box::new(AnyGuard(self.0.iter().map(|g| g.clone_guard()).collect()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return guard that matches if all of the supplied guards.
|
/// Return guard that matches if all of the supplied guards.
|
||||||
|
@ -160,6 +175,10 @@ impl Guard for AllGuard {
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clone_guard(&self) -> Box<dyn Guard> {
|
||||||
|
Box::new(AllGuard(self.0.iter().map(|g| g.clone_guard()).collect()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return guard that matches if supplied guard does not match.
|
/// Return guard that matches if supplied guard does not match.
|
||||||
|
@ -174,6 +193,10 @@ impl Guard for NotGuard {
|
||||||
fn check(&self, request: &RequestHead) -> bool {
|
fn check(&self, request: &RequestHead) -> bool {
|
||||||
!self.0.check(request)
|
!self.0.check(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clone_guard(&self) -> Box<dyn Guard> {
|
||||||
|
self.0.clone_guard()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Http method guard
|
/// Http method guard
|
||||||
|
@ -184,6 +207,10 @@ impl Guard for MethodGuard {
|
||||||
fn check(&self, request: &RequestHead) -> bool {
|
fn check(&self, request: &RequestHead) -> bool {
|
||||||
request.method == self.0
|
request.method == self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clone_guard(&self) -> Box<dyn Guard> {
|
||||||
|
Box::new(MethodGuard(self.0.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Guard to match *GET* http method
|
/// Guard to match *GET* http method
|
||||||
|
@ -255,6 +282,10 @@ impl Guard for HeaderGuard {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clone_guard(&self) -> Box<dyn Guard> {
|
||||||
|
Box::new(HeaderGuard(self.0.clone(), self.1.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return predicate that matches if request contains specified Host name.
|
/// Return predicate that matches if request contains specified Host name.
|
||||||
|
@ -319,6 +350,10 @@ impl Guard for HostGuard {
|
||||||
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clone_guard(&self) -> Box<dyn Guard> {
|
||||||
|
Box::new(HostGuard(self.0.clone(), self.1.clone()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
25
src/route.rs
25
src/route.rs
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::task::{Context, Poll};
|
use std::task::{Context, Poll};
|
||||||
|
|
||||||
use actix_http::{http::Method, Error};
|
use actix_http::{http::Method, Error};
|
||||||
|
@ -43,7 +42,7 @@ type BoxedRouteNewService = Box<
|
||||||
/// If handler is not explicitly set, default *404 Not Found* handler is used.
|
/// If handler is not explicitly set, default *404 Not Found* handler is used.
|
||||||
pub struct Route {
|
pub struct Route {
|
||||||
service: BoxedRouteNewService,
|
service: BoxedRouteNewService,
|
||||||
guards: Rc<Vec<Box<dyn Guard>>>,
|
guards: Vec<Box<dyn Guard>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Route {
|
impl Route {
|
||||||
|
@ -54,34 +53,34 @@ impl Route {
|
||||||
service: Box::new(RouteNewService::new(HandlerService::new(|| {
|
service: Box::new(RouteNewService::new(HandlerService::new(|| {
|
||||||
ready(HttpResponse::NotFound())
|
ready(HttpResponse::NotFound())
|
||||||
}))),
|
}))),
|
||||||
guards: Rc::new(Vec::new()),
|
guards: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn take_guards(&mut self) -> Vec<Box<dyn Guard>> {
|
pub(crate) fn take_guards(&mut self) -> Vec<Box<dyn Guard>> {
|
||||||
std::mem::take(Rc::get_mut(&mut self.guards).unwrap())
|
std::mem::take(&mut self.guards)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceFactory<ServiceRequest> for Route {
|
impl ServiceFactory<ServiceRequest> for Route {
|
||||||
type Config = ();
|
|
||||||
type Response = ServiceResponse;
|
type Response = ServiceResponse;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
type InitError = ();
|
type Config = ();
|
||||||
type Service = RouteService;
|
type Service = RouteService;
|
||||||
|
type InitError = ();
|
||||||
type Future = CreateRouteService;
|
type Future = CreateRouteService;
|
||||||
|
|
||||||
fn new_service(&self, _: ()) -> Self::Future {
|
fn new_service(&self, _: ()) -> Self::Future {
|
||||||
CreateRouteService {
|
CreateRouteService {
|
||||||
fut: self.service.new_service(()),
|
fut: self.service.new_service(()),
|
||||||
guards: self.guards.clone(),
|
guards: self.guards.iter().map(|g| g.clone_guard()).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CreateRouteService {
|
pub struct CreateRouteService {
|
||||||
fut: LocalBoxFuture<'static, Result<BoxedRouteService, ()>>,
|
fut: LocalBoxFuture<'static, Result<BoxedRouteService, ()>>,
|
||||||
guards: Rc<Vec<Box<dyn Guard>>>,
|
guards: Vec<Box<dyn Guard>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for CreateRouteService {
|
impl Future for CreateRouteService {
|
||||||
|
@ -93,7 +92,7 @@ impl Future for CreateRouteService {
|
||||||
match this.fut.as_mut().poll(cx)? {
|
match this.fut.as_mut().poll(cx)? {
|
||||||
Poll::Ready(service) => Poll::Ready(Ok(RouteService {
|
Poll::Ready(service) => Poll::Ready(Ok(RouteService {
|
||||||
service,
|
service,
|
||||||
guards: this.guards.clone(),
|
guards: std::mem::take(&mut this.guards),
|
||||||
})),
|
})),
|
||||||
Poll::Pending => Poll::Pending,
|
Poll::Pending => Poll::Pending,
|
||||||
}
|
}
|
||||||
|
@ -102,7 +101,7 @@ impl Future for CreateRouteService {
|
||||||
|
|
||||||
pub struct RouteService {
|
pub struct RouteService {
|
||||||
service: BoxedRouteService,
|
service: BoxedRouteService,
|
||||||
guards: Rc<Vec<Box<dyn Guard>>>,
|
guards: Vec<Box<dyn Guard>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RouteService {
|
impl RouteService {
|
||||||
|
@ -145,9 +144,7 @@ impl Route {
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn method(mut self, method: Method) -> Self {
|
pub fn method(mut self, method: Method) -> Self {
|
||||||
Rc::get_mut(&mut self.guards)
|
self.guards.push(Box::new(guard::Method(method)));
|
||||||
.unwrap()
|
|
||||||
.push(Box::new(guard::Method(method)));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +162,7 @@ impl Route {
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn guard<F: Guard + 'static>(mut self, f: F) -> Self {
|
pub fn guard<F: Guard + 'static>(mut self, f: F) -> Self {
|
||||||
Rc::get_mut(&mut self.guards).unwrap().push(Box::new(f));
|
self.guards.push(Box::new(f));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue