//! Error handling.

pub use failure::{Error, Fail};

use std::fmt;

macro_rules! ok {
   ($v:expr, $msg:expr) => {
      match $v {
         Some(v) => Ok(v),
         None    => Err(err_msg($msg)),
      }
   };
}

macro_rules! flag_ok {
   ($t:ident$(::$tc:ident)*, $v:expr) => {
      match $t$(::$tc)*::from_bits($v) {
         Some(v) => Ok(v),
         None    => Err(err_msg(concat!("bad ", stringify!($t)))),
      }
   };
}

macro_rules! bail {
   ($e:expr) => {
      return Err(err_msg($e));
   };
}

/// Returns an `Error` with a static string.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::err::err_msg;
///
/// assert_eq!(format!("{}", err_msg("oh no not things")),
///            "oh no not things");
/// ```
pub fn err_msg(msg: &'static str) -> Error {ErrMsg(msg).into()}

/// Returns an `Error` from a `ReprError`.
///
/// # Examples
///
/// ```
/// use maraiah::durandal::err::repr_error;
///
/// assert_eq!(format!("{}", repr_error(77)),
///            "representation error (got 77)");
/// ```
pub fn repr_error<T: Into<i64>>(n: T) -> Error {ReprError::new(n).into()}

impl ReprError
{
   /// Creates a new `ReprError`.
   ///
   /// # Examples
   ///
   /// ```
   /// use maraiah::durandal::err::ReprError;
   ///
   /// let err = ReprError::new(7);
   ///
   /// assert_eq!(format!("{}", err), "representation error (got 7)");
   /// ```
   #[inline]
   pub fn new<T: Into<i64>>(n: T) -> Self {Self(n.into())}
}

impl Fail for ReprError {}
impl Fail for ErrMsg {}

impl fmt::Display for ReprError
{
   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
   {
      write!(f, "representation error (got {})", self.0)
   }
}

impl fmt::Display for ErrMsg
{
   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
   {
      f.write_str(self.0)
   }
}

/// A representation error for an integer.
#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct ReprError(i64);

#[derive(Debug)]
struct ErrMsg(&'static str);

/// A generic `failure` based `Result` type.
pub type ResultS<T> = Result<T, Error>;

// EOF
