1use std::error::Error as StdError;
2use std::fmt::{self, Display, Formatter};
3
4use crate::crypto::{Error as CryptoError, ErrorKind as CryptoErrorKind};
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub enum ErrorKind {
9 Backend,
11
12 Busy,
14
15 Custom,
17
18 Duplicate,
20
21 Encryption,
23
24 Input,
26
27 NotFound,
29
30 Unexpected,
32
33 Unsupported,
35}
36
37impl ErrorKind {
38 pub fn as_str(&self) -> &'static str {
40 match self {
41 Self::Backend => "Backend error",
42 Self::Busy => "Busy",
43 Self::Custom => "Custom error",
44 Self::Duplicate => "Duplicate",
45 Self::Encryption => "Encryption error",
46 Self::Input => "Input error",
47 Self::NotFound => "Not found",
48 Self::Unexpected => "Unexpected error",
49 Self::Unsupported => "Unsupported",
50 }
51 }
52}
53
54impl Display for ErrorKind {
55 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
56 f.write_str(self.as_str())
57 }
58}
59
60#[derive(Debug)]
62pub struct Error {
63 pub(crate) kind: ErrorKind,
64 pub(crate) cause: Option<Box<dyn StdError + Send + Sync + 'static>>,
65 pub(crate) message: Option<String>,
66}
67
68impl Error {
69 pub(crate) fn from_msg<T: Into<String>>(kind: ErrorKind, msg: T) -> Self {
70 Self {
71 kind,
72 cause: None,
73 message: Some(msg.into()),
74 }
75 }
76
77 pub fn kind(&self) -> ErrorKind {
79 self.kind
80 }
81
82 pub fn message(&self) -> Option<&str> {
84 self.message.as_deref()
85 }
86
87 pub fn into_parts(
89 self,
90 ) -> (
91 ErrorKind,
92 Option<Box<dyn StdError + Send + Sync + 'static>>,
93 Option<String>,
94 ) {
95 (self.kind, self.cause, self.message)
96 }
97
98 pub(crate) fn with_cause<T: Into<Box<dyn StdError + Send + Sync + 'static>>>(
99 mut self,
100 err: T,
101 ) -> Self {
102 self.cause = Some(err.into());
103 self
104 }
105}
106
107impl Display for Error {
108 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
109 if let Some(msg) = self.message.as_ref() {
110 f.write_str(msg)?;
111 } else {
112 f.write_str(self.kind.as_str())?;
113 }
114 if let Some(cause) = self.cause.as_ref() {
115 write!(f, "\nCaused by: {}", cause)?;
116 }
117 Ok(())
118 }
119}
120
121impl StdError for Error {
122 fn source(&self) -> Option<&(dyn StdError + 'static)> {
123 self.cause
124 .as_ref()
125 .map(|err| &**err as &(dyn StdError + 'static))
126 }
127}
128
129impl PartialEq for Error {
130 fn eq(&self, other: &Self) -> bool {
131 self.kind == other.kind && self.message == other.message
132 }
133}
134
135impl From<ErrorKind> for Error {
136 fn from(kind: ErrorKind) -> Self {
137 Self {
138 kind,
139 cause: None,
140 message: None,
141 }
142 }
143}
144
145#[cfg(any(feature = "postgres", feature = "sqlite"))]
148impl From<sqlx::Error> for Error {
149 fn from(err: sqlx::Error) -> Self {
150 Error::from(ErrorKind::Backend).with_cause(err)
151 }
152}
153
154impl From<CryptoError> for Error {
155 fn from(err: CryptoError) -> Self {
156 let kind = match err.kind() {
157 CryptoErrorKind::Custom => ErrorKind::Custom,
158 CryptoErrorKind::Encryption => ErrorKind::Encryption,
159 CryptoErrorKind::ExceededBuffer | CryptoErrorKind::Unexpected => ErrorKind::Unexpected,
160 CryptoErrorKind::Invalid
161 | CryptoErrorKind::InvalidKeyData
162 | CryptoErrorKind::InvalidNonce
163 | CryptoErrorKind::MissingSecretKey
164 | CryptoErrorKind::Usage => ErrorKind::Input,
165 CryptoErrorKind::Unsupported => ErrorKind::Unsupported,
166 };
167 Error::from_msg(kind, err.message())
168 }
169}
170
171macro_rules! err_msg {
172 () => {
173 $crate::error::Error::from($crate::error::ErrorKind::Input)
174 };
175 ($kind:ident) => {
176 $crate::error::Error::from($crate::error::ErrorKind::$kind)
177 };
178 ($kind:ident, $($args:tt)+) => {
179 $crate::error::Error::from_msg($crate::error::ErrorKind::$kind, format!($($args)+))
180 };
181 ($($args:tt)+) => {
182 $crate::error::Error::from_msg($crate::error::ErrorKind::Input, format!($($args)+))
183 };
184}
185
186macro_rules! err_map {
187 ($($params:tt)*) => {
188 |err| err_msg!($($params)*).with_cause(err)
189 };
190}