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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use std::fmt;
use std::str;
use std::collections::BTreeMap;
use bytes::Bytes;
use edgedb_errors::{Error, InternalServerError};
pub use crate::server_message::{ErrorSeverity, ErrorResponse};
pub const FIELD_HINT: u16 = 0x_00_01;
pub const FIELD_DETAILS: u16 = 0x_00_02;
pub const FIELD_SERVER_TRACEBACK: u16 = 0x_01_01;
pub const FIELD_POSITION_START: u16 = 0x_FF_F1;
pub const FIELD_POSITION_END: u16 = 0x_FF_F2;
pub const FIELD_LINE: u16 = 0x_FF_F3;
pub const FIELD_COLUMN: u16 = 0x_FF_F4;
pub struct DisplayError<'a>(&'a Error, bool);
pub struct VerboseError<'a>(&'a Error);
struct DisplayNum<'a>(Option<&'a Bytes>);
pub fn display_error(e: &Error, verbose: bool) -> DisplayError {
DisplayError(e, verbose)
}
pub fn display_error_verbose(e: &Error) -> VerboseError {
VerboseError(e)
}
impl Into<Error> for ErrorResponse {
fn into(self) -> Error {
Error::from_code(self.code)
.context(self.message)
.with_headers(self.attributes)
}
}
impl fmt::Display for DisplayError<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let DisplayError(ref e, verbose) = self;
write!(f, "{:#}", e)?;
if let Some(hint) = e.headers().get(&FIELD_HINT) {
if let Ok(hint) = str::from_utf8(hint) {
write!(f, "\n Hint: {}", hint)?;
}
}
if let Some(detail) = e.headers().get(&FIELD_DETAILS) {
if let Ok(detail) = str::from_utf8(detail) {
write!(f, "\n Detail: {}", detail)?;
}
}
if e.is::<InternalServerError>() || *verbose {
let tb = e.headers().get(&FIELD_SERVER_TRACEBACK);
if let Some(traceback) = tb {
if let Ok(traceback) = str::from_utf8(traceback) {
write!(f, "\n Server traceback:")?;
for line in traceback.lines() {
write!(f, "\n {}", line)?;
}
}
}
}
Ok(())
}
}
impl fmt::Display for DisplayNum<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let num = self.0.as_ref()
.and_then(|x| str::from_utf8(x).ok())
.and_then(|x| x.parse::<usize>().ok());
match num {
Some(x) => x.fmt(f),
None => "?".fmt(f),
}
}
}
impl fmt::Display for VerboseError<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let e = self.0;
writeln!(f, "Error type: {}", e.kind_debug())?;
writeln!(f, "Message: {:#}", e)?;
let mut attr = e.headers().iter().collect::<BTreeMap<_, _>>();
if let Some(hint) = attr.remove(&FIELD_HINT) {
if let Ok(hint) = str::from_utf8(hint) {
writeln!(f, "Hint: {}", hint)?;
}
}
if let Some(detail) = attr.remove(&FIELD_DETAILS) {
if let Ok(detail) = str::from_utf8(detail) {
writeln!(f, "Detail: {}", detail)?;
}
}
if let Some(hint) = attr.remove(&FIELD_HINT) {
if let Ok(hint) = str::from_utf8(hint) {
writeln!(f, "Hint: {}", hint)?;
}
}
let pstart = attr.remove(&FIELD_POSITION_START);
let pend = attr.remove(&FIELD_POSITION_END);
let line = attr.remove(&FIELD_LINE);
let column = attr.remove(&FIELD_COLUMN);
if [pstart, pend, line, column].iter().any(|x| x.is_some()) {
writeln!(f, "Span: {}-{}, line {}, column {}",
DisplayNum(pstart), DisplayNum(pend),
DisplayNum(line), DisplayNum(column))?;
}
if let Some(traceback) = attr.remove(&FIELD_SERVER_TRACEBACK) {
if let Ok(traceback) = str::from_utf8(traceback) {
writeln!(f, "Server traceback:")?;
for line in traceback.lines() {
writeln!(f, " {}", line)?;
}
}
}
if !attr.is_empty() {
writeln!(f, "Other attributes:")?;
for (k, v) in attr {
writeln!(f, " 0x{:04x}: {:?}", k, v)?;
}
}
Ok(())
}
}