1#[cfg(feature = "std")]
2use alloc::boxed::Box;
3use core::fmt::{self, Display, Formatter};
4
5#[cfg(feature = "std")]
6use std::error::Error as StdError;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum ErrorKind {
11 Custom,
13
14 Encryption,
16
17 ExceededBuffer,
19
20 Invalid,
22
23 InvalidKeyData,
25
26 InvalidNonce,
28
29 MissingSecretKey,
31
32 Unexpected,
34
35 Usage,
37
38 Unsupported,
40}
41
42impl ErrorKind {
43 pub fn as_str(&self) -> &'static str {
45 match self {
46 Self::Custom => "Custom error",
47 Self::Encryption => "Encryption error",
48 Self::ExceededBuffer => "Exceeded buffer size",
49 Self::Invalid => "Invalid input",
50 Self::InvalidNonce => "Invalid encryption nonce",
51 Self::InvalidKeyData => "Invalid key data",
52 Self::MissingSecretKey => "Missing secret key",
53 Self::Unexpected => "Unexpected error",
54 Self::Usage => "Usage error",
55 Self::Unsupported => "Unsupported",
56 }
57 }
58}
59
60impl Display for ErrorKind {
61 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
62 f.write_str(self.as_str())
63 }
64}
65
66#[derive(Debug)]
68pub struct Error {
69 pub(crate) kind: ErrorKind,
70 #[cfg(feature = "std")]
71 pub(crate) cause: Option<Box<dyn StdError + Send + Sync + 'static>>,
72 pub(crate) message: Option<&'static str>,
73}
74
75impl Error {
76 pub fn from_msg(kind: ErrorKind, msg: &'static str) -> Self {
78 Self {
79 kind,
80 #[cfg(feature = "std")]
81 cause: None,
82 message: Some(msg),
83 }
84 }
85
86 pub fn kind(&self) -> ErrorKind {
88 self.kind
89 }
90
91 pub fn message(&self) -> &'static str {
93 self.message.unwrap_or_else(|| self.kind.as_str())
94 }
95
96 #[cfg(feature = "std")]
97 pub(crate) fn with_cause<T: Into<Box<dyn StdError + Send + Sync>>>(mut self, err: T) -> Self {
98 self.cause = Some(err.into());
99 self
100 }
101}
102
103impl Display for Error {
104 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
105 if let Some(msg) = self.message {
106 f.write_str(msg)?;
107 } else {
108 f.write_str(self.kind.as_str())?;
109 }
110 #[cfg(feature = "std")]
111 if let Some(cause) = self.cause.as_ref() {
112 write!(f, "\nCaused by: {}", cause)?;
113 }
114 Ok(())
115 }
116}
117
118#[cfg(feature = "std")]
119impl StdError for Error {
120 fn source(&self) -> Option<&(dyn StdError + 'static)> {
121 self.cause.as_ref().map(|err| {
122 (&**err) as &dyn StdError
125 })
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 #[cfg(feature = "std")]
140 cause: None,
141 message: None,
142 }
143 }
144}
145
146#[macro_export]
147macro_rules! err_msg {
149 ($kind:ident) => {
150 $crate::Error::from($crate::ErrorKind::$kind)
151 };
152 ($kind:ident, $msg:expr) => {
153 $crate::Error::from_msg($crate::ErrorKind::$kind, $msg)
154 };
155}
156
157#[cfg(feature = "std")]
158#[macro_export]
160macro_rules! err_map {
161 ($($params:tt)*) => {
162 |err| err_msg!($($params)*).with_cause(err)
163 };
164}
165
166#[cfg(not(feature = "std"))]
167#[macro_export]
169macro_rules! err_map {
170 ($($params:tt)*) => {
171 |_| err_msg!($($params)*)
172 };
173}
174
175#[cfg(all(test, feature = "std"))]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn downcast_err() {
182 #[derive(Debug)]
183 struct E;
184 impl Display for E {
185 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
186 write!(f, "E")
187 }
188 }
189 impl StdError for E {}
190
191 let err = Error::from(ErrorKind::Unexpected).with_cause(E);
192 let e = err.source().unwrap().downcast_ref::<E>();
193 assert!(e.is_some());
194 }
195}