1#[derive(Debug)]
5#[non_exhaustive]
6pub enum Error {
7 Unsupported,
9
10 Unavailable(String),
12
13 Format(String),
15
16 Platform(Box<dyn std::error::Error + Send + Sync>),
18}
19
20impl std::fmt::Display for Error {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 match self {
23 Error::Unsupported => write!(f, "operation not supported on this platform"),
24 Error::Unavailable(msg) => write!(f, "theme data unavailable: {msg}"),
25 Error::Format(msg) => write!(f, "theme format error: {msg}"),
26 Error::Platform(err) => write!(f, "platform error: {err}"),
27 }
28 }
29}
30
31impl std::error::Error for Error {
32 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
33 match self {
34 Error::Platform(err) => Some(&**err),
35 _ => None,
36 }
37 }
38}
39
40impl From<toml::de::Error> for Error {
41 fn from(err: toml::de::Error) -> Self {
42 Error::Format(err.to_string())
43 }
44}
45
46impl From<toml::ser::Error> for Error {
47 fn from(err: toml::ser::Error) -> Self {
48 Error::Format(err.to_string())
49 }
50}
51
52impl From<std::io::Error> for Error {
53 fn from(err: std::io::Error) -> Self {
54 Error::Unavailable(err.to_string())
55 }
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn unsupported_display() {
64 let err = Error::Unsupported;
65 let msg = err.to_string();
66 assert!(msg.contains("not supported"), "got: {msg}");
67 }
68
69 #[test]
70 fn unavailable_display() {
71 let err = Error::Unavailable("file not found".into());
72 let msg = err.to_string();
73 assert!(msg.contains("unavailable"), "got: {msg}");
74 assert!(msg.contains("file not found"), "got: {msg}");
75 }
76
77 #[test]
78 fn format_display() {
79 let err = Error::Format("invalid TOML".into());
80 let msg = err.to_string();
81 assert!(msg.contains("format error"), "got: {msg}");
82 assert!(msg.contains("invalid TOML"), "got: {msg}");
83 }
84
85 #[test]
86 fn platform_display() {
87 let inner = std::io::Error::other("dbus failure");
88 let err = Error::Platform(Box::new(inner));
89 let msg = err.to_string();
90 assert!(msg.contains("platform error"), "got: {msg}");
91 assert!(msg.contains("dbus failure"), "got: {msg}");
92 }
93
94 #[test]
95 fn platform_source_returns_inner() {
96 let inner = std::io::Error::other("inner error");
97 let err = Error::Platform(Box::new(inner));
98 let source = std::error::Error::source(&err);
99 assert!(source.is_some());
100 assert!(source.unwrap().to_string().contains("inner error"));
101 }
102
103 #[test]
104 fn non_platform_source_is_none() {
105 assert!(std::error::Error::source(&Error::Unsupported).is_none());
106 assert!(std::error::Error::source(&Error::Unavailable("x".into())).is_none());
107 assert!(std::error::Error::source(&Error::Format("x".into())).is_none());
108 }
109
110 #[test]
111 fn error_is_send_sync() {
112 fn assert_send_sync<T: Send + Sync>() {}
113 assert_send_sync::<Error>();
114 }
115
116 #[test]
117 fn from_toml_de_error() {
118 let toml_err: Result<toml::Value, toml::de::Error> = toml::from_str("=invalid");
120 let err: Error = toml_err.unwrap_err().into();
121 match &err {
122 Error::Format(msg) => assert!(!msg.is_empty()),
123 other => panic!("expected Format variant, got: {other:?}"),
124 }
125 }
126
127 #[test]
128 fn from_io_error() {
129 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "missing file");
130 let err: Error = io_err.into();
131 match &err {
132 Error::Unavailable(msg) => assert!(msg.contains("missing file")),
133 other => panic!("expected Unavailable variant, got: {other:?}"),
134 }
135 }
136}