1use std::error;
2use std::fmt;
3
4#[cfg(not(target_family = "wasm"))]
5use std::time::Duration;
6#[cfg(target_family = "wasm")]
7use web_time::Duration;
8
9pub enum Error<E> {
15 Permanent(E),
18
19 Transient {
23 err: E,
24 retry_after: Option<Duration>,
25 },
26}
27
28impl<E> Error<E> {
29 pub fn permanent(err: E) -> Self {
31 Error::Permanent(err)
32 }
33
34 pub fn transient(err: E) -> Self {
37 Error::Transient {
38 err,
39 retry_after: None,
40 }
41 }
42
43 pub fn retry_after(err: E, duration: Duration) -> Self {
46 Error::Transient {
47 err,
48 retry_after: Some(duration),
49 }
50 }
51}
52
53impl<E> fmt::Display for Error<E>
54where
55 E: fmt::Display,
56{
57 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
58 match *self {
59 Error::Permanent(ref err)
60 | Error::Transient {
61 ref err,
62 retry_after: _,
63 } => err.fmt(f),
64 }
65 }
66}
67
68impl<E> fmt::Debug for Error<E>
69where
70 E: fmt::Debug,
71{
72 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
73 let (name, err) = match *self {
74 Error::Permanent(ref err) => ("Permanent", err as &dyn fmt::Debug),
75 Error::Transient {
76 ref err,
77 retry_after: _,
78 } => ("Transient", err as &dyn fmt::Debug),
79 };
80 f.debug_tuple(name).field(err).finish()
81 }
82}
83
84impl<E> error::Error for Error<E>
85where
86 E: error::Error,
87{
88 fn description(&self) -> &str {
89 match *self {
90 Error::Permanent(_) => "permanent error",
91 Error::Transient { .. } => "transient error",
92 }
93 }
94
95 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
96 match *self {
97 Error::Permanent(ref err)
98 | Error::Transient {
99 ref err,
100 retry_after: _,
101 } => err.source(),
102 }
103 }
104
105 fn cause(&self) -> Option<&dyn error::Error> {
106 self.source()
107 }
108}
109
110impl<E> From<E> for Error<E> {
114 fn from(err: E) -> Error<E> {
115 Error::Transient {
116 err,
117 retry_after: None,
118 }
119 }
120}
121
122impl<E> PartialEq for Error<E>
123where
124 E: PartialEq,
125{
126 fn eq(&self, other: &Self) -> bool {
127 match (self, other) {
128 (Error::Permanent(self_err), Error::Permanent(other_err)) => self_err == other_err,
129 (
130 Error::Transient {
131 err: self_err,
132 retry_after: self_retry_after,
133 },
134 Error::Transient {
135 err: other_err,
136 retry_after: other_retry_after,
137 },
138 ) => self_err == other_err && self_retry_after == other_retry_after,
139 _ => false,
140 }
141 }
142}
143
144#[test]
145fn create_permanent_error() {
146 let e = Error::permanent("err");
147 assert_eq!(e, Error::Permanent("err"));
148}
149
150#[test]
151fn create_transient_error() {
152 let e = Error::transient("err");
153 assert_eq!(
154 e,
155 Error::Transient {
156 err: "err",
157 retry_after: None
158 }
159 );
160}
161
162#[test]
163fn create_transient_error_with_retry_after() {
164 let retry_after = Duration::from_secs(42);
165 let e = Error::retry_after("err", retry_after);
166 assert_eq!(
167 e,
168 Error::Transient {
169 err: "err",
170 retry_after: Some(retry_after),
171 }
172 );
173}