common_error/
ext.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::any::Any;
16use std::sync::Arc;
17
18use crate::status_code::StatusCode;
19
20/// Extension to [`Error`](std::error::Error) in std.
21pub trait ErrorExt: StackError {
22    /// Map this error to [StatusCode].
23    fn status_code(&self) -> StatusCode {
24        StatusCode::Unknown
25    }
26
27    /// Returns the error as [Any](std::any::Any) so that it can be
28    /// downcast to a specific implementation.
29    fn as_any(&self) -> &dyn Any;
30
31    fn output_msg(&self) -> String
32    where
33        Self: Sized,
34    {
35        match self.status_code() {
36            StatusCode::Unknown | StatusCode::Internal => {
37                // masks internal error from end user
38                format!("Internal error: {}", self.status_code() as u32)
39            }
40            _ => {
41                let error = self.last();
42                if let Some(external_error) = error.source() {
43                    let external_root = external_error.sources().last().unwrap();
44
45                    if error.transparent() {
46                        format!("{external_root}")
47                    } else {
48                        format!("{error}: {external_root}")
49                    }
50                } else {
51                    format!("{error}")
52                }
53            }
54        }
55    }
56
57    /// Find out root level error for nested error
58    fn root_cause(&self) -> Option<&dyn std::error::Error>
59    where
60        Self: Sized,
61    {
62        let error = self.last();
63        if let Some(external_error) = error.source() {
64            let external_root = external_error.sources().last().unwrap();
65            Some(external_root)
66        } else {
67            None
68        }
69    }
70}
71
72pub trait StackError: std::error::Error {
73    fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>);
74
75    fn next(&self) -> Option<&dyn StackError>;
76
77    fn last(&self) -> &dyn StackError
78    where
79        Self: Sized,
80    {
81        let Some(mut result) = self.next() else {
82            return self;
83        };
84        while let Some(err) = result.next() {
85            result = err;
86        }
87        result
88    }
89
90    /// Indicates whether this error is "transparent", that it delegates its "display" and "source"
91    /// to the underlying error. Could be useful when you are just wrapping some external error,
92    /// **AND** can not or would not provide meaningful contextual info. For example, the
93    /// `DataFusionError`.
94    fn transparent(&self) -> bool {
95        false
96    }
97}
98
99impl<T: ?Sized + StackError> StackError for Arc<T> {
100    fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
101        self.as_ref().debug_fmt(layer, buf)
102    }
103
104    fn next(&self) -> Option<&dyn StackError> {
105        self.as_ref().next()
106    }
107}
108
109impl<T: StackError> StackError for Box<T> {
110    fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
111        self.as_ref().debug_fmt(layer, buf)
112    }
113
114    fn next(&self) -> Option<&dyn StackError> {
115        self.as_ref().next()
116    }
117}
118
119/// An opaque boxed error based on errors that implement [ErrorExt] trait.
120pub struct BoxedError {
121    inner: Box<dyn crate::ext::ErrorExt + Send + Sync>,
122}
123
124impl BoxedError {
125    pub fn new<E: crate::ext::ErrorExt + Send + Sync + 'static>(err: E) -> Self {
126        Self {
127            inner: Box::new(err),
128        }
129    }
130
131    pub fn into_inner(self) -> Box<dyn crate::ext::ErrorExt + Send + Sync> {
132        self.inner
133    }
134}
135
136impl std::fmt::Debug for BoxedError {
137    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138        let mut buf = vec![];
139        self.debug_fmt(0, &mut buf);
140        write!(f, "{}", buf.join("\n"))
141    }
142}
143
144impl std::fmt::Display for BoxedError {
145    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
146        write!(f, "{}", self.inner)
147    }
148}
149
150impl std::error::Error for BoxedError {
151    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
152        self.inner.source()
153    }
154}
155
156impl crate::ext::ErrorExt for BoxedError {
157    fn status_code(&self) -> crate::status_code::StatusCode {
158        self.inner.status_code()
159    }
160
161    fn as_any(&self) -> &dyn std::any::Any {
162        self.inner.as_any()
163    }
164}
165
166// Implement ErrorCompat for this opaque error so the backtrace is also available
167// via `ErrorCompat::backtrace()`.
168impl crate::snafu::ErrorCompat for BoxedError {
169    fn backtrace(&self) -> Option<&crate::snafu::Backtrace> {
170        None
171    }
172}
173
174impl StackError for BoxedError {
175    fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
176        self.inner.debug_fmt(layer, buf)
177    }
178
179    fn next(&self) -> Option<&dyn StackError> {
180        self.inner.next()
181    }
182}
183
184/// Error type with plain error message
185#[derive(Debug)]
186pub struct PlainError {
187    msg: String,
188    status_code: StatusCode,
189}
190
191impl PlainError {
192    pub fn new(msg: String, status_code: StatusCode) -> Self {
193        Self { msg, status_code }
194    }
195}
196
197impl std::fmt::Display for PlainError {
198    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199        write!(f, "{}", self.msg)
200    }
201}
202
203impl std::error::Error for PlainError {
204    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
205        None
206    }
207}
208
209impl crate::ext::ErrorExt for PlainError {
210    fn status_code(&self) -> crate::status_code::StatusCode {
211        self.status_code
212    }
213
214    fn as_any(&self) -> &dyn std::any::Any {
215        self as _
216    }
217}
218
219impl StackError for PlainError {
220    fn debug_fmt(&self, layer: usize, buf: &mut Vec<String>) {
221        buf.push(format!("{}: {}", layer, self.msg))
222    }
223
224    fn next(&self) -> Option<&dyn StackError> {
225        None
226    }
227}