From b187851a32574176c820ef3ed0ef653250f7995e Mon Sep 17 00:00:00 2001 From: fakeshadow <24548779@qq.com> Date: Sun, 17 Jan 2021 10:11:08 +0800 Subject: [PATCH] optimize Route guards --- src/guard.rs | 43 +++++++++++++++++++++++++++++++++++++++---- src/route.rs | 25 +++++++++++-------------- 2 files changed, 50 insertions(+), 18 deletions(-) diff --git a/src/guard.rs b/src/guard.rs index ba0cbea85..0482aeb87 100644 --- a/src/guard.rs +++ b/src/guard.rs @@ -38,6 +38,9 @@ use actix_http::RequestHead; pub trait Guard { /// Check if request matches predicate fn check(&self, request: &RequestHead) -> bool; + + /// Clone self into a new boxed guard. + fn clone_guard(&self) -> Box; } /// Create guard object for supplied function. @@ -58,29 +61,37 @@ pub trait Guard { /// ``` pub fn fn_guard(f: F) -> impl Guard where - F: Fn(&RequestHead) -> bool, + F: Fn(&RequestHead) -> bool + Clone + 'static, { FnGuard(f) } -struct FnGuard bool>(F); +struct FnGuard bool + Clone>(F); impl Guard for FnGuard where - F: Fn(&RequestHead) -> bool, + F: Fn(&RequestHead) -> bool + Clone + 'static, { fn check(&self, head: &RequestHead) -> bool { (self.0)(head) } + + fn clone_guard(&self) -> Box { + Box::new(FnGuard(self.0.clone())) + } } impl Guard for F where - F: Fn(&RequestHead) -> bool, + F: Fn(&RequestHead) -> bool + Clone + 'static, { fn check(&self, head: &RequestHead) -> bool { (self)(head) } + + fn clone_guard(&self) -> Box { + Box::new(FnGuard(self.clone())) + } } /// Return guard that matches if any of supplied guards. @@ -120,6 +131,10 @@ impl Guard for AnyGuard { } false } + + fn clone_guard(&self) -> Box { + Box::new(AnyGuard(self.0.iter().map(|g| g.clone_guard()).collect())) + } } /// Return guard that matches if all of the supplied guards. @@ -160,6 +175,10 @@ impl Guard for AllGuard { } true } + + fn clone_guard(&self) -> Box { + Box::new(AllGuard(self.0.iter().map(|g| g.clone_guard()).collect())) + } } /// Return guard that matches if supplied guard does not match. @@ -174,6 +193,10 @@ impl Guard for NotGuard { fn check(&self, request: &RequestHead) -> bool { !self.0.check(request) } + + fn clone_guard(&self) -> Box { + self.0.clone_guard() + } } /// Http method guard @@ -184,6 +207,10 @@ impl Guard for MethodGuard { fn check(&self, request: &RequestHead) -> bool { request.method == self.0 } + + fn clone_guard(&self) -> Box { + Box::new(MethodGuard(self.0.clone())) + } } /// Guard to match *GET* http method @@ -255,6 +282,10 @@ impl Guard for HeaderGuard { } false } + + fn clone_guard(&self) -> Box { + Box::new(HeaderGuard(self.0.clone(), self.1.clone())) + } } /// Return predicate that matches if request contains specified Host name. @@ -319,6 +350,10 @@ impl Guard for HostGuard { true } + + fn clone_guard(&self) -> Box { + Box::new(HostGuard(self.0.clone(), self.1.clone())) + } } #[cfg(test)] diff --git a/src/route.rs b/src/route.rs index 8a3d1da9f..dacae12b4 100644 --- a/src/route.rs +++ b/src/route.rs @@ -2,7 +2,6 @@ use std::future::Future; use std::pin::Pin; -use std::rc::Rc; use std::task::{Context, Poll}; 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. pub struct Route { service: BoxedRouteNewService, - guards: Rc>>, + guards: Vec>, } impl Route { @@ -54,34 +53,34 @@ impl Route { service: Box::new(RouteNewService::new(HandlerService::new(|| { ready(HttpResponse::NotFound()) }))), - guards: Rc::new(Vec::new()), + guards: Vec::new(), } } pub(crate) fn take_guards(&mut self) -> Vec> { - std::mem::take(Rc::get_mut(&mut self.guards).unwrap()) + std::mem::take(&mut self.guards) } } impl ServiceFactory for Route { - type Config = (); type Response = ServiceResponse; type Error = Error; - type InitError = (); + type Config = (); type Service = RouteService; + type InitError = (); type Future = CreateRouteService; fn new_service(&self, _: ()) -> Self::Future { CreateRouteService { fut: self.service.new_service(()), - guards: self.guards.clone(), + guards: self.guards.iter().map(|g| g.clone_guard()).collect(), } } } pub struct CreateRouteService { fut: LocalBoxFuture<'static, Result>, - guards: Rc>>, + guards: Vec>, } impl Future for CreateRouteService { @@ -93,7 +92,7 @@ impl Future for CreateRouteService { match this.fut.as_mut().poll(cx)? { Poll::Ready(service) => Poll::Ready(Ok(RouteService { service, - guards: this.guards.clone(), + guards: std::mem::take(&mut this.guards), })), Poll::Pending => Poll::Pending, } @@ -102,7 +101,7 @@ impl Future for CreateRouteService { pub struct RouteService { service: BoxedRouteService, - guards: Rc>>, + guards: Vec>, } impl RouteService { @@ -145,9 +144,7 @@ impl Route { /// # } /// ``` pub fn method(mut self, method: Method) -> Self { - Rc::get_mut(&mut self.guards) - .unwrap() - .push(Box::new(guard::Method(method))); + self.guards.push(Box::new(guard::Method(method))); self } @@ -165,7 +162,7 @@ impl Route { /// # } /// ``` pub fn guard(mut self, f: F) -> Self { - Rc::get_mut(&mut self.guards).unwrap().push(Box::new(f)); + self.guards.push(Box::new(f)); self }