1use std::fmt::{Debug, Display};
15
16#[derive(Debug)]
18pub struct Error<Kind>
19where
20 Kind: Clone + Debug + Display + PartialEq,
21{
22 pub(crate) kind: Kind,
23 pub(crate) source: Option<crate::Error>,
24}
25
26impl<Kind> Error<Kind>
27where
28 Kind: Clone + Debug + Display + PartialEq,
29{
30 pub(crate) fn new(kind: Kind) -> Self {
31 Self { kind, source: None }
32 }
33
34 pub(crate) fn with_source<S>(kind: Kind, source: S) -> Self
35 where
36 S: Into<crate::Error>,
37 {
38 Self {
39 kind,
40 source: Some(source.into()),
41 }
42 }
43
44 pub fn kind(&self) -> Kind {
46 self.kind.clone()
47 }
48}
49
50impl<Kind> Display for Error<Kind>
51where
52 Kind: Clone + Debug + Display + PartialEq,
53{
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 if let Some(err) = &self.source {
56 write!(f, "{}: {}", self.kind, err)
57 } else {
58 write!(f, "{}", self.kind)
59 }
60 }
61}
62
63impl<Kind> std::error::Error for Error<Kind>
64where
65 Kind: Clone + Debug + Display + PartialEq,
66{
67 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
68 self.source
69 .as_ref()
70 .map(|boxed| boxed.as_ref() as &(dyn std::error::Error + 'static))
71 }
72}
73
74impl<Kind> From<Kind> for Error<Kind>
75where
76 Kind: Clone + Debug + Display + PartialEq,
77{
78 fn from(kind: Kind) -> Self {
79 Self { kind, source: None }
80 }
81}
82
83#[cfg(test)]
84mod test {
85 #![allow(dead_code)]
86
87 use super::*;
88 use std::fmt::Formatter;
89
90 #[derive(Clone, Debug, PartialEq)]
92 enum FooErrorKind {
93 Bar,
94 Baz,
95 }
96
97 impl Display for FooErrorKind {
98 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
99 match self {
100 Self::Bar => write!(f, "bar error"),
101 Self::Baz => write!(f, "baz error"),
102 }
103 }
104 }
105
106 type FooError = Error<FooErrorKind>;
108
109 #[test]
110 fn new() {
111 let error = FooError::new(FooErrorKind::Bar);
112 assert_eq!(error.kind, FooErrorKind::Bar);
113 assert!(error.source.is_none());
114 }
115
116 #[test]
117 fn with_source() {
118 let source = std::io::Error::new(std::io::ErrorKind::Other, "foo");
119 let error = FooError::with_source(FooErrorKind::Bar, source);
120 assert_eq!(error.kind, FooErrorKind::Bar);
121 assert_eq!(error.source.unwrap().to_string(), "foo");
122 }
123
124 #[test]
125 fn kind() {
126 let error: FooError = FooErrorKind::Bar.into();
127 let kind = error.kind();
128 let _ = error.kind();
130 assert_eq!(kind, FooErrorKind::Bar);
131 }
132
133 #[test]
134 fn display_without_source() {
135 let error: FooError = FooErrorKind::Bar.into();
136 assert_eq!(format!("{}", error), "bar error");
137 }
138
139 #[test]
140 fn from() {
141 let error: FooError = FooErrorKind::Bar.into();
142 assert_eq!(error.kind, FooErrorKind::Bar);
143 assert!(error.source.is_none());
144 }
145}