mod error_ext_impl;
pub use crate::error_ext_impl::*;
pub use lambda_runtime_errors_derive::*;
use failure::{format_err, Compat, Error, Fail};
use std::fmt;
pub trait LambdaErrorExt {
fn error_type(&self) -> &str;
}
impl LambdaErrorExt for Error {
fn error_type(&self) -> &str {
self.find_root_cause().name().unwrap_or_else(|| "FailureError")
}
}
impl LambdaErrorExt for Compat<Error> {
fn error_type(&self) -> &str {
"CompatFailureError"
}
}
pub trait LambdaResultExt<OK, ERR> {
fn handler_error(self) -> Result<OK, HandlerError>;
fn failure_compat(self) -> Result<OK, Compat<Error>>;
}
impl<OK, ERR> LambdaResultExt<OK, ERR> for Result<OK, ERR>
where
ERR: Fail + LambdaErrorExt,
{
fn handler_error(self) -> Result<OK, HandlerError> {
self.map_err(HandlerError::new)
}
fn failure_compat(self) -> Result<OK, Compat<Error>> {
self.map_err(|err| Error::from(err).compat())
}
}
#[derive(Debug)]
pub struct HandlerError {
err_type: String,
inner: failure::Error,
}
impl HandlerError {
pub fn new<T: failure::Fail + LambdaErrorExt + Send + Sync>(e: T) -> Self {
let err_type = e.error_type().to_owned();
HandlerError {
err_type,
inner: failure::Error::from(e),
}
}
}
impl std::error::Error for HandlerError {}
impl fmt::Display for HandlerError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {}", self.err_type, self.inner.find_root_cause())
}
}
impl LambdaErrorExt for HandlerError {
fn error_type(&self) -> &str {
&self.err_type
}
}
impl From<&str> for HandlerError {
fn from(s: &str) -> Self {
HandlerError {
err_type: "UnknownError".to_owned(),
inner: format_err!("{}", s),
}
}
}
impl From<failure::Error> for HandlerError {
fn from(e: failure::Error) -> Self {
let error_type = e.error_type();
HandlerError {
err_type: error_type.to_owned(),
inner: e,
}
}
}
impl From<serde_json::error::Error> for HandlerError {
fn from(e: serde_json::error::Error) -> Self {
HandlerError {
err_type: "JsonError".to_owned(),
inner: failure::Error::from(e),
}
}
}
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use failure::Fail;
#[derive(Fail, Debug)]
#[fail(display = "Custom Error")]
struct CustomError;
#[test]
fn std_error_type() {
let parsed_int = "hello".parse::<u8>();
let err = HandlerError::from(parsed_int.err().unwrap());
assert_eq!(err.error_type(), "std::num::ParseIntError");
}
#[test]
fn error_type_from_failure() {
let err = HandlerError::from(failure::Error::from(CustomError {}));
assert_eq!(err.error_type(), "lambda_runtime_errors::tests::CustomError");
}
}