From 29098f8397ff8ec8b8d615d72c5a08bec08fec4d Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Thu, 18 Jul 2019 13:25:50 +0200 Subject: [PATCH] Add support for downcasting response errors (#986) * Add support for downcasting response errors * Added test for error casting --- actix-http/src/error.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/actix-http/src/error.rs b/actix-http/src/error.rs index 368ee6dde..c4d663ade 100644 --- a/actix-http/src/error.rs +++ b/actix-http/src/error.rs @@ -4,6 +4,7 @@ use std::io::Write; use std::str::Utf8Error; use std::string::FromUtf8Error; use std::{fmt, io, result}; +use std::any::TypeId; pub use actix_threadpool::BlockingError; use actix_utils::timeout::TimeoutError; @@ -51,6 +52,11 @@ impl Error { pub fn as_response_error(&self) -> &dyn ResponseError { self.cause.as_ref() } + + /// Similar to `as_response_error` but downcasts. + pub fn as_error(&self) -> Option<&T> { + ResponseError::downcast_ref(self.cause.as_ref()) + } } /// Error that can be converted to `Response` @@ -73,6 +79,22 @@ pub trait ResponseError: fmt::Debug + fmt::Display { ); resp.set_body(Body::from(buf)) } + + #[doc(hidden)] + fn __private_get_type_id__(&self) -> TypeId where Self: 'static { + TypeId::of::() + } +} + +impl ResponseError + 'static { + /// Downcasts a response error to a specific type. + pub fn downcast_ref(&self) -> Option<&T> { + if self.__private_get_type_id__() == TypeId::of::() { + unsafe { Some(&*(self as *const ResponseError as *const T)) } + } else { + None + } + } } impl fmt::Display for Error { @@ -1044,6 +1066,16 @@ mod tests { assert_eq!(resp.status(), StatusCode::OK); } + #[test] + fn test_error_casting() { + let err = PayloadError::Overflow; + let resp_err: &ResponseError = &err; + let err = resp_err.downcast_ref::().unwrap(); + assert_eq!(err.to_string(), "A payload reached size limit."); + let not_err = resp_err.downcast_ref::(); + assert!(not_err.is_none()); + } + #[test] fn test_error_helpers() { let r: Response = ErrorBadRequest("err").into();