errcraft 0.1.0

Beautiful, structured, and colorful error handling for Rust.
Documentation
//! Convenience macros for creating error frames.

/// Creates a new `ErrFrame` with a formatted message.
///
/// # Examples
///
/// ```rust
/// use errcraft::craft;
///
/// let err = craft!("Failed to load file: {}", "config.toml");
/// ```
#[macro_export]
macro_rules! craft {
    ($msg:expr) => {
        $crate::ErrFrame::new($msg)
    };
    ($fmt:expr, $($arg:tt)*) => {
        $crate::ErrFrame::new(format!($fmt, $($arg)*))
    };
}

/// Creates an error and returns it immediately.
///
/// # Examples
///
/// ```rust,should_panic
/// use errcraft::bail;
///
/// fn do_something() -> Result<(), errcraft::ErrFrame> {
///     bail!("Something went wrong");
/// }
///
/// do_something().unwrap();
/// ```
#[macro_export]
macro_rules! bail {
    ($msg:expr) => {
        return Err($crate::ErrFrame::new($msg))
    };
    ($fmt:expr, $($arg:tt)*) => {
        return Err($crate::ErrFrame::new(format!($fmt, $($arg)*)))
    };
}

/// Ensures a condition is true, otherwise returns an error.
///
/// # Examples
///
/// ```rust,should_panic
/// use errcraft::ensure;
///
/// fn check_value(x: i32) -> Result<(), errcraft::ErrFrame> {
///     ensure!(x > 0, "Value must be positive, got {}", x);
///     Ok(())
/// }
///
/// check_value(-1).unwrap();
/// ```
#[macro_export]
macro_rules! ensure {
    ($cond:expr, $msg:expr) => {
        if !$cond {
            return Err($crate::ErrFrame::new($msg));
        }
    };
    ($cond:expr, $fmt:expr, $($arg:tt)*) => {
        if !$cond {
            return Err($crate::ErrFrame::new(format!($fmt, $($arg)*)));
        }
    };
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_craft_macro() {
        let err = craft!("test error");
        assert_eq!(err.message(), "test error");

        let err = craft!("error: {}", 42);
        assert_eq!(err.message(), "error: 42");
    }

    #[test]
    fn test_bail_macro() {
        fn failing_fn() -> Result<(), crate::ErrFrame> {
            bail!("failed");
        }

        assert!(failing_fn().is_err());
    }

    #[test]
    fn test_ensure_macro() {
        fn check(x: i32) -> Result<(), crate::ErrFrame> {
            ensure!(x > 0, "must be positive");
            Ok(())
        }

        assert!(check(1).is_ok());
        assert!(check(-1).is_err());
    }
}