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
//! 通过跟踪功能消除类型擦除错误.
use crate::SharedString;
use std::{error, fmt};

mod source;

use source::Source;

#[derive(Debug)]
pub struct Error {
    /// 错误消息
    message: SharedString,
    /// 错误源
    source: Option<Box<Error>>,
}

impl Error {
    /// 通过错误消息创建一个新的实例.
    #[inline]
    pub fn new(message: impl Into<SharedString>) -> Self {
        Self {
            message: message.into(),
            source: None,
        }
    }

    /// 通过错误消息和错误源创建新的实例
    #[inline]
    pub fn with_source(message: impl Into<SharedString>, source: impl Into<Error>) -> Self {
        Self {
            message: message.into(),
            source: Some(Box::new(source.into())),
        }
    }

    /// 通过额外的上下文错误消息,创建错误实例
    #[inline]
    pub fn context(self, message: impl Into<SharedString>) -> Self {
        Self {
            message: message.into(),
            source: Some(Box::new(self)),
        }
    }

    /// 返回错误消息
    #[inline]
    pub fn message(&self) -> &str {
        self.message.as_ref()
    }

    /// 返回错误源
    #[inline]
    pub fn source(&self) -> Option<&Error> {
        self.source.as_deref()
    }

    /// 通过 `self` 返回错误源的迭代器
    #[inline]
    pub fn sources(&self) -> impl Iterator<Item = &Error> {
        Source::new(self)
    }

    /// 返回 `slef` 的顶层错误源
    ///
    /// 最顶层的错误源是通过 [`sources()`](Error::sources) 返回的迭代器的最后一个.
    #[inline]
    pub fn root_source(&self) -> Option<&Error> {
        self.sources().last()
    }
}

impl<E: error::Error> From<E> for Error {
    #[inline]
    fn from(err: E) -> Self {
        Self {
            message: err.to_string().into(),
            source: err.source().map(|err| Box::new(Self::new(err.to_string()))),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let message = &self.message;
        if let Some(source) = &self.source {
            let source = source.message();
            let root_source = self.root_source().map(|err| err.message());
            if root_source != Some(source) {
                tracing::error!(root_source, source, "{message}");
            } else {
                tracing::error!(root_source, "{message}");
            }
        } else {
            tracing::error!("{message}");
        }
        write!(f, "{message}")
    }
}