use std::fmt::Formatter;
use std::{
fmt::{self, Debug, Display},
io::{self, Write},
result::Result as StdResult,
};
pub use tectonic_errors::Error;
cfg_if::cfg_if! {
if #[cfg(feature = "toml")] {
pub type ReadError = toml::de::Error;
pub type WriteError = toml::ser::Error;
} else {
use std::error;
#[derive(Debug)]
pub enum ReadError {}
impl Display for ReadError {
fn fmt(&self, _fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
impl error::Error for ReadError { }
#[derive(Debug)]
pub enum WriteError {}
impl Display for WriteError {
fn fmt(&self, _fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
Ok(())
}
}
impl error::Error for WriteError { }
}
}
#[macro_export]
macro_rules! ctry {
($op:expr ; $( $chain_fmt_args:expr ),*) => {{
#[allow(unused_imports)]
use anyhow::Context;
$op.with_context(|| format!($( $chain_fmt_args ),*))?
}}
}
#[derive(Debug)]
pub struct EngineError(&'static str);
impl EngineError {
pub fn new(engine: &'static str) -> EngineError {
EngineError(engine)
}
pub fn engine(&self) -> &str {
self.0
}
}
impl Display for EngineError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "the {} engine had an unrecoverable error", self.0)
}
}
pub fn dump_uncolorized(error: &Error) {
let mut s = io::stderr();
writeln!(s, "{:#}", error).expect("write to stderr failed");
}
pub trait DefinitelySame {
fn definitely_same(&self, other: &Self) -> bool;
}
impl DefinitelySame for Error {
fn definitely_same(&self, other: &Self) -> bool {
self.to_string() == other.to_string()
}
}
impl DefinitelySame for Box<dyn std::error::Error + Send> {
fn definitely_same(&self, other: &Self) -> bool {
self.to_string() == other.to_string()
}
}
impl<T: DefinitelySame> DefinitelySame for Option<T> {
fn definitely_same(&self, other: &Self) -> bool {
match (self, other) {
(None, None) => true,
(Some(a), Some(b)) => a.definitely_same(b),
_ => false,
}
}
}
impl<T: DefinitelySame, E: DefinitelySame> DefinitelySame for StdResult<T, E> {
fn definitely_same(&self, other: &Self) -> bool {
match *self {
Ok(ref st) => {
if let Ok(ref ot) = *other {
st.definitely_same(ot)
} else {
false
}
}
Err(ref se) => {
if let Err(ref oe) = *other {
se.definitely_same(oe)
} else {
false
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::error::Error as StdError;
#[test]
fn test_def_same_option() {
let a = Some(Box::from(Error::msg("A")));
let b = Some(Box::from(Error::msg("A")));
assert!(a.definitely_same(&b));
assert!(b.definitely_same(&a));
let b = Some(Box::from(Error::msg("B")));
assert!(!a.definitely_same(&b));
let b = None;
let c = None;
assert!(!a.definitely_same(&b));
assert!(b.definitely_same(&c));
}
#[test]
fn test_def_same_err() {
let a = Error::msg("A");
let b = Error::msg("A");
assert!(a.definitely_same(&b));
let b = Error::msg("B");
assert!(!a.definitely_same(&b));
let a = Error::msg("A");
assert!(!a.definitely_same(&b));
let b = Error::msg("A");
assert!(a.definitely_same(&b));
}
#[test]
fn test_def_same_box_err() {
let a: Box<dyn StdError + Send> = Box::from(Error::msg("A"));
let b: Box<dyn StdError + Send> = Box::from(Error::msg("B"));
assert!(a.definitely_same(&a));
assert!(!a.definitely_same(&b));
}
}