af_core/
fail.rs

1// Copyright © 2020 Alexandra Frydl
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7//! A general purpose error type.
8
9pub use af_core_macros::{fail, fail_err as err, fail_when as when, fail_wrap as wrap};
10
11use crate::prelude::*;
12use crate::string::SharedString;
13
14/// A generic cloneable error.
15#[derive(Clone)]
16pub struct Error {
17  message: SharedString,
18  trace: im::Vector<SharedString>,
19}
20
21/// Represents either success (`Ok`) or failure (`Err`).
22///
23/// This type doesn't require any type parameters and defaults to
24/// `Result<(), fail::Error>`.
25pub type Result<T = (), E = Error> = std::result::Result<T, E>;
26
27/// Create a new [`Error`] from a given error.
28pub fn from<T: Into<Error>>(err: T) -> Error {
29  err.into()
30}
31
32impl Error {
33  /// Creates a new error with the given message.
34  pub fn new(message: impl Into<SharedString>) -> Self {
35    Self { message: message.into(), trace: default() }
36  }
37
38  /// Sets the cause of this error.
39  pub fn set_cause(&mut self, cause: impl Into<Self>) {
40    let cause = cause.into();
41
42    self.trace = cause.trace;
43    self.trace.push_front(cause.message);
44  }
45
46  /// Returns a copy of this error with a new cause.
47  pub fn with_cause(mut self, cause: impl Into<Self>) -> Self {
48    self.set_cause(cause);
49    self
50  }
51}
52
53// Implement `From` to convert from other types of errors.
54
55impl<T> From<T> for Error
56where
57  T: std::error::Error,
58{
59  fn from(err: T) -> Self {
60    Self::new(err.to_string())
61  }
62}
63
64// Implement formatting.
65
66impl Debug for Error {
67  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68    Debug::fmt(&self.message, f)
69  }
70}
71
72impl Display for Error {
73  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74    Display::fmt(&self.message, f)?;
75
76    if f.alternate() {
77      for err in &self.trace {
78        write!(f, "\n * {:#}", fmt::indent("", "   ", err))?;
79      }
80    }
81
82    Ok(())
83  }
84}