Skip to content

Commit

Permalink
initial draft of notion failure trait and types
Browse files Browse the repository at this point in the history
  • Loading branch information
dherman committed Feb 28, 2018
1 parent d1aceff commit bb03b8b
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
110 changes: 110 additions & 0 deletions crates/notion-core/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use std::convert::From;
use std::fmt::{self, Display};

use failure::{self, Fail, Backtrace};

/// The failure trait for all Notion errors.
pub trait NotionFail: Fail {
/// Indicates whether this error has a message suitable for reporting to an end-user.
fn is_user_friendly(&self) -> bool;

/// Indicates the process exit code that should be returned if the process exits with this error.
fn exit_code(&self) -> i32;
}

/// The `NotionError` type, which can contain any Notion failure.
#[derive(Fail, Debug)]
#[fail(display = "{}", error)]
pub struct NotionError {
error: failure::Error,
user_friendly: bool,
exit_code: i32
}

impl NotionError {
/// Returns a reference to the underlying failure of this error.
pub fn as_fail(&self) -> &Fail {
self.error.cause()
}

/// Gets a reference to the `Backtrace` for this error.
pub fn backtrace(&self) -> &Backtrace {
self.error.backtrace()
}

/// Attempts to downcast this error to a particular `NotionFail` type by reference.
///
/// If the underlying error is not of type `T`, this will return `None`.
pub fn downcast_ref<T: NotionFail>(&self) -> Option<&T> {
self.error.downcast_ref()
}

/// Attempts to downcast this error to a particular `NotionFail` type by mutable reference.
///
/// If the underlying error is not of type `T`, this will return `None`.
pub fn downcast_mut<T: NotionFail>(&mut self) -> Option<&mut T> {
self.error.downcast_mut()
}
}

impl<T: NotionFail> From<T> for NotionError {
fn from(failure: T) -> Self {
let user_friendly = failure.is_user_friendly();
let exit_code = failure.exit_code();
NotionError {
error: failure.into(),
user_friendly,
exit_code
}
}
}

/// An extension trait allowing any failure, including failures from external libraries,
/// to be converted to a Notion error. This marks the error as an unknown error, i.e.
/// a non-user-friendly error.
pub trait FailExt {
fn unknown(self) -> NotionError;
}

/// A wrapper type for unknown errors.
#[derive(Debug)]
struct UnknownNotionError {
error: failure::Error
}

impl Display for UnknownNotionError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "An unknown error has occurred")
}
}

impl Fail for UnknownNotionError {
fn cause(&self) -> Option<&Fail> {
Some(self.error.cause())
}

fn backtrace(&self) -> Option<&Backtrace> {
Some(self.error.backtrace())
}
}

impl NotionFail for UnknownNotionError {
fn is_user_friendly(&self) -> bool { false }
fn exit_code(&self) -> i32 { 1 }
}

impl<T: Fail> FailExt for T {
fn unknown(self) -> NotionError {
UnknownNotionError { error: self.into() }.into()
}
}

impl<D: NotionFail> NotionFail for failure::Context<D> {
fn is_user_friendly(&self) -> bool {
self.get_context().is_user_friendly()
}

fn exit_code(&self) -> i32 {
self.get_context().exit_code()
}
}
1 change: 1 addition & 0 deletions crates/notion-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub mod catalog;
pub mod session;
pub mod style;
pub mod serial;
pub mod error;
mod plugin;
mod installer;

Expand Down

0 comments on commit bb03b8b

Please sign in to comment.