1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
//! Errors for printpdf

use std::error::Error as IError;
use std::io::Error as IoError;
use rusttype::Error as RusttypeError;
use std::fmt;

/// error_chain and failure are certainly nice, but completely overengineered
/// for this use-case. For example, neither of them allow error localization.
/// Additionally, debugging macros can get hairy really quick and matching with
/// `*e.kind()` or doing From conversions for other errors is really hard to do.
///
/// So in this case, the best form of error handling is to use the simple Rust-native
/// way: Just enums, `From` + pattern matching. No macros, except for this one.
///
/// What this macro does is (simplified): `impl From<$a> for $b { $b::$variant(error) }`
macro_rules! impl_from {
    ($from:ident, $to:ident::$variant:ident) => (
        impl From<$from> for $to {
            fn from(err: $from) -> Self {
                $to::$variant(err.into())
            }
        }
    )
}

#[derive(Debug)]
pub enum Error {
    /// External: std::io::Error
    Io(IoError),
    /// External: rusttype::Error
    Rusttype(RusttypeError),
    /// PDF error
    Pdf(PdfError),
    /// Indexing error (please report if this happens, shouldn't happen)
    Index(IndexError),
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum PdfError {
    FontFaceError,
}

impl fmt::Display for PdfError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl IError for PdfError {
    fn description(&self) -> &str {
        use self::PdfError::*;
        match *self {
            FontFaceError => "Invalid or corrupt font face",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum IndexError {
    PdfPageIndexError,
    PdfLayerIndexError,
    PdfMarkerIndexError,
}

impl fmt::Display for IndexError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

impl IError for IndexError {
    fn description(&self) -> &str {
        use self::IndexError::*;
        match *self {
            PdfPageIndexError => "Page index out of bounds",
            PdfLayerIndexError => "PDF layer index out of bounds",
            PdfMarkerIndexError => "PDF layer index out of bounds",
        }
    }
}

impl_from!(IoError, Error::Io);
impl_from!(RusttypeError, Error::Rusttype);
impl_from!(PdfError, Error::Pdf);
impl_from!(IndexError, Error::Index);

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;
        match *self {
            Io(ref e) => write!(f, "{}", e),
            Rusttype(ref e) => write!(f, "{}", e),
            Pdf(ref e) => write!(f, "{}", e),
            Index(ref e) => write!(f, "{}", e),
        }
    }
}

impl IError for Error {
    fn description(&self) -> &str {
        use self::Error::*;
        match self {
            Io(ref e) => e.description(),
            Rusttype(ref e) => e.description(),
            Pdf(ref e) => e.description(),
            Index(ref e) => e.description(),
        }
    }
}