diff --git a/Cargo.toml b/Cargo.toml index a98b29e8..03d481e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,8 @@ ssl = ["openssl", "tokio-openssl"] # rustls rust-tls = ["rustls", "tokio-rustls", "webpki", "webpki-roots"] +cell = [] + [dependencies] actix = "0.7.0" diff --git a/src/cell.rs b/src/cell.rs new file mode 100644 index 00000000..855c6aac --- /dev/null +++ b/src/cell.rs @@ -0,0 +1,62 @@ +//! Custom cell impl + +#[cfg(feature = "cell")] +use std::cell::UnsafeCell; +#[cfg(not(feature = "cell"))] +use std::cell::{Ref, RefCell, RefMut}; +use std::fmt; +use std::rc::Rc; + +pub(crate) struct Cell { + #[cfg(feature = "cell")] + inner: Rc>, + #[cfg(not(feature = "cell"))] + inner: Rc>, +} + +impl Clone for Cell { + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + } + } +} + +impl fmt::Debug for Cell { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.fmt(f) + } +} + +#[cfg(feature = "cell")] +impl Cell { + pub(crate) fn new(inner: T) -> Self { + Self { + inner: Rc::new(UnsafeCell::new(inner)), + } + } + + pub(crate) fn borrow(&self) -> &T { + unsafe { &*self.inner.as_ref().get() } + } + + pub(crate) fn borrow_mut(&self) -> &mut T { + unsafe { &mut *self.inner.as_ref().get() } + } +} + +#[cfg(not(feature = "cell"))] +impl Cell { + pub(crate) fn new(inner: T) -> Self { + Self { + inner: Rc::new(RefCell::new(inner)), + } + } + + pub(crate) fn borrow(&self) -> Ref { + self.inner.borrow() + } + pub(crate) fn borrow_mut(&self) -> RefMut { + self.inner.borrow_mut() + } +} diff --git a/src/cloneable.rs b/src/cloneable.rs index d94e2953..ec3fd0b4 100644 --- a/src/cloneable.rs +++ b/src/cloneable.rs @@ -1,19 +1,17 @@ -use std::cell::RefCell; -use std::rc::Rc; - use futures::Poll; +use super::cell::Cell; use super::service::Service; /// Service that allows to turn non-clone service to a service with `Clone` impl pub struct CloneableService { - service: Rc>, + service: Cell, } impl CloneableService { pub fn new(service: S) -> Self { Self { - service: Rc::new(RefCell::new(service)), + service: Cell::new(service), } } } diff --git a/src/lib.rs b/src/lib.rs index f6262791..1400bdac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,6 +55,7 @@ extern crate webpki; #[cfg(feature = "rust-tls")] extern crate webpki_roots; +mod cell; pub mod cloneable; pub mod connector; pub mod counter; diff --git a/src/service/and_then.rs b/src/service/and_then.rs index 187ab167..9dd67277 100644 --- a/src/service/and_then.rs +++ b/src/service/and_then.rs @@ -1,9 +1,7 @@ -use std::cell::RefCell; -use std::rc::Rc; - use futures::{Async, Future, Poll}; use super::{IntoNewService, NewService, Service}; +use cell::Cell; /// Service for the `and_then` combinator, chaining a computation onto the end /// of another service which completes successfully. @@ -11,7 +9,7 @@ use super::{IntoNewService, NewService, Service}; /// This is created by the `ServiceExt::and_then` method. pub struct AndThen { a: A, - b: Rc>, + b: Cell, } impl AndThen @@ -21,10 +19,7 @@ where { /// Create new `AndThen` combinator pub fn new(a: A, b: B) -> Self { - Self { - a, - b: Rc::new(RefCell::new(b)), - } + Self { a, b: Cell::new(b) } } } @@ -66,7 +61,7 @@ where A: Service, B: Service, { - b: Rc>, + b: Cell, fut_b: Option, fut_a: A::Future, } @@ -76,7 +71,7 @@ where A: Service, B: Service, { - fn new(fut_a: A::Future, b: Rc>) -> Self { + fn new(fut_a: A::Future, b: Cell) -> Self { AndThenFuture { b, fut_a, diff --git a/src/service/then.rs b/src/service/then.rs index d31e807d..b10537b5 100644 --- a/src/service/then.rs +++ b/src/service/then.rs @@ -1,9 +1,7 @@ -use std::cell::RefCell; -use std::rc::Rc; - use futures::{Async, Future, Poll}; use super::{IntoNewService, NewService, Service}; +use cell::Cell; /// Service for the `then` combinator, chaining a computation onto the end of /// another service. @@ -11,7 +9,7 @@ use super::{IntoNewService, NewService, Service}; /// This is created by the `ServiceExt::then` method. pub struct Then { a: A, - b: Rc>, + b: Cell, } impl Then @@ -21,10 +19,7 @@ where { /// Create new `Then` combinator pub fn new(a: A, b: B) -> Then { - Then { - a, - b: Rc::new(RefCell::new(b)), - } + Then { a, b: Cell::new(b) } } } @@ -66,7 +61,7 @@ where A: Service, B: Service>, { - b: Rc>, + b: Cell, fut_b: Option, fut_a: A::Future, } @@ -76,7 +71,7 @@ where A: Service, B: Service>, { - fn new(fut_a: A::Future, b: Rc>) -> Self { + fn new(fut_a: A::Future, b: Cell) -> Self { ThenFuture { b, fut_a, @@ -243,6 +238,7 @@ mod tests { use super::*; use service::{NewServiceExt, ServiceExt}; + #[derive(Clone)] struct Srv1(Rc>); impl Service for Srv1 { type Request = Result<&'static str, &'static str>; @@ -263,7 +259,6 @@ mod tests { } } - #[derive(Clone)] struct Srv2(Rc>); impl Service for Srv2 { @@ -298,7 +293,7 @@ mod tests { #[test] fn test_call() { let cnt = Rc::new(Cell::new(0)); - let mut srv = Srv1(cnt.clone()).then(Srv2(cnt)); + let mut srv = Srv1(cnt.clone()).then(Srv2(cnt)).clone(); let res = srv.call(Ok("srv1")).poll(); assert!(res.is_ok()); @@ -315,7 +310,7 @@ mod tests { let cnt2 = cnt.clone(); let blank = move || Ok::<_, ()>(Srv1(cnt2.clone())); let new_srv = blank.into_new_service().then(move || Ok(Srv2(cnt.clone()))); - if let Async::Ready(mut srv) = new_srv.new_service().poll().unwrap() { + if let Async::Ready(mut srv) = new_srv.clone().new_service().poll().unwrap() { let res = srv.call(Ok("srv1")).poll(); assert!(res.is_ok()); assert_eq!(res.unwrap(), Async::Ready(("srv1", "ok"))); diff --git a/src/timer.rs b/src/timer.rs index df8f83a6..e4c3d3c6 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,5 +1,3 @@ -use std::cell::RefCell; -use std::rc::Rc; use std::time::{Duration, Instant}; use futures::future::{ok, FutureResult}; @@ -7,11 +5,12 @@ use futures::{Async, Future, Poll}; use tokio_current_thread::spawn; use tokio_timer::sleep; +use super::cell::Cell; use super::service::{NewService, Service}; use super::Never; #[derive(Clone, Debug)] -pub struct LowResTimer(Rc>); +pub struct LowResTimer(Cell); #[derive(Debug)] struct Inner { @@ -30,7 +29,7 @@ impl Inner { impl LowResTimer { pub fn with_interval(interval: Duration) -> LowResTimer { - LowResTimer(Rc::new(RefCell::new(Inner::new(interval)))) + LowResTimer(Cell::new(Inner::new(interval))) } pub fn timer(&self) -> LowResTimerService { @@ -40,7 +39,7 @@ impl LowResTimer { impl Default for LowResTimer { fn default() -> Self { - LowResTimer(Rc::new(RefCell::new(Inner::new(Duration::from_secs(1))))) + LowResTimer(Cell::new(Inner::new(Duration::from_secs(1)))) } } @@ -58,11 +57,11 @@ impl NewService for LowResTimer { } #[derive(Clone, Debug)] -pub struct LowResTimerService(Rc>); +pub struct LowResTimerService(Cell); impl LowResTimerService { pub fn with_resolution(resolution: Duration) -> LowResTimerService { - LowResTimerService(Rc::new(RefCell::new(Inner::new(resolution)))) + LowResTimerService(Cell::new(Inner::new(resolution))) } /// Get current time. This function has to be called from