1use std::{error, fmt::{self, Display}, io};
2
3use serde::{de, ser};
4
5#[derive(PartialEq, Eq, Copy, Clone, Debug)]
7pub enum ErrorKind {
8 NoLeftSpaceError,
10 BufferOverMaxError,
12 TypeNotMatchError,
14 ParseError,
16 MissingError,
18 StringFormatError,
20 IoError,
24 ExtensionError,
27}
28
29#[derive(Debug)]
30enum ErrorRepr {
31 WithDescription(ErrorKind, &'static str),
32 WithDescriptionAndDetail(ErrorKind, &'static str, String),
33 ExtensionError(String, String),
34 IoError(io::Error),
35}
36
37pub struct HpError {
41 repr: ErrorRepr,
42}
43
44pub type HpResult<T> = Result<T, HpError>;
46
47impl PartialEq for HpError {
48 fn eq(&self, other: &HpError) -> bool {
49 match (&self.repr, &other.repr) {
50 (&ErrorRepr::WithDescription(kind_a, _), &ErrorRepr::WithDescription(kind_b, _)) => {
51 kind_a == kind_b
52 }
53 (
54 &ErrorRepr::WithDescriptionAndDetail(kind_a, _, _),
55 &ErrorRepr::WithDescriptionAndDetail(kind_b, _, _),
56 ) => kind_a == kind_b,
57 (&ErrorRepr::ExtensionError(ref a, _), &ErrorRepr::ExtensionError(ref b, _)) => {
58 *a == *b
59 }
60 _ => false,
61 }
62 }
63}
64
65impl From<io::Error> for HpError {
66 fn from(err: io::Error) -> HpError {
67 HpError {
68 repr: ErrorRepr::IoError(err),
69 }
70 }
71}
72
73impl From<(ErrorKind, &'static str)> for HpError {
74 fn from((kind, desc): (ErrorKind, &'static str)) -> HpError {
75 HpError {
76 repr: ErrorRepr::WithDescription(kind, desc),
77 }
78 }
79}
80
81impl From<(ErrorKind, &'static str, String)> for HpError {
82 fn from((kind, desc, detail): (ErrorKind, &'static str, String)) -> HpError {
83 HpError {
84 repr: ErrorRepr::WithDescriptionAndDetail(kind, desc, detail),
85 }
86 }
87}
88
89impl error::Error for HpError {
90 fn cause(&self) -> Option<&dyn error::Error> {
91 match self.repr {
92 ErrorRepr::IoError(ref err) => Some(err as &dyn error::Error),
93 _ => None,
94 }
95 }
96}
97
98impl fmt::Display for HpError {
99 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
100 match self.repr {
101 ErrorRepr::WithDescription(_, desc) => desc.fmt(f),
102 ErrorRepr::WithDescriptionAndDetail(_, desc, ref detail) => {
103 desc.fmt(f)?;
104 f.write_str(": ")?;
105 detail.fmt(f)
106 }
107 ErrorRepr::ExtensionError(ref code, ref detail) => {
108 code.fmt(f)?;
109 f.write_str(": ")?;
110 detail.fmt(f)
111 }
112 ErrorRepr::IoError(ref err) => err.fmt(f),
113 }
114 }
115}
116
117impl fmt::Debug for HpError {
118 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
119 fmt::Display::fmt(self, f)
120 }
121}
122
123impl HpError {
125 pub fn kind(&self) -> ErrorKind {
127 match self.repr {
128 ErrorRepr::WithDescription(kind, _) => kind,
129 ErrorRepr::WithDescriptionAndDetail(kind, _, _) => kind,
130 ErrorRepr::ExtensionError(_, _) => ErrorKind::ExtensionError,
131 ErrorRepr::IoError(_) => ErrorKind::IoError,
132 }
133 }
134
135 pub fn category(&self) -> &str {
137 match self.kind() {
138 ErrorKind::NoLeftSpaceError => "no left space error",
139 ErrorKind::BufferOverMaxError => "buffer over max error",
140 ErrorKind::TypeNotMatchError => "type not match error",
141 ErrorKind::ParseError => "parse error",
142 ErrorKind::MissingError => "missing error",
143 ErrorKind::StringFormatError => "string format error",
144 ErrorKind::IoError => "I/O error",
145 ErrorKind::ExtensionError => "extension error",
146 }
147 }
148
149 pub fn is_io_error(&self) -> bool {
151 match self.kind() {
152 ErrorKind::IoError => true,
153 _ => false,
154 }
155 }
156
157 pub fn extension_error_code(&self) -> Option<&str> {
159 match self.repr {
160 ErrorRepr::ExtensionError(ref code, _) => Some(&code),
161 _ => None,
162 }
163 }
164
165 pub fn extension_error_detail(&self) -> Option<&str> {
167 match self.repr {
168 ErrorRepr::ExtensionError(_, ref detail) => Some(&detail),
169 ErrorRepr::WithDescriptionAndDetail(_, _, ref detail) => Some(&detail),
170 _ => None,
171 }
172 }
173}
174
175pub fn make_extension_error(code: &str, detail: Option<&str>) -> HpError {
176 HpError {
177 repr: ErrorRepr::ExtensionError(
178 code.to_string(),
179 match detail {
180 Some(x) => x.to_string(),
181 None => "Unknown extension error encountered".to_string(),
182 },
183 ),
184 }
185}
186
187
188impl ser::Error for HpError {
189 fn custom<T: Display>(msg: T) -> Self {
190 HpError {
191 repr: ErrorRepr::ExtensionError(
192 "ser".to_string(),
193 msg.to_string(),
194 ),
195 }
196 }
197}
198
199impl de::Error for HpError {
200 fn custom<T: Display>(msg: T) -> Self {
201 HpError {
202 repr: ErrorRepr::ExtensionError(
203 "de".to_string(),
204 msg.to_string(),
205 ),
206 }
207 }
208}