1use std::fmt::Display;
2use thiserror::*;
3
4#[derive(Error, Debug)]
11#[error(transparent)]
12pub struct Error(pub(crate) InternalError);
13
14pub type Result<T> = std::result::Result<T, Error>;
16
17impl<E> From<E> for Error
18where
19 E: Into<InternalError>,
20{
21 fn from(err: E) -> Self {
22 Self(err.into())
23 }
24}
25
26#[derive(Error, Debug)]
33#[non_exhaustive]
34#[doc(hidden)]
35pub enum InternalError {
36 #[error(transparent)]
37 Fmt(#[from] std::fmt::Error),
38
39 #[error(transparent)]
40 Io(#[from] std::io::Error),
41
42 #[error(transparent)]
43 Regex(#[from] fancy_regex::Error),
44
45 #[error(transparent)]
46 FromUtf8(#[from] std::string::FromUtf8Error),
47
48 #[error(transparent)]
49 Utf8(#[from] std::str::Utf8Error),
50
51 #[error(transparent)]
52 Base64(#[from] base64::DecodeError),
53
54 #[error(transparent)]
55 ParseFloat(#[from] std::num::ParseFloatError),
56
57 #[error(transparent)]
58 ParseInt(#[from] std::num::ParseIntError),
59
60 #[error(transparent)]
61 FloatIsNan(#[from] ordered_float::FloatIsNan),
62
63 #[error("{0}")]
64 StringErr(#[from] StringWrap),
65
66 #[error(transparent)]
67 Anyhow(#[from] anyhow::Error),
68
69 #[error(transparent)]
70 Terminfo(#[from] terminfo::Error),
71
72 #[error(transparent)]
73 FileDescriptor(#[from] filedescriptor::Error),
74
75 #[error(transparent)]
76 BlobLease(#[from] wezterm_blob_leases::Error),
77
78 #[cfg(feature = "use_image")]
79 #[error(transparent)]
80 ImageError(#[from] image::ImageError),
81
82 #[error("{}", .context)]
83 Context {
84 context: String,
85 source: Box<dyn std::error::Error + Send + Sync + 'static>,
86 },
87}
88
89impl From<String> for InternalError {
90 fn from(s: String) -> Self {
91 InternalError::StringErr(StringWrap(s))
92 }
93}
94
95#[derive(Error, Debug)]
96#[doc(hidden)]
97#[error("{0}")]
98pub struct StringWrap(pub String);
99
100#[macro_export]
101macro_rules! format_err {
102 ($msg:literal $(,)?) => {
103 return $crate::error::Error::from($crate::error::StringWrap($msg.to_string()))
104 };
105 ($err:expr $(,)?) => {
106 return $crate::error::Error::from($crate::error::StringWrap(format!($err)))
107 };
108 ($fmt:expr, $($arg:tt)*) => {
109 return $crate::error::Error::from($crate::error::StringWrap(format!($fmt, $($arg)*)))
110 };
111}
112
113#[macro_export]
114macro_rules! bail {
115 ($msg:literal $(,)?) => {
116 return Err($crate::error::StringWrap($msg.to_string()).into())
117 };
118 ($err:expr $(,)?) => {
119 return Err($crate::error::StringWrap(format!($err)).into())
120 };
121 ($fmt:expr, $($arg:tt)*) => {
122 return Err($crate::error::StringWrap(format!($fmt, $($arg)*)).into())
123 };
124}
125
126#[macro_export]
127macro_rules! ensure {
128 ($cond:expr, $msg:literal $(,)?) => {
129 if !$cond {
130 return Err($crate::error::StringWrap(format!($msg)).into());
131 }
132 };
133 ($cond:expr, $err:expr $(,)?) => {
134 if !$cond {
135 return Err($crate::error::StringWrap(format!($err)).into());
136 }
137 };
138 ($cond:expr, $fmt:expr, $($arg:tt)*) => {
139 if !$cond {
140 return Err($crate::error::StringWrap(format!($fmt, $($arg)*)).into());
141 }
142 };
143}
144
145pub trait Context<T, E> {
149 fn context<C>(self, context: C) -> Result<T>
151 where
152 C: Display + Send + Sync + 'static;
153
154 fn with_context<C, F>(self, f: F) -> Result<T>
157 where
158 C: Display + Send + Sync + 'static,
159 F: FnOnce() -> C;
160}
161
162impl<T, E> Context<T, E> for std::result::Result<T, E>
163where
164 E: std::error::Error + Send + Sync + 'static,
165{
166 fn context<C>(self, context: C) -> Result<T>
167 where
168 C: Display + Send + Sync + 'static,
169 {
170 self.map_err(|error| {
171 Error(InternalError::Context {
172 context: context.to_string(),
173 source: Box::new(error),
174 })
175 })
176 }
177
178 fn with_context<C, F>(self, context: F) -> Result<T>
179 where
180 C: Display + Send + Sync + 'static,
181 F: FnOnce() -> C,
182 {
183 self.map_err(|error| {
184 Error(InternalError::Context {
185 context: context().to_string(),
186 source: Box::new(error),
187 })
188 })
189 }
190}