1#![allow(missing_docs)]
11
12use error_chain::error_chain;
13use std::{
14 ffi,
15 fmt::{self, Debug, Display},
16 io,
17 io::Write,
18 num,
19 result::Result as StdResult,
20 str,
21 sync::{Arc, Mutex, Weak},
22};
23use tectonic_errors::Error as NewError;
24use zip::result::ZipError;
25
26cfg_if::cfg_if! {
27 if #[cfg(feature = "toml")] {
28 pub type ReadError = toml::de::Error;
29 pub type WriteError = toml::ser::Error;
30 } else {
31 use std::error;
32
33 #[derive(Debug)]
34 pub enum ReadError {}
35
36 impl Display for ReadError {
37 fn fmt(&self, _fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
38 Ok(())
39 }
40 }
41
42 impl error::Error for ReadError { }
43
44 #[derive(Debug)]
45 pub enum WriteError {}
46
47 impl Display for WriteError {
48 fn fmt(&self, _fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
49 Ok(())
50 }
51 }
52
53 impl error::Error for WriteError { }
54 }
55}
56
57error_chain! {
58 types {
59 Error, ErrorKind, ResultExt, Result;
60 }
61
62 foreign_links {
63 Io(io::Error);
64 Fmt(fmt::Error);
65 Nul(ffi::NulError);
66 ParseInt(num::ParseIntError);
67 Persist(tempfile::PersistError);
68 ConfigRead(ReadError);
69 ConfigWrite(WriteError);
70 NewStyle(NewError);
71 QuickXml(quick_xml::Error);
72 Time(std::time::SystemTimeError);
73 Utf8(str::Utf8Error);
74 Xdv(tectonic_xdv::XdvError);
75 Zip(ZipError);
76 }
77
78 errors {
79 BadLength(expected: usize, observed: usize) {
80 description("the item is not the expected length")
81 display("expected length {}; found {}", expected, observed)
82 }
83
84 NotSeekable {
85 description("this stream is not seekable")
86 display("this stream is not seekable")
87 }
88
89 NotSizeable {
90 description("the size of this stream cannot be determined")
91 display("the size of this stream cannot be determined")
92 }
93
94 PathForbidden(path: String) {
95 description("access to this file path is forbidden")
96 display("access to the path {} is forbidden", path)
97 }
98
99 EngineError(engine: &'static str) {
100 description("some engine had an unrecoverable error")
101 display("the {} engine had an unrecoverable error", engine)
102 }
103 }
104}
105
106pub trait ChainErrCompatExt<T> {
108 fn chain_err<F, K>(self, chainer: F) -> Result<T>
110 where
111 F: FnOnce() -> K,
112 K: Into<ErrorKind>;
113}
114
115impl<T> ChainErrCompatExt<T> for StdResult<T, NewError> {
116 fn chain_err<F, K>(self, chainer: F) -> Result<T>
117 where
118 F: FnOnce() -> K,
119 K: Into<ErrorKind>,
120 {
121 self.map_err(|e| {
122 let e: Error = e.into();
123 e.chain_err(chainer)
124 })
125 }
126}
127
128#[macro_export]
131macro_rules! errmsg {
132 ($( $fmt_args:expr ),*) => {
133 $crate::errors::ErrorKind::Msg(format!($( $fmt_args ),*)).into()
134 };
135}
136
137#[macro_export]
139macro_rules! ctry {
140 ($op:expr ; $( $chain_fmt_args:expr ),*) => {{
141 #[allow(unused_imports)]
142 use $crate::errors::{ChainErrCompatExt, ResultExt};
143 $op.chain_err(|| format!($( $chain_fmt_args ),*))?
144 }}
145}
146
147impl From<Error> for io::Error {
148 fn from(err: Error) -> io::Error {
149 io::Error::other(err.to_string())
150 }
151}
152
153impl Error {
154 pub fn dump_uncolorized(&self) {
165 let mut prefix = "error:";
166 let mut s = io::stderr();
167
168 for item in self.iter() {
169 writeln!(s, "{prefix} {item}").expect("write to stderr failed");
170 prefix = "caused by:";
171 }
172
173 if let Some(backtrace) = self.backtrace() {
174 writeln!(s, "debugging: backtrace follows:").expect("write to stderr failed");
175 writeln!(s, "{backtrace:?}").expect("write to stderr failed");
176 }
177 }
178}
179
180pub trait DefinitelySame {
189 fn definitely_same(&self, other: &Self) -> bool;
190}
191
192impl DefinitelySame for Error {
205 fn definitely_same(&self, other: &Self) -> bool {
206 if !self.0.definitely_same(&other.0) {
207 return false;
208 }
209 self.1.definitely_same(&other.1)
210 }
211}
212
213impl DefinitelySame for error_chain::State {
214 fn definitely_same(&self, other: &Self) -> bool {
215 self.next_error.definitely_same(&other.next_error)
218 }
219}
220
221impl DefinitelySame for ErrorKind {
222 fn definitely_same(&self, other: &Self) -> bool {
223 match self {
224 ErrorKind::Msg(ref s) => {
225 if let ErrorKind::Msg(ref o) = *other {
226 s == o
227 } else {
228 false
229 }
230 }
231
232 ErrorKind::NewStyle(ref s) => {
234 if let ErrorKind::NewStyle(ref o) = *other {
235 s.to_string() == o.to_string()
236 } else {
237 false
238 }
239 }
240
241 _ => false,
242 }
243 }
244}
245
246impl DefinitelySame for NewError {
247 fn definitely_same(&self, other: &Self) -> bool {
249 self.to_string() == other.to_string()
250 }
251}
252
253impl DefinitelySame for Box<dyn std::error::Error + Send> {
254 fn definitely_same(&self, other: &Self) -> bool {
256 self.to_string() == other.to_string()
257 }
258}
259
260impl<T: DefinitelySame> DefinitelySame for Option<T> {
261 fn definitely_same(&self, other: &Self) -> bool {
262 match (self, other) {
263 (None, None) => true,
264 (Some(a), Some(b)) => a.definitely_same(b),
265 _ => false,
266 }
267 }
268}
269
270impl<T: DefinitelySame, E: DefinitelySame> DefinitelySame for StdResult<T, E> {
271 fn definitely_same(&self, other: &Self) -> bool {
272 match *self {
273 Ok(ref st) => {
274 if let Ok(ref ot) = *other {
275 st.definitely_same(ot)
276 } else {
277 false
278 }
279 }
280 Err(ref se) => {
281 if let Err(ref oe) = *other {
282 se.definitely_same(oe)
283 } else {
284 false
285 }
286 }
287 }
288 }
289}
290
291pub struct SyncError<T: 'static> {
298 inner: Arc<Mutex<T>>,
299 proxy: Option<CauseProxy<T>>,
300}
301
302impl<T: std::error::Error + 'static> SyncError<T> {
303 pub fn new(err: T) -> Self {
304 let arc = Arc::new(Mutex::new(err));
305 let proxy = arc
306 .lock()
307 .unwrap()
308 .source()
309 .map(|s| CauseProxy::new(s, Arc::downgrade(&arc), 0));
310
311 SyncError { inner: arc, proxy }
312 }
313
314 pub fn maybe<R>(r: std::result::Result<R, T>) -> std::result::Result<R, Self> {
315 match r {
316 Ok(v) => Ok(v),
317 Err(e) => Err(SyncError::new(e)),
318 }
319 }
320
321 pub fn unwrap(self) -> T {
322 Arc::try_unwrap(self.inner).unwrap().into_inner().unwrap()
323 }
324}
325
326impl<T: std::error::Error + 'static> std::error::Error for SyncError<T> {
327 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
328 self.proxy.as_ref().map(|e| e as _)
329 }
330}
331
332impl<T> Display for SyncError<T>
333where
334 T: Display,
335{
336 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337 self.inner.lock().unwrap().fmt(f)
338 }
339}
340
341impl<T> Debug for SyncError<T>
342where
343 T: Debug,
344{
345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346 self.inner.lock().unwrap().fmt(f)
347 }
348}
349
350struct CauseProxy<T: 'static> {
351 inner: Weak<Mutex<T>>,
352 next: Option<Box<CauseProxy<T>>>,
353 depth: u32,
354}
355
356impl<T: std::error::Error> CauseProxy<T> {
357 fn new(err: &dyn std::error::Error, weak: Weak<Mutex<T>>, depth: u32) -> Self {
358 CauseProxy {
364 inner: weak.clone(),
365 depth,
366 next: err
367 .source()
368 .map(|s| Box::new(CauseProxy::new(s, weak, depth + 1))),
369 }
370 }
371
372 fn with_instance<R, F>(&self, f: F) -> R
373 where
374 F: FnOnce(&(dyn std::error::Error + 'static)) -> R,
375 {
376 let arc = self.inner.upgrade().unwrap();
377 {
378 let e = arc.lock().unwrap();
379 let mut source = e.source().unwrap();
380 for _ in 0..self.depth {
381 source = source.source().unwrap();
382 }
383 f(source)
384 }
385 }
386}
387
388impl<T: std::error::Error + 'static> std::error::Error for CauseProxy<T> {
389 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
390 self.next.as_ref().map(|e| e as _)
391 }
392}
393
394impl<T> Display for CauseProxy<T>
395where
396 T: Display + std::error::Error,
397{
398 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
399 self.with_instance(|i| std::fmt::Display::fmt(&i, f))
400 }
401}
402
403impl<T> Debug for CauseProxy<T>
404where
405 T: Debug + std::error::Error,
406{
407 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
408 self.with_instance(|i| std::fmt::Debug::fmt(&i, f))
409 }
410}
411
412#[cfg(test)]
413mod tests {
414 use super::*;
415 use error_chain::{ChainedError, State};
416 use std::error::Error as StdError;
417
418 #[test]
419 fn test_def_same_option() {
420 let a = Some(Box::from(NewError::msg("A")));
421 let b = Some(Box::from(NewError::msg("A")));
422
423 assert!(a.definitely_same(&b));
424 assert!(b.definitely_same(&a));
425
426 let b = Some(Box::from(NewError::msg("B")));
427 assert!(!a.definitely_same(&b));
428
429 let b = None;
430 let c = None;
431 assert!(!a.definitely_same(&b));
432 assert!(b.definitely_same(&c));
433 }
434
435 #[test]
436 fn test_def_same_err() {
437 let a = Error::new(ErrorKind::Msg(String::from("A")), State::default());
438 let b = Error::new(ErrorKind::Msg(String::from("A")), State::default());
439
440 assert!(a.definitely_same(&b));
442
443 let b = Error::new(ErrorKind::BadLength(0, 0), State::default());
444 assert!(!a.definitely_same(&b));
445
446 let a = Error::new(ErrorKind::NewStyle(NewError::msg("A")), State::default());
447 assert!(!a.definitely_same(&b));
448
449 let b = Error::new(ErrorKind::NewStyle(NewError::msg("A")), State::default());
450 assert!(a.definitely_same(&b));
451 }
452
453 #[test]
454 fn test_def_same_box_err() {
455 let a: Box<dyn StdError + Send> = Box::from(NewError::msg("A"));
456 let b: Box<dyn StdError + Send> = Box::from(NewError::msg("B"));
457
458 assert!(a.definitely_same(&a));
459 assert!(!a.definitely_same(&b));
460 }
461}