1use core::fmt;
4
5#[derive(Debug)]
9pub enum Error<E> {
10 Timeout,
12 Closed,
14 Backend(E),
16}
17
18impl<E> Error<E> {
19 pub fn into_backend(self) -> Option<E> {
21 match self {
22 Error::Backend(e) => Some(e),
23 _ => None,
24 }
25 }
26}
27
28impl<E: fmt::Display> fmt::Display for Error<E> {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 match self {
31 Error::Timeout => f.write_str("timed out waiting for a pooled connection"),
32 Error::Closed => f.write_str("connection pool is closed"),
33 Error::Backend(e) => write!(f, "failed to establish connection: {e}"),
34 }
35 }
36}
37
38impl<E: std::error::Error + 'static> std::error::Error for Error<E> {
39 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
40 match self {
41 Error::Backend(e) => Some(e),
42 _ => None,
43 }
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use std::error::Error as _;
50
51 use super::*;
52
53 fn io() -> std::io::Error {
54 std::io::Error::new(std::io::ErrorKind::ConnectionRefused, "refused")
55 }
56
57 #[test]
58 fn into_backend_yields_the_manager_error() {
59 assert_eq!(Error::Backend("boom").into_backend(), Some("boom"));
60 }
61
62 #[test]
63 fn into_backend_is_none_for_pool_side_failures() {
64 assert_eq!(Error::<&str>::Timeout.into_backend(), None);
65 assert_eq!(Error::<&str>::Closed.into_backend(), None);
66 }
67
68 #[test]
69 fn display_names_the_failure_mode() {
70 assert_eq!(
71 Error::<&str>::Timeout.to_string(),
72 "timed out waiting for a pooled connection"
73 );
74 assert_eq!(
75 Error::<&str>::Closed.to_string(),
76 "connection pool is closed"
77 );
78 assert_eq!(
79 Error::Backend("refused").to_string(),
80 "failed to establish connection: refused"
81 );
82 }
83
84 #[test]
85 fn a_backend_error_is_the_source() {
86 let e = Error::Backend(io());
87 let source = e.source().expect("Backend must expose its cause");
88 assert_eq!(source.to_string(), io().to_string());
89 }
90
91 #[test]
92 fn pool_side_failures_have_no_source() {
93 assert!(Error::<std::io::Error>::Timeout.source().is_none());
94 assert!(Error::<std::io::Error>::Closed.source().is_none());
95 }
96
97 #[test]
98 fn is_debug() {
99 assert!(format!("{:?}", Error::<&str>::Timeout).contains("Timeout"));
100 assert!(format!("{:?}", Error::<&str>::Closed).contains("Closed"));
101 assert!(format!("{:?}", Error::Backend("x")).contains("Backend"));
102 }
103
104 #[test]
107 fn implements_std_error_for_std_error_payloads() {
108 fn assert_std_error<T: std::error::Error>(_: &T) {}
109 assert_std_error(&Error::Backend(io()));
110 }
111}