ruspiro_error/
lib.rs

1/***********************************************************************************************************************
2 * Copyright (c) 2019 by the authors
3 *
4 * Author: André Borrmann
5 * License: Appache License 2.0
6 **********************************************************************************************************************/
7#![doc(html_root_url = "https://docs.rs/ruspiro-error/0.1.1")]
8#![cfg_attr(not(any(test, doctest)), no_std)]
9
10//! # Basic Error trait
11//!
12//! This is more or less the same as found in Rust std library:
13//! [Error](https://doc.rust-lang.org/std/error/trait.Error.html) but made available in `[no_std]` expecting an
14//! allocator to be in place, which provided with [`ruspiro-allocator`](https://crates.io/crates/ruspiro-allocator).
15
16extern crate alloc;
17use alloc::{boxed::Box, string::String};
18use core::fmt::{Debug, Display};
19
20/// The type that shall be used as `Error` type when returning a [`Result`]. This allows the usage of the
21/// `?` operator on functions or methods.
22pub type BoxError = Box<dyn Error + Send>; // + Send + Sync needed ?
23
24/// The generic Error trait. All actual errors implementing this trait also need to implement `Debug`
25/// and `Display` to provide human readable text of the error.
26pub trait Error: Debug + Display + Send {
27    /// the underlaying source of this error, if any. This allows to "stack" errors while keeping
28    /// track to it's root cause
29    fn source(&self) -> Option<&(dyn Error + 'static)> {
30        None
31    }
32}
33
34impl<'a, E: Error + 'a + Send> From<E> for Box<dyn Error + 'a + Send> {
35    /// Conviniently convert an [`Error`] into a boxed `dyn Error`. This allows simple usage of
36    /// `.into()` calls when returning an `Error` type.
37    fn from(orig: E) -> Box<dyn Error + 'a + Send> {
38        Box::new(orig)
39    }
40}
41
42/// The most generic Error type. This can be used if no specific error type will be implemented and returning an erro
43/// only containing an error message is sufficient.
44///
45/// # Example
46/// ```
47/// # use ruspiro_error::*;
48///
49/// fn some_function() -> Result<(), BoxError> {
50///     Err(
51///         GenericError::with_message("Some Message").into()    
52///     )
53/// }
54/// ```
55pub struct GenericError {
56    message: Option<String>,
57}
58
59impl GenericError {
60    /// Create a [GenericError] that does not even contain a custom message
61    ///
62    /// # Example
63    /// ```
64    /// # use ruspiro_error::*;
65    ///
66    /// fn some_function() -> Result<(), BoxError> {
67    ///     Err(
68    ///         GenericError::default().into()    
69    ///     )
70    /// }
71    /// ```
72    pub fn default() -> Self {
73        GenericError { message: None }
74    }
75
76    /// Crate a [GenericError] containing the custom error message
77    ///
78    /// # Example
79    /// ```
80    /// # use ruspiro_error::*;
81    ///
82    /// fn some_function() -> Result<(), BoxError> {
83    ///     Err(
84    ///         GenericError::with_message("Some Message").into()    
85    ///     )
86    /// }
87    /// ```
88    pub fn with_message(message: &str) -> Self {
89        GenericError {
90            message: Some(message.into()),
91        }
92    }
93}
94
95impl Error for GenericError {}
96impl Display for GenericError {
97    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
98        match &self.message {
99            Some(msg) => write!(fmt, "Error: {}", msg),
100            None => write!(fmt, "Generic Error"),
101        }
102    }
103}
104
105impl Debug for GenericError {
106    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107        // re-use the display implementation in case of debug formatting
108        <GenericError as Display>::fmt(self, fmt)
109    }
110}