Skip to main content

speedy2d/
error.rs

1/*
2 *  Copyright 2021 QuantumBadger
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 */
16use std::fmt::{Debug, Display, Formatter};
17use std::rc::Rc;
18
19use backtrace::Backtrace;
20
21/// An error with an associated backtrace, and an optional cause.
22#[derive(Clone)]
23pub struct BacktraceError<E>
24where
25    E: Debug + Display + 'static
26{
27    value: Rc<BacktraceErrorImpl<E>>
28}
29
30struct BacktraceErrorImpl<E>
31where
32    E: Debug + Display
33{
34    error: E,
35    backtrace: Backtrace,
36    cause: Option<Box<dyn std::error::Error>>
37}
38
39impl<E: Debug + Display> std::error::Error for BacktraceError<E> {}
40
41impl<E: Debug + Display> Display for BacktraceError<E>
42{
43    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
44    {
45        Display::fmt(self.error(), f)
46    }
47}
48
49impl<E: Debug + Display> Debug for BacktraceError<E>
50{
51    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
52    {
53        f.debug_struct("BacktraceError")
54            .field("error", self.error())
55            .field("backtrace", self.get_backtrace())
56            .field("cause", self.cause())
57            .finish()
58    }
59}
60
61impl<E: Debug + Display> BacktraceError<E>
62{
63    #[must_use]
64    pub(crate) fn new_with_cause<Cause: std::error::Error + 'static>(
65        error: E,
66        cause: Cause
67    ) -> Self
68    {
69        BacktraceError {
70            value: Rc::new(BacktraceErrorImpl {
71                backtrace: Backtrace::new(),
72                error,
73                cause: Some(Box::new(cause))
74            })
75        }
76    }
77
78    #[must_use]
79    pub(crate) fn new(error: E) -> Self
80    {
81        BacktraceError {
82            value: Rc::new(BacktraceErrorImpl {
83                backtrace: Backtrace::new(),
84                error,
85                cause: None
86            })
87        }
88    }
89
90    /// Returns the backtrace for this error.
91    #[must_use]
92    pub fn get_backtrace(&self) -> &Backtrace
93    {
94        &self.value.backtrace
95    }
96
97    /// Returns the error.
98    #[must_use]
99    pub fn error(&self) -> &E
100    {
101        &self.value.error
102    }
103
104    /// Returns the original cause of the error, if one is present.
105    #[must_use]
106    pub fn cause(&self) -> &Option<Box<dyn std::error::Error>>
107    {
108        &self.value.cause
109    }
110
111    #[must_use]
112    pub(crate) fn context<S: AsRef<str>>(
113        self,
114        description: S
115    ) -> BacktraceError<ErrorMessage>
116    {
117        BacktraceError::new_with_cause(
118            ErrorMessage {
119                description: description.as_ref().to_string()
120            },
121            self
122        )
123    }
124}
125
126/// A human-readable error message.
127#[derive(Clone, Debug)]
128pub struct ErrorMessage
129{
130    description: String
131}
132
133impl ErrorMessage
134{
135    pub(crate) fn msg<S: AsRef<str>>(description: S) -> BacktraceError<Self>
136    {
137        BacktraceError::new(Self {
138            description: description.as_ref().to_string()
139        })
140    }
141
142    pub(crate) fn msg_with_cause<S, Cause>(
143        description: S,
144        cause: Cause
145    ) -> BacktraceError<Self>
146    where
147        S: AsRef<str>,
148        Cause: std::error::Error + 'static
149    {
150        BacktraceError::new_with_cause(
151            Self {
152                description: description.as_ref().to_string()
153            },
154            cause
155        )
156    }
157}
158
159impl Display for ErrorMessage
160{
161    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result
162    {
163        Display::fmt(&self.description, f)
164    }
165}
166
167pub(crate) trait Context<R>
168{
169    fn context<S: AsRef<str>>(
170        self,
171        description: S
172    ) -> Result<R, BacktraceError<ErrorMessage>>;
173}
174
175impl<R, E: std::error::Error + 'static> Context<R> for Result<R, E>
176{
177    fn context<S: AsRef<str>>(
178        self,
179        description: S
180    ) -> Result<R, BacktraceError<ErrorMessage>>
181    {
182        match self {
183            Ok(result) => Ok(result),
184            Err(err) => Err(BacktraceError::new_with_cause(
185                ErrorMessage {
186                    description: description.as_ref().to_string()
187                },
188                err
189            ))
190        }
191    }
192}