From 68d3f6c22e1a78c0a048ea2fd6ccd1565097cffa Mon Sep 17 00:00:00 2001 From: David Barsky Date: Tue, 15 Jan 2019 15:05:14 -0500 Subject: [PATCH] Use `tokio::timer` instead of `tokio_timer`; use Kind pattern (#141) --- tower-timeout/src/lib.rs | 118 ++++++++++++++++++++++++++++++++------- 1 file changed, 98 insertions(+), 20 deletions(-) diff --git a/tower-timeout/src/lib.rs b/tower-timeout/src/lib.rs index ce7528c..9cf49b7 100644 --- a/tower-timeout/src/lib.rs +++ b/tower-timeout/src/lib.rs @@ -3,13 +3,17 @@ //! If the response does not complete within the specified timeout, the response //! will be aborted. +#![doc(html_root_url = "https://docs.rs/tower-timeout/0.1.0")] +#![deny(missing_debug_implementations, missing_docs)] +#![cfg_attr(test, deny(warnings))] + extern crate futures; extern crate tower_service; extern crate tokio_timer; use futures::{Future, Poll, Async}; use tower_service::Service; -use tokio_timer::{clock, Delay}; +use tokio_timer::{clock, Delay, Error as TimerError}; use std::{error, fmt}; use std::time::Duration; @@ -23,12 +27,19 @@ pub struct Timeout { /// Errors produced by `Timeout`. #[derive(Debug)] -pub enum Error { - /// The inner service produced an error +pub struct Error(Kind); + +/// Timeout error variants +#[derive(Debug)] +enum Kind { + /// Inner value returned an error Inner(T), - /// The request did not complete within the specified timeout. - Timeout, + /// The timeout elapsed. + Elapsed, + + /// Timer returned an error. + Timer(TimerError), } /// `Timeout` response future @@ -41,6 +52,7 @@ pub struct ResponseFuture { // ===== impl Timeout ===== impl Timeout { + /// Creates a new Timeout pub fn new(inner: T, timeout: Duration) -> Self { Timeout { inner, @@ -59,7 +71,9 @@ where fn poll_ready(&mut self) -> Poll<(), Self::Error> { self.inner.poll_ready() - .map_err(Error::Inner) + .map_err(|e| { + Error(Kind::Inner(e)) + }) } fn call(&mut self, request: Request) -> Self::Future { @@ -83,19 +97,18 @@ where T: Future, match self.response.poll() { Ok(Async::Ready(v)) => return Ok(Async::Ready(v)), Ok(Async::NotReady) => {} - Err(e) => return Err(Error::Inner(e)), + Err(e) => return Err(Error(Kind::Inner(e))), } // Now check the sleep match self.sleep.poll() { Ok(Async::NotReady) => Ok(Async::NotReady), - Ok(Async::Ready(_)) => Err(Error::Timeout), - Err(_) => Err(Error::Timeout), + Ok(Async::Ready(_)) => Err(Error(Kind::Elapsed)), + Err(e) => Err(Error(Kind::Timer(e))), } } } - // ===== impl Error ===== impl fmt::Display for Error @@ -103,30 +116,95 @@ where T: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Inner(ref why) => fmt::Display::fmt(why, f), - Error::Timeout => f.pad("request timed out"), + match self.0 { + Kind::Inner(ref why) => fmt::Display::fmt(why, f), + Kind::Elapsed => f.pad("request timed out"), + Kind::Timer(ref why) => fmt::Display::fmt(why, f), } } } impl error::Error for Error where - T: error::Error, + T: error::Error + 'static, { - fn cause(&self) -> Option<&error::Error> { - if let Error::Inner(ref why) = *self { + fn description(&self) -> &str { + match self.0 { + Kind::Inner(ref e) => e.description(), + Kind::Elapsed => "request timed out", + Kind::Timer(ref e) => e.description(), + } + } + + fn source(&self) -> Option<&(error::Error + 'static)> { + let kind = &self.0; + if let Kind::Inner(ref why) = kind { Some(why) } else { None } } +} - fn description(&self) -> &str { - match *self { - Error::Inner(_) => "inner service error", - Error::Timeout => "request timed out", +// ===== impl Error ===== + +impl Error { + /// Create a new `Error` representing the inner value completing with `Err`. + pub fn inner(err: T) -> Error { + Error(Kind::Inner(err)) + } + + /// Returns `true` if the error was caused by the inner value completing + /// with `Err`. + pub fn is_inner(&self) -> bool { + match self.0 { + Kind::Inner(_) => true, + _ => false, } } + /// Consumes `self`, returning the inner future error. + pub fn into_inner(self) -> Option { + match self.0 { + Kind::Inner(err) => Some(err), + _ => None, + } + } + + /// Create a new `Error` representing the inner value not completing before + /// the deadline is reached. + pub fn elapsed() -> Error { + Error(Kind::Elapsed) + } + + /// Returns `true` if the error was caused by the inner value not completing + /// before the deadline is reached. + pub fn is_elapsed(&self) -> bool { + match self.0 { + Kind::Elapsed => true, + _ => false, + } + } + + /// Creates a new `Error` representing an error encountered by the timer + /// implementation + pub fn timer(err: TimerError) -> Error { + Error(Kind::Timer(err)) + } + + /// Returns `true` if the error was caused by the timer. + pub fn is_timer(&self) -> bool { + match self.0 { + Kind::Timer(_) => true, + _ => false, + } + } + + /// Consumes `self`, returning the error raised by the timer implementation. + pub fn into_timer(self) -> Option { + match self.0 { + Kind::Timer(err) => Some(err), + _ => None, + } + } }