1use darling::Error as DarlingError;
8use failure::{Error, Fail};
9use proc_macro2::Span;
10use proc_macro2::TokenStream;
11use quote::ToTokens;
12use std::fmt;
13use std::fmt::Display;
14use std::path::PathBuf;
15use std::sync::{Arc, Mutex};
16
17#[derive(Debug, Fail)]
18pub enum TracersError {
19 InvalidProvider {
20 message: String,
21 #[fail(cause)]
22 syn_error: Error,
23 },
24
25 SynError {
26 message: String,
27 #[fail(cause)]
28 syn_error: Error,
29 },
30
31 DarlingError {
32 message: String,
33 darling_error: Arc<Mutex<DarlingError>>,
34 },
35
36 InvalidCallExpression {
37 message: String,
38 #[fail(cause)]
39 syn_error: Error,
40 },
41
42 OtherError {
43 message: String,
44 #[fail(cause)]
45 error: Error,
46 },
47
48 MissingCallInBuildRs,
49
50 BuildInfoReadError {
51 message: String,
52 build_info_path: String,
53 #[fail(cause)]
54 error: Error,
55 },
56
57 BuildInfoWriteError {
58 message: String,
59 build_info_path: String,
60 #[fail(cause)]
61 error: Error,
62 },
63
64 ProviderTraitNotProcessedError {
65 message: String,
66 trait_name: String,
67 #[fail(cause)]
68 error: Error,
69 },
70
71 CodeGenerationError {
72 message: String,
73 },
74
75 NativeCodeGenerationError {
76 message: String,
77 #[fail(cause)]
78 error: Error,
79 },
80}
81
82impl Display for TracersError {
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 match self {
85 TracersError::InvalidProvider { message, .. } => write!(f, "{}", message),
86 TracersError::SynError { message, .. } => write!(f, "{}", message),
87 TracersError::DarlingError { message, .. } => write!(f, "{}", message),
88 TracersError::InvalidCallExpression { message, .. } => write!(f, "{}", message),
89 TracersError::OtherError { message, .. } => write!(f, "{}", message),
90 TracersError::MissingCallInBuildRs => write!(f, "Build environment is incomplete; make sure you are calling `tracers_build::build()` in your `build.rs` build script"),
91 TracersError::BuildInfoReadError { message, .. } => write!(f, "{}", message),
92 TracersError::BuildInfoWriteError { message, .. } => write!(f, "{}", message),
93 TracersError::ProviderTraitNotProcessedError { message,.. } => write!(f, "{}", message),
94 TracersError::CodeGenerationError { message } => write!(f, "Error generating probing code: {}", message),
95 TracersError::NativeCodeGenerationError { message, .. } => write!(f, "Error generating or compiling native C++ wrapper code: {}", message)
96 }
97 }
98}
99
100unsafe impl Send for TracersError {}
101unsafe impl Sync for TracersError {}
102
103impl PartialEq<TracersError> for TracersError {
104 fn eq(&self, other: &TracersError) -> bool {
105 self.to_string() == other.to_string()
108 }
109}
110
111impl TracersError {
112 pub fn invalid_provider<T: ToTokens>(message: impl AsRef<str>, element: T) -> TracersError {
113 let message = format!(
114 "There's a problem with this provider trait: {}",
115 message.as_ref()
116 );
117 let e = Self::new_syn_error(&message, element);
118
119 TracersError::InvalidProvider {
120 message,
121 syn_error: e,
122 }
123 }
124
125 pub fn syn_error(message: impl AsRef<str>, e: syn::Error) -> TracersError {
126 let message = format!("Parse error: {}\nDetails: {}", message.as_ref(), e);
133 let e = syn::Error::new(e.span(), &message);
134 let e = Self::wrap_syn_error(e);
135
136 TracersError::SynError {
137 message,
138 syn_error: e,
139 }
140 }
141
142 pub fn syn_like_error<T: ToTokens, U: Display>(message: U, tokens: T) -> TracersError {
147 let message = message.to_string();
148
149 Self::syn_error(&message, syn::Error::new_spanned(tokens, &message))
150 }
151
152 pub fn darling_error(e: DarlingError) -> TracersError {
153 let message = e.to_string();
154
155 TracersError::DarlingError {
156 message,
157 darling_error: Arc::new(Mutex::new(e)),
158 }
159 }
160
161 pub fn invalid_call_expression<T: ToTokens>(
162 message: impl AsRef<str>,
163 element: T,
164 ) -> TracersError {
165 let message = format!("Invalid call expression: {}", message.as_ref());
166 let e = Self::new_syn_error(&message, element);
167 TracersError::InvalidCallExpression {
168 message,
169 syn_error: e,
170 }
171 }
172
173 pub fn other_error<D: Display + Send + Sync + 'static>(e: failure::Context<D>) -> TracersError {
174 TracersError::OtherError {
175 message: Self::fail_string(&e),
176 error: e.into(),
177 }
178 }
179
180 pub fn missing_call_in_build_rs() -> TracersError {
181 TracersError::MissingCallInBuildRs
182 }
183
184 pub fn build_info_read_error(build_info_path: PathBuf, e: Error) -> TracersError {
185 let message = format!("Unable to read build info from '{}'.\nAre you sure you're calling `tracers_build::build()` in your `build.rs`?\nError cause: {}",
186 build_info_path.display(),
187 Self::error_string(&e));
188 TracersError::BuildInfoReadError {
189 message,
190 build_info_path: build_info_path.display().to_string(),
191 error: e,
192 }
193 }
194
195 pub fn build_info_write_error(build_info_path: PathBuf, e: Error) -> TracersError {
196 let message = format!("Unable to write build info from '{}'.\nAre you sure you're calling `tracers_build::build()` in your `build.rs`?\nError cause: {}",
197 build_info_path.display(),
198 Self::error_string(&e));
199 TracersError::BuildInfoWriteError {
200 message,
201 build_info_path: build_info_path.display().to_string(),
202 error: e,
203 }
204 }
205
206 pub fn provider_trait_not_processed_error<T: AsRef<str>, E: Into<Error> + Display>(
207 trait_name: T,
208 e: E,
209 ) -> TracersError {
210 TracersError::ProviderTraitNotProcessedError {
211 message: format!("The provider trait '{}' couldn't be processed by the code generator: {}\nCheck your build output for errors. Tracing will be disabled for this provider",
212 trait_name.as_ref(),
213 e),
214 trait_name: trait_name.as_ref().to_owned(),
215 error: e.into()
216 }
217 }
218
219 pub fn code_generation_error<S: AsRef<str>>(message: S) -> TracersError {
220 TracersError::CodeGenerationError {
221 message: message.as_ref().to_owned(),
222 }
223 }
224
225 pub fn native_code_generation_error<S: AsRef<str>, E: Into<Error> + Display>(
226 message: S,
227 e: E,
228 ) -> TracersError {
229 TracersError::NativeCodeGenerationError {
230 message: format!("{}: {}", message.as_ref(), e),
231 error: e.into(),
232 }
233 }
234
235 pub fn into_syn_error(self) -> syn::Error {
238 match self {
239 TracersError::InvalidProvider { syn_error, .. } => Self::error_as_syn_error(syn_error),
240 TracersError::SynError { syn_error, .. } => Self::error_as_syn_error(syn_error),
241 TracersError::InvalidCallExpression { syn_error, .. } => {
242 Self::error_as_syn_error(syn_error)
243 }
244 others => syn::Error::new(Span::call_site(), others.to_string()),
245 }
246 }
247
248 pub fn into_compiler_error(self) -> TokenStream {
253 if let TracersError::DarlingError { darling_error, .. } = self {
256 let lock =
259 Arc::try_unwrap(darling_error).expect("Somehow a lock is still held on this error");
260 let darling_error = lock
261 .into_inner()
262 .expect("The mutex can't possibly be locked");
263
264 darling_error.write_errors()
265 } else {
266 self.into_syn_error().to_compile_error()
267 }
268 }
269
270 fn new_syn_error<T: ToTokens, U: Display>(message: U, tokens: T) -> Error {
271 Self::wrap_syn_error(syn::Error::new_spanned(tokens, message))
272 }
273
274 fn wrap_syn_error(e: syn::Error) -> Error {
275 Self::wrap_error(e)
276 }
277
278 fn error_as_syn_error(e: Error) -> syn::Error {
281 e.downcast::<syn::Error>()
282 .unwrap_or_else(|e| syn::Error::new(Span::call_site(), e.to_string()))
283 }
284
285 fn wrap_error(e: impl std::error::Error + Sync + Send + 'static) -> Error {
286 e.into()
287 }
288
289 #[allow(clippy::redundant_closure)] fn error_string(e: &Error) -> String {
292 let causes: Vec<_> = e.iter_chain().map(|c| c.to_string()).collect();
293 causes.join(": ")
294 }
295
296 #[allow(clippy::redundant_closure)] fn fail_string(f: &dyn Fail) -> String {
298 let causes: Vec<_> = f.iter_chain().map(|c| c.to_string()).collect();
299 causes.join(": ")
300 }
301}
302
303impl<D: Display + Send + Sync + 'static> From<failure::Context<D>> for TracersError {
306 fn from(failure: failure::Context<D>) -> TracersError {
307 TracersError::other_error(failure)
308 }
309}
310
311pub type TracersResult<T> = std::result::Result<T, TracersError>;