1use std::any::{Any, TypeId};
2use std::borrow::Cow;
3use std::collections::HashMap;
4use std::error::Error as StdError;
5use std::fmt;
6use std::str;
7
8use crate::kinds::UserError;
9use crate::kinds::{error_name, tag_check};
10use crate::traits::{ErrorKind, Field};
11
12const FIELD_HINT: u16 = 0x_00_01;
13const FIELD_DETAILS: u16 = 0x_00_02;
14const FIELD_SERVER_TRACEBACK: u16 = 0x_01_01;
15
16const FIELD_POSITION_START: u16 = 0x_FF_F1;
18const FIELD_POSITION_END: u16 = 0x_FF_F2;
19const FIELD_LINE: u16 = 0x_FF_F3;
20const FIELD_COLUMN: u16 = 0x_FF_F4;
21
22#[derive(Debug)]
26pub struct Error(pub(crate) Box<Inner>);
27
28pub struct Chain<'a>(Option<&'a (dyn StdError + 'static)>);
29
30#[derive(Clone, Copy)]
32pub struct Tag {
33 pub(crate) bit: u32,
34}
35
36pub(crate) enum Source {
37 Box(Box<dyn StdError + Send + Sync + 'static>),
38 Ref(Box<dyn AsRef<dyn StdError + Send + Sync + 'static> + Send + Sync + 'static>),
39}
40
41#[derive(Debug)]
42pub(crate) struct Inner {
43 pub code: u32,
44 pub messages: Vec<Cow<'static, str>>,
46 pub error: Option<Source>,
47 pub headers: HashMap<u16, bytes::Bytes>,
49 pub fields: HashMap<(&'static str, TypeId), Box<dyn Any + Send + Sync>>,
50}
51
52impl Error {
53 pub fn is<T: ErrorKind>(&self) -> bool {
54 T::is_superclass_of(self.0.code)
55 }
56 pub fn has_tag(&self, tag: Tag) -> bool {
57 tag_check(self.0.code, tag.bit)
58 }
59 pub fn chain(&self) -> Chain {
60 Chain(Some(self))
61 }
62 pub fn context<S: Into<Cow<'static, str>>>(mut self, msg: S) -> Error {
63 self.0.messages.push(msg.into());
64 self
65 }
66 pub fn headers(&self) -> &HashMap<u16, bytes::Bytes> {
67 &self.0.headers
68 }
69 pub fn with_headers(mut self, headers: HashMap<u16, bytes::Bytes>) -> Error {
70 self.0.headers = headers;
71 self
72 }
73 pub fn kind_name(&self) -> &str {
74 error_name(self.0.code)
75 }
76 pub fn kind_debug(&self) -> impl fmt::Display {
77 format!("{} [0x{:08X}]", error_name(self.0.code), self.0.code)
78 }
79 pub fn initial_message(&self) -> Option<&str> {
80 self.0.messages.first().map(|m| &m[..])
81 }
82 pub fn contexts(&self) -> impl DoubleEndedIterator<Item = &str> {
83 self.0.messages.iter().skip(1).map(|m| &m[..])
84 }
85 fn header(&self, field: u16) -> Option<&str> {
86 if let Some(value) = self.headers().get(&field) {
87 if let Ok(value) = str::from_utf8(value) {
88 return Some(value);
89 }
90 }
91 None
92 }
93 fn usize_header(&self, field: u16) -> Option<usize> {
94 self.header(field)
95 .and_then(|x| x.parse::<u32>().ok())
96 .map(|x| x as usize)
97 }
98 pub fn hint(&self) -> Option<&str> {
99 self.header(FIELD_HINT)
100 }
101 pub fn details(&self) -> Option<&str> {
102 self.header(FIELD_DETAILS)
103 }
104 pub fn server_traceback(&self) -> Option<&str> {
105 self.header(FIELD_SERVER_TRACEBACK)
106 }
107 pub fn position_start(&self) -> Option<usize> {
108 self.usize_header(FIELD_POSITION_START)
109 }
110 pub fn position_end(&self) -> Option<usize> {
111 self.usize_header(FIELD_POSITION_END)
112 }
113 pub fn line(&self) -> Option<usize> {
114 self.usize_header(FIELD_LINE)
115 }
116 pub fn column(&self) -> Option<usize> {
117 self.usize_header(FIELD_COLUMN)
118 }
119 pub(crate) fn unknown_headers(&self) -> impl Iterator<Item = (&u16, &bytes::Bytes)> {
120 self.headers().iter().filter(|(key, _)| {
121 **key != FIELD_HINT
122 && **key != FIELD_DETAILS
123 && **key != FIELD_POSITION_START
124 && **key != FIELD_POSITION_END
125 && **key != FIELD_LINE
126 && **key != FIELD_COLUMN
127 })
128 }
129 pub fn from_code(code: u32) -> Error {
130 Error(Box::new(Inner {
131 code,
132 messages: Vec::new(),
133 error: None,
134 headers: HashMap::new(),
135 fields: HashMap::new(),
136 }))
137 }
138 pub fn code(&self) -> u32 {
139 self.0.code
140 }
141 pub fn refine_kind<T: ErrorKind>(mut self) -> Error {
142 self.0.code = T::CODE;
143 self
144 }
145 pub fn set<T: Field>(mut self, value: impl Into<T::Value>) -> Error {
146 self.0
147 .fields
148 .insert((T::NAME, TypeId::of::<T::Value>()), Box::new(value.into()));
149 self
150 }
151 pub fn get<T: Field>(&self) -> Option<&T::Value> {
152 self.0
153 .fields
154 .get(&(T::NAME, TypeId::of::<T::Value>()))
155 .and_then(|bx| bx.downcast_ref::<T::Value>())
156 }
157}
158
159impl fmt::Display for Error {
160 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161 let kind = self.kind_name();
162 if f.alternate() {
163 write!(f, "{}", kind)?;
164 for msg in self.0.messages.iter().rev() {
165 write!(f, ": {}", msg)?;
166 }
167 if let Some(mut src) = self.source() {
168 write!(f, ": {}", src)?;
169 while let Some(next) = src.source() {
170 write!(f, ": {}", next)?;
171 src = next;
172 }
173 }
174 } else if let Some(last) = self.0.messages.last() {
175 write!(f, "{}: {}", kind, last)?;
176 } else {
177 write!(f, "{}", kind)?;
178 }
179 if let Some((line, col)) = self.line().zip(self.column()) {
180 write!(f, " (on line {}, column {})", line, col)?;
181 }
182 if let Some(hint) = self.hint() {
183 write!(f, "\n Hint: {}", hint)?;
184 }
185 if let Some(detail) = self.details() {
186 write!(f, "\n Detail: {}", detail)?;
187 }
188 Ok(())
189 }
190}
191
192impl StdError for Error {
193 fn source(&self) -> Option<&(dyn StdError + 'static)> {
194 self.0.error.as_ref().map(|s| match s {
195 Source::Box(b) => b.as_ref() as &dyn std::error::Error,
196 Source::Ref(b) => (**b).as_ref() as &dyn std::error::Error,
197 })
198 }
199}
200
201impl fmt::Debug for Source {
202 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203 match self {
204 Source::Box(b) => fmt::Debug::fmt(b.as_ref(), f),
205 Source::Ref(b) => fmt::Debug::fmt((**b).as_ref(), f),
206 }
207 }
208}
209
210impl<T> From<T> for Error
211where
212 T: AsRef<dyn StdError + Send + Sync + 'static> + Send + Sync + 'static,
213{
214 fn from(err: T) -> Error {
215 UserError::with_source_ref(err)
216 }
217}
218
219impl<'a> Iterator for Chain<'a> {
220 type Item = &'a (dyn StdError + 'static);
221 fn next(&mut self) -> Option<Self::Item> {
222 let result = self.0.take();
223 self.0 = result.and_then(|e| e.source());
224 result
225 }
226}