hcproto/
error.rs

1use std::{error, fmt::{self, Display}, io};
2
3use serde::{de, ser};
4
5/// An enum of all error kinds.
6#[derive(PartialEq, Eq, Copy, Clone, Debug)]
7pub enum ErrorKind {
8    /// will read bytes over than left bytes
9    NoLeftSpaceError,
10    /// the buffer over max
11    BufferOverMaxError,
12    /// The type not match
13    TypeNotMatchError,
14    /// the buffer can't parse the right data
15    ParseError,
16    /// miss the major data
17    MissingError,
18    /// string format must be utf-8
19    StringFormatError,
20    /// This kind is returned if the redis error is one that is
21    /// not native to the system.  This is usually the case if
22    /// the cause is another error.
23    IoError,
24    /// An extension error.  This is an error created by the server
25    /// that is not directly understood by the library.
26    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
37/// Represents a redis error.  For the most part you should be using
38/// the Error trait to interact with this rather than the actual
39/// struct.
40pub struct HpError {
41    repr: ErrorRepr,
42}
43
44/// Library generic result type.
45pub 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
123/// Indicates a general failure in the library.
124impl HpError {
125    /// Returns the kind of the error.
126    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    /// Returns the name of the error category for display purposes.
136    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    /// Indicates that this failure is an IO failure.
150    pub fn is_io_error(&self) -> bool {
151        match self.kind() {
152            ErrorKind::IoError => true,
153            _ => false,
154        }
155    }
156
157    /// Returns the extension error code
158    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    /// Returns the extension error detail
166    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}