1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
/***********************************************************************************************************************
 * Copyright (c) 2019 by the authors
 *
 * Author: André Borrmann
 * License: Appache License 2.0
 **********************************************************************************************************************/
#![doc(html_root_url = "https://docs.rs/ruspiro-error/0.1.1")]
#![cfg_attr(not(any(test, doctest)), no_std)]

//! # Basic Error trait
//!
//! This is more or less the same as found in Rust std library:
//! [Error](https://doc.rust-lang.org/std/error/trait.Error.html) but made available in `[no_std]` expecting an
//! allocator to be in place, which provided with [`ruspiro-allocator`](https://crates.io/crates/ruspiro-allocator).

extern crate alloc;
use alloc::{boxed::Box, string::String};
use core::fmt::{Debug, Display};

/// The type that shall be used as `Error` type when returning a [`Result`]. This allows the usage of the
/// `?` operator on functions or methods.
pub type BoxError = Box<dyn Error + Send>; // + Send + Sync needed ?

/// The generic Error trait. All actual errors implementing this trait also need to implement `Debug`
/// and `Display` to provide human readable text of the error.
pub trait Error: Debug + Display + Send {
    /// the underlaying source of this error, if any. This allows to "stack" errors while keeping
    /// track to it's root cause
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        None
    }
}

impl<'a, E: Error + 'a + Send> From<E> for Box<dyn Error + 'a + Send> {
    /// Conviniently convert an [`Error`] into a boxed `dyn Error`. This allows simple usage of
    /// `.into()` calls when returning an `Error` type.
    fn from(orig: E) -> Box<dyn Error + 'a + Send> {
        Box::new(orig)
    }
}

/// The most generic Error type. This can be used if no specific error type will be implemented and returning an erro
/// only containing an error message is sufficient.
///
/// # Example
/// ```
/// # use ruspiro_error::*;
///
/// fn some_function() -> Result<(), BoxError> {
///     Err(
///         GenericError::with_message("Some Message").into()    
///     )
/// }
/// ```
pub struct GenericError {
    message: Option<String>,
}

impl GenericError {
    /// Create a [GenericError] that does not even contain a custom message
    ///
    /// # Example
    /// ```
    /// # use ruspiro_error::*;
    ///
    /// fn some_function() -> Result<(), BoxError> {
    ///     Err(
    ///         GenericError::default().into()    
    ///     )
    /// }
    /// ```
    pub fn default() -> Self {
        GenericError { message: None }
    }

    /// Crate a [GenericError] containing the custom error message
    ///
    /// # Example
    /// ```
    /// # use ruspiro_error::*;
    ///
    /// fn some_function() -> Result<(), BoxError> {
    ///     Err(
    ///         GenericError::with_message("Some Message").into()    
    ///     )
    /// }
    /// ```
    pub fn with_message(message: &str) -> Self {
        GenericError {
            message: Some(message.into()),
        }
    }
}

impl Error for GenericError {}
impl Display for GenericError {
    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match &self.message {
            Some(msg) => write!(fmt, "Error: {}", msg),
            None => write!(fmt, "Generic Error"),
        }
    }
}

impl Debug for GenericError {
    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        // re-use the display implementation in case of debug formatting
        <GenericError as Display>::fmt(self, fmt)
    }
}