Better error handling 🌍

This commit is contained in:
Laurenz 2019-03-14 16:26:06 +01:00
parent aae8a3a77e
commit 22ea09d9c1
5 changed files with 110 additions and 82 deletions

View File

@ -132,15 +132,20 @@ impl<'s> Engine<'s> {
type TypeResult<T> = std::result::Result<T, TypesetError>;
/// The error type for typesetting.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TypesetError {
message: String,
}
pub enum TypesetError {}
impl error::Error for TypesetError {}
impl fmt::Display for TypesetError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.message)
#[inline]
fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
Ok(())
}
}
impl fmt::Debug for TypesetError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}

View File

@ -5,9 +5,9 @@ use std::error;
use std::fmt;
use std::io::{self, Cursor, Seek, SeekFrom};
use byteorder::{BE, ReadBytesExt, WriteBytesExt};
use opentype::{OpenTypeReader, Outlines, TableRecord, Tag};
use opentype::tables::{Header, MacStyleFlags, Name, NameEntry, CharMap,
MaximumProfile, HorizontalMetrics, Post, OS2};
use opentype::{Error as OpentypeError, OpenTypeReader, Outlines, TableRecord, Tag};
use opentype::tables::{Header, Name, CharMap, MaximumProfile, HorizontalMetrics, Post, OS2};
use opentype::tables::{MacStyleFlags, NameEntry};
use crate::doc::Size;
@ -588,8 +588,7 @@ impl<T> TakeInvalid<T> for Option<T> {
type FontResult<T> = Result<T, FontError>;
/// The error type for font subsetting.
#[derive(Debug)]
/// The error type for font operations.
pub enum FontError {
/// The font file is incorrect.
InvalidFont(String),
@ -601,9 +600,6 @@ pub enum FontError {
MissingCharacter(char),
/// An I/O Error occured while reading the font program.
Io(io::Error),
#[doc(hidden)]
__Extensible,
}
impl error::Error for FontError {
@ -619,18 +615,23 @@ impl error::Error for FontError {
impl fmt::Display for FontError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use FontError::*;
match self {
InvalidFont(message) => write!(f, "invalid font: {}", message),
MissingTable(table) => write!(f, "missing table: {}", table),
UnsupportedTable(table) => write!(f, "unsupported table: {}", table),
MissingCharacter(c) => write!(f, "missing character: '{}'", c),
Io(err) => fmt::Display::fmt(err, f),
__Extensible => panic!("tried to display extensible variant"),
FontError::InvalidFont(message) => write!(f, "invalid font: {}", message),
FontError::MissingTable(table) => write!(f, "missing table: {}", table),
FontError::UnsupportedTable(table) => write!(f, "unsupported table: {}", table),
FontError::MissingCharacter(c) => write!(f, "missing character: '{}'", c),
FontError::Io(err) => write!(f, "io error: {}", err),
}
}
}
impl fmt::Debug for FontError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl From<io::Error> for FontError {
#[inline]
fn from(err: io::Error) -> FontError {
@ -638,13 +639,12 @@ impl From<io::Error> for FontError {
}
}
impl From<opentype::Error> for FontError {
fn from(err: opentype::Error) -> FontError {
use opentype::Error::*;
impl From<OpentypeError> for FontError {
fn from(err: OpentypeError) -> FontError {
match err {
InvalidFont(message) => FontError::InvalidFont(message),
MissingTable(tag) => FontError::MissingTable(tag.to_string()),
Io(err) => FontError::Io(err),
OpentypeError::InvalidFont(message) => FontError::InvalidFont(message),
OpentypeError::MissingTable(tag) => FontError::MissingTable(tag.to_string()),
OpentypeError::Io(err) => FontError::Io(err),
_ => panic!("unexpected extensible variant"),
}
}

View File

@ -7,17 +7,17 @@
//! ```
//! use typeset::Compiler;
//!
//! // Minimal source code for our document.
//! let src = "Hello World from Typeset!";
//!
//! // Create an output file.
//! # /*
//! let mut file = std::fs::File::create("hello-typeset.pdf").unwrap();
//! # */
//! # let mut file = std::fs::File::create("../target/typeset-hello.pdf").unwrap();
//!
//! // Create a compiler and export a PDF.
//! let src = "Hello World from Typeset!";
//! // Create a compiler and write the document into a file as a PDF.
//! let compiler = Compiler::new();
//!
//! // Write the document into a file as a PDF.
//! compiler.write_pdf(src, &mut file).unwrap();
//! ```
@ -31,7 +31,7 @@ mod utility;
pub use crate::parsing::{Tokens, ParseError};
pub use crate::engine::TypesetError;
pub use crate::pdf::PdfWritingError;
pub use crate::pdf::PdfError;
use std::error;
use std::fmt;
@ -74,8 +74,8 @@ impl Compiler {
/// Return the abstract syntax tree representation of the document.
#[inline]
pub fn parse<'s>(&self, source: &'s str) -> Result<SyntaxTree<'s>, Error> {
Parser::new(self.tokenize(source)).parse().map_err(Into::into)
pub fn parse<'s>(&self, source: &'s str) -> Result<SyntaxTree<'s>, ParseError> {
Parser::new(self.tokenize(source)).parse()
}
/// Return the abstract typesetted representation of the document.
@ -92,8 +92,7 @@ impl Compiler {
}
}
/// The error type for compilation.
#[derive(Debug, Clone, Eq, PartialEq)]
/// The general error type for compilation.
pub enum Error {
/// An error that occured while transforming source code into
/// an abstract syntax tree.
@ -101,7 +100,7 @@ pub enum Error {
/// An error that occured while typesetting into an abstract document.
Typeset(TypesetError),
/// An error that occured while writing the document as a _PDF_.
PdfWrite(PdfWritingError)
Pdf(PdfError),
}
impl error::Error for Error {
@ -110,7 +109,7 @@ impl error::Error for Error {
match self {
Error::Parse(err) => Some(err),
Error::Typeset(err) => Some(err),
Error::PdfWrite(err) => Some(err),
Error::Pdf(err) => Some(err),
}
}
}
@ -121,11 +120,18 @@ impl fmt::Display for Error {
match self {
Error::Parse(err) => write!(f, "parse error: {}", err),
Error::Typeset(err) => write!(f, "typeset error: {}", err),
Error::PdfWrite(err) => write!(f, "typeset error: {}", err),
Error::Pdf(err) => write!(f, "pdf error: {}", err),
}
}
}
impl fmt::Debug for Error {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl From<ParseError> for Error {
#[inline]
fn from(err: ParseError) -> Error {
@ -140,10 +146,10 @@ impl From<TypesetError> for Error {
}
}
impl From<PdfWritingError> for Error {
impl From<PdfError> for Error {
#[inline]
fn from(err: PdfWritingError) -> Error {
Error::PdfWrite(err)
fn from(err: PdfError) -> Error {
Error::Pdf(err)
}
}

View File

@ -359,7 +359,6 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item = Token<'s>> {
type ParseResult<T> = std::result::Result<T, ParseError>;
/// The error type for parsing.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ParseError {
/// A message describing the error.
message: String,
@ -368,11 +367,18 @@ pub struct ParseError {
impl error::Error for ParseError {}
impl fmt::Display for ParseError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.message)
}
}
impl fmt::Debug for ParseError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
#[cfg(test)]
mod token_tests {
@ -491,12 +497,12 @@ mod parse_tests {
/// Test if the source code parses into the syntax tree.
fn test(src: &str, tree: SyntaxTree) {
assert_eq!(Parser::new(Tokens::new(src)).parse(), Ok(tree));
assert_eq!(Parser::new(Tokens::new(src)).parse().unwrap(), tree);
}
/// Test if the source parses into the error.
fn test_err(src: &str, err: ParseError) {
assert_eq!(Parser::new(Tokens::new(src)).parse(), Err(err));
fn test_err(src: &str, err: &str) {
assert_eq!(Parser::new(Tokens::new(src)).parse().unwrap_err().message, err);
}
/// Short cut macro to create a syntax tree.
@ -577,17 +583,9 @@ mod parse_tests {
/// Tests whether errors get reported correctly.
#[test]
fn parse_errors() {
test_err("No functions here]", ParseError {
message: "unexpected closing bracket".to_owned(),
});
test_err("[hello][world", ParseError {
message: "expected closing bracket".to_owned(),
});
test_err("[hello world", ParseError {
message: "expected closing bracket".to_owned(),
});
test_err("[ no-name][Why?]", ParseError {
message: "expected identifier".to_owned(),
});
test_err("No functions here]", "unexpected closing bracket");
test_err("[hello][world", "expected closing bracket");
test_err("[hello world", "expected closing bracket");
test_err("[ no-name][Why?]", "expected identifier");
}
}

View File

@ -4,12 +4,12 @@ use std::collections::HashSet;
use std::error;
use std::fmt;
use std::io::{self, Write};
use pdf::{PdfWriter, Reference, Rect, Version, Trailer};
use pdf::{DocumentCatalog, PageTree, Page, Resource, Text, Content};
use pdf::font::{Type0Font, CMapEncoding, CIDFont, CIDFontType, CIDSystemInfo,
WidthRecord, FontDescriptor, FontFlags, EmbeddedFont, GlyphUnit};
use pdf::{PdfWriter, Reference, Rect, Version, Trailer, DocumentCatalog};
use pdf::{PageTree, Page, Resource, Text, Content};
use pdf::font::{Type0Font, CMapEncoding, CIDFont, CIDFontType, CIDSystemInfo};
use pdf::font::{WidthRecord, FontDescriptor, FontFlags, EmbeddedFont, GlyphUnit};
use crate::doc::{Document, Size, Text as DocText, TextCommand as DocTextCommand};
use crate::font::Font;
use crate::font::{Font, FontError};
/// Writes documents in the _PDF_ format.
@ -279,34 +279,53 @@ impl std::ops::Deref for PdfFont {
}
/// Result type used for parsing.
type PdfResult<T> = std::result::Result<T, PdfWritingError>;
type PdfResult<T> = std::result::Result<T, PdfError>;
/// The error type for _PDF_ creation.
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PdfWritingError {
/// A message describing the error.
message: String,
pub enum PdfError {
/// An error occured while subsetting the font for the _PDF_.
Font(FontError),
/// An I/O Error on the underlying writable occured.
Io(io::Error),
}
impl error::Error for PdfWritingError {}
impl From<io::Error> for PdfWritingError {
impl error::Error for PdfError {
#[inline]
fn from(err: io::Error) -> PdfWritingError {
PdfWritingError { message: format!("{}", err) }
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
PdfError::Font(err) => Some(err),
PdfError::Io(err) => Some(err),
}
}
}
impl From<crate::font::FontError> for PdfWritingError {
#[inline]
fn from(err: crate::font::FontError) -> PdfWritingError {
PdfWritingError { message: format!("{}", err) }
}
}
impl fmt::Display for PdfWritingError {
impl fmt::Display for PdfError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.message)
match self {
PdfError::Font(err) => write!(f, "font error: {}", err),
PdfError::Io(err) => write!(f, "io error: {}", err),
}
}
}
impl fmt::Debug for PdfError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
impl From<io::Error> for PdfError {
#[inline]
fn from(err: io::Error) -> PdfError {
PdfError::Io(err)
}
}
impl From<FontError> for PdfError {
#[inline]
fn from(err: FontError) -> PdfError {
PdfError::Font(err)
}
}