Implement std::error::Error for Tower error types (#51)

I've implemented `std::error::Error` for the error types in the `tower-balance`, `tower-buffer`, `tower-in-flight-limit`, and `tower-reconnect` middleware crates.

This is required upstream for runconduit/conduit#442, and also just generally seems like the right thing to do as a library.
This commit is contained in:
Eliza Weisman 2018-02-24 10:48:04 -08:00 committed by GitHub
parent e0ca6545bb
commit cc99f32486
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 187 additions and 1 deletions

View File

@ -12,6 +12,7 @@ extern crate tower_discover;
use futures::{Future, Poll, Async};
use ordermap::OrderMap;
use rand::Rng;
use std::{fmt, error};
use std::marker::PhantomData;
use tower::Service;
use tower_discover::Discover;
@ -312,6 +313,48 @@ impl<F: Future, E> Future for ResponseFuture<F, E> {
}
}
// ===== impl Error =====
impl<T, U> fmt::Display for Error<T, U>
where
T: fmt::Display,
U: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Inner(ref why) =>
write!(f, "inner service error: {}", why),
Error::Balance(ref why) =>
write!(f, "load balancing failed: {}", why),
Error::NotReady => f.pad("not ready"),
}
}
}
impl<T, U> error::Error for Error<T, U>
where
T: error::Error,
U: error::Error,
{
fn cause(&self) -> Option<&error::Error> {
match *self {
Error::Inner(ref why) => Some(why),
Error::Balance(ref why) => Some(why),
_ => None,
}
}
fn description(&self) -> &str {
match *self {
Error::Inner(_) => "inner service error",
Error::Balance(_) => "load balancing failed",
Error::NotReady => "not ready",
}
}
}
#[cfg(test)]
mod tests {
use futures::future;

View File

@ -18,6 +18,7 @@ use futures::sync::oneshot;
use futures::sync::mpsc::{self, UnboundedSender, UnboundedReceiver};
use tower::Service;
use std::{error, fmt};
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering::SeqCst;
@ -222,3 +223,65 @@ where T: Service,
}
}
}
// ===== impl Error =====
impl<T> fmt::Display for Error<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Inner(ref why) =>
write!(f, "inner service error: {}", why),
Error::Closed =>
write!(f, "buffer closed"),
}
}
}
impl<T> error::Error for Error<T>
where
T: error::Error,
{
fn cause(&self) -> Option<&error::Error> {
if let Error::Inner(ref why) = *self {
Some(why)
} else {
None
}
}
fn description(&self) -> &str {
match *self {
Error::Inner(_) => "inner service error",
Error::Closed => "buffer closed",
}
}
}
// ===== impl SpawnError =====
impl<T> fmt::Display for SpawnError<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "error spawning buffer task: {:?}", self.inner)
}
}
impl<T> error::Error for SpawnError<T>
where
T: error::Error,
{
fn cause(&self) -> Option<&error::Error> {
Some(&self.inner)
}
fn description(&self) -> &str {
"error spawning buffer task"
}
}

View File

@ -10,6 +10,7 @@ use tower_ready_service::ReadyService;
use futures::{Future, Poll, Async};
use futures::task::AtomicTask;
use std::{error, fmt};
use std::sync::Arc;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::SeqCst;
@ -241,3 +242,41 @@ impl Shared {
self.curr.fetch_sub(1, SeqCst);
}
}
// ===== impl Error =====
impl<T> fmt::Display for Error<T>
where
T: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Upstream(ref why) =>
write!(f, "upstream service error: {}", why),
Error::NoCapacity =>
write!(f, "in-flight limit exceeded"),
}
}
}
impl<T> error::Error for Error<T>
where
T: error::Error,
{
fn cause(&self) -> Option<&error::Error> {
if let Error::Upstream(ref why) = *self {
Some(why)
} else {
None
}
}
fn description(&self) -> &str {
match *self {
Error::Upstream(_) => "upstream service error",
Error::NoCapacity => "in-flight limit exceeded",
}
}
}

View File

@ -6,7 +6,7 @@ extern crate tower;
use futures::{Future, Async, Poll};
use tower::{Service, NewService};
use std::fmt;
use std::{error, fmt};
pub struct Reconnect<T>
where T: NewService,
@ -161,3 +161,44 @@ impl<T: NewService> Future for ResponseFuture<T> {
}
}
}
// ===== impl Error =====
impl<T, U> fmt::Display for Error<T, U>
where
T: fmt::Display,
U: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::Inner(ref why) =>
write!(f, "inner service error: {}", why),
Error::Connect(ref why) =>
write!(f, "connection failed: {}", why),
Error::NotReady => f.pad("not ready"),
}
}
}
impl<T, U> error::Error for Error<T, U>
where
T: error::Error,
U: error::Error,
{
fn cause(&self) -> Option<&error::Error> {
match *self {
Error::Inner(ref why) => Some(why),
Error::Connect(ref why) => Some(why),
_ => None,
}
}
fn description(&self) -> &str {
match *self {
Error::Inner(_) => "inner service error",
Error::Connect(_) => "connection failed",
Error::NotReady => "not ready",
}
}
}