diff --git a/src/engine.rs b/src/engine.rs index 1d249172a..ff89d6749 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1,8 +1,5 @@ //! Core typesetting engine. -use std::io; -use std::error; -use std::fmt; use crate::syntax::{SyntaxTree, Node}; use crate::doc::{Document, Size, Page, Text, TextCommand}; use crate::font::{Font, FontConfig, FontError}; @@ -141,58 +138,25 @@ impl<'a> Engine<'a> { } } -/// Result type used for typesetting. -type TypeResult = std::result::Result; - /// The error type for typesetting. pub enum TypesetError { /// There was no suitable font. MissingFont, /// An error occured while gathering font data. Font(FontError), - /// An I/O Error on occured while reading a font. - Io(io::Error), } -impl error::Error for TypesetError { - #[inline] - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match self { - TypesetError::Font(err) => Some(err), - TypesetError::Io(err) => Some(err), - _ => None, - } - } -} - -impl fmt::Display for TypesetError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - TypesetError::MissingFont => write!(f, "missing font"), - TypesetError::Font(err) => write!(f, "font error: {}", err), - TypesetError::Io(err) => write!(f, "io error: {}", err), - } - } -} - -impl fmt::Debug for TypesetError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self, f) - } -} - -impl From for TypesetError { - #[inline] - fn from(err: io::Error) -> TypesetError { - TypesetError::Io(err) - } -} - -impl From for TypesetError { - #[inline] - fn from(err: FontError) -> TypesetError { - TypesetError::Font(err) - } +error_type! { + err: TypesetError, + res: TypeResult, + show: f => match err { + TypesetError::MissingFont => write!(f, "missing font"), + TypesetError::Font(err) => write!(f, "font error: {}", err), + }, + source: match err { + TypesetError::Font(err) => Some(err), + _ => None, + }, + from: (std::io::Error, TypesetError::Font(FontError::Io(err))), + from: (FontError, TypesetError::Font(err)), } diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 000000000..cfdb1f0e9 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,38 @@ +/// Create an error type. +macro_rules! error_type { + ( + $var:ident: $err:ident, + $(res: $res:ident,)* + show: $f:ident => $show:expr, + $(source: $source:expr,)* + $(from: ($from:path, $conv:expr),)* + ) => { + $(type $res = std::result::Result;)* + + impl std::fmt::Display for $err { + fn fmt(&self, $f: &mut std::fmt::Formatter) -> std::fmt::Result { + let $var = self; + $show + } + } + + impl std::fmt::Debug for $err { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } + } + + impl std::error::Error for $err { + $(fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + let $var = self; + $source + })* + } + + $(impl From<$from> for $err { + fn from($var: $from) -> $err { + $conv + } + })* + }; +} diff --git a/src/export/pdf.rs b/src/export/pdf.rs index 31aa39d5e..630a05010 100644 --- a/src/export/pdf.rs +++ b/src/export/pdf.rs @@ -1,14 +1,11 @@ //! Exporting into _PDF_ documents. use std::collections::HashSet; -use std::fmt::{self, Display, Debug, Formatter}; use std::io::{self, Write}; - use pdf::{PdfWriter, Ref, Rect, Version, Trailer, Content}; use pdf::doc::{Catalog, PageTree, Page, Resource, Text}; use pdf::font::{Type0Font, CIDFont, CIDFontType, CIDSystemInfo, FontDescriptor, FontFlags}; use pdf::font::{GlyphUnit, CMapEncoding, WidthRecord, FontStream, EmbeddedFontType}; - use crate::doc::{Document, Size, Text as DocText, TextCommand}; use crate::font::{Font, FontError}; @@ -284,9 +281,6 @@ impl std::ops::Deref for PdfFont { } } -/// Result type for _PDF_ creation. -type PdfResult = std::result::Result; - /// The error type for _PDF_ creation. pub enum PdfExportError { /// An error occured while subsetting the font for the _PDF_. @@ -295,38 +289,17 @@ pub enum PdfExportError { Io(io::Error), } -impl std::error::Error for PdfExportError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - PdfExportError::Font(err) => Some(err), - PdfExportError::Io(err) => Some(err), - } - } -} - -impl Display for PdfExportError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - PdfExportError::Font(err) => write!(f, "font error: {}", err), - PdfExportError::Io(err) => write!(f, "io error: {}", err), - } - } -} - -impl Debug for PdfExportError { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(self, f) - } -} - -impl From for PdfExportError { - fn from(err: io::Error) -> PdfExportError { - PdfExportError::Io(err) - } -} - -impl From for PdfExportError { - fn from(err: FontError) -> PdfExportError { - PdfExportError::Font(err) - } +error_type! { + err: PdfExportError, + res: PdfResult, + show: f => match err { + PdfExportError::Font(err) => write!(f, "font error: {}", err), + PdfExportError::Io(err) => write!(f, "io error: {}", err), + }, + source: match err { + PdfExportError::Font(err) => Some(err), + PdfExportError::Io(err) => Some(err), + }, + from: (io::Error, PdfExportError::Io(err)), + from: (FontError, PdfExportError::Font(err)), } diff --git a/src/font.rs b/src/font.rs index 2f19a82bc..294c2b7eb 100644 --- a/src/font.rs +++ b/src/font.rs @@ -3,8 +3,6 @@ #![macro_use] use std::collections::HashMap; -use std::error; -use std::fmt; use std::path::{Path, PathBuf}; use std::io::{self, Cursor, Read, Seek, SeekFrom}; use byteorder::{BE, ReadBytesExt, WriteBytesExt}; @@ -715,8 +713,6 @@ impl FontProvider for FileFontProvider<'_> { } } -type FontResult = Result; - /// The error type for font operations. pub enum FontError { /// The font file is incorrect. @@ -731,50 +727,25 @@ pub enum FontError { Io(io::Error), } -impl error::Error for FontError { - #[inline] - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match self { - FontError::Io(err) => Some(err), - _ => None, - } - } -} - -impl fmt::Display for FontError { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - 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 for FontError { - #[inline] - fn from(err: io::Error) -> FontError { - FontError::Io(err) - } -} - -impl From for FontError { - fn from(err: OpentypeError) -> FontError { - match 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"), - } - } +error_type! { + err: FontError, + res: FontResult, + show: f => match err { + 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), + }, + source: match err { + FontError::Io(err) => Some(err), + _ => None, + }, + from: (io::Error, FontError::Io(err)), + from: (OpentypeError, match 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"), + }), } diff --git a/src/lib.rs b/src/lib.rs index 18d165c8c..4434f62f1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,20 +38,21 @@ //! exporter.export(&document, &mut file).unwrap(); //! ``` -use std::fmt::{self, Display, Debug, Formatter}; use crate::syntax::SyntaxTree; use crate::parsing::{Tokens, Parser, ParseError}; use crate::doc::{Document, Style}; use crate::font::FontProvider; use crate::engine::{Engine, TypesetError}; +#[macro_use] +mod error; +mod utility; pub mod doc; pub mod engine; pub mod export; pub mod font; pub mod parsing; pub mod syntax; -mod utility; /// Transforms source code into typesetted documents. @@ -120,43 +121,20 @@ pub enum Error { Typeset(TypesetError), } -impl std::error::Error for Error { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - Error::Parse(err) => Some(err), - Error::Typeset(err) => Some(err), - } - } +error_type! { + err: Error, + show: f => match err { + Error::Parse(e) => write!(f, "parse error: {}", e), + Error::Typeset(e) => write!(f, "typeset error: {}", e), + }, + source: match err { + Error::Parse(e) => Some(e), + Error::Typeset(e) => Some(e), + }, + from: (ParseError, Error::Parse(err)), + from: (TypesetError, Error::Typeset(err)), } -impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Error::Parse(err) => write!(f, "parse error: {}", err), - Error::Typeset(err) => write!(f, "typeset error: {}", err), - } - } -} - -impl Debug for Error { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(self, f) - } -} - -impl From for Error { - fn from(err: ParseError) -> Error { - Error::Parse(err) - } -} - -impl From for Error { - fn from(err: TypesetError) -> Error { - Error::Typeset(err) - } -} - - #[cfg(test)] mod test { use std::fs::File; diff --git a/src/parsing.rs b/src/parsing.rs index 5122597f9..2737fde44 100644 --- a/src/parsing.rs +++ b/src/parsing.rs @@ -1,6 +1,5 @@ //! Parsing of source code into tokens and syntax trees. -use std::error; use std::fmt; use std::iter::Peekable; use std::mem::swap; @@ -9,7 +8,7 @@ use crate::syntax::*; use crate::utility::{Splinor, Spline, Splined, StrExt}; -/// An iterator over the tokens of a text. +/// An iterator over the tokens of source code. #[derive(Clone)] pub struct Tokens<'s> { source: &'s str, @@ -211,7 +210,7 @@ impl<'s> Tokens<'s> { } } -/// Parses a token stream into an abstract syntax tree. +/// Transforms token streams to syntax trees. #[derive(Debug, Clone)] pub struct Parser<'s, T> where T: Iterator> { tokens: Peekable, @@ -355,30 +354,17 @@ impl<'s, T> Parser<'s, T> where T: Iterator> { } } -/// Result type used for parsing. -type ParseResult = std::result::Result; - /// The error type for parsing. pub struct ParseError { - /// A message describing the error. message: String, } -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) - } +error_type! { + err: ParseError, + res: ParseResult, + show: f => f.write_str(&err.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 {