mirror of
https://github.com/typst/typst
synced 2025-05-13 12:36:23 +08:00
Better error handling 🌍
This commit is contained in:
parent
aae8a3a77e
commit
22ea09d9c1
@ -132,15 +132,20 @@ impl<'s> Engine<'s> {
|
|||||||
type TypeResult<T> = std::result::Result<T, TypesetError>;
|
type TypeResult<T> = std::result::Result<T, TypesetError>;
|
||||||
|
|
||||||
/// The error type for typesetting.
|
/// The error type for typesetting.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
pub enum TypesetError {}
|
||||||
pub struct TypesetError {
|
|
||||||
message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for TypesetError {}
|
impl error::Error for TypesetError {}
|
||||||
|
|
||||||
impl fmt::Display for TypesetError {
|
impl fmt::Display for TypesetError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
#[inline]
|
||||||
f.write_str(&self.message)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
42
src/font.rs
42
src/font.rs
@ -5,9 +5,9 @@ use std::error;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{self, Cursor, Seek, SeekFrom};
|
use std::io::{self, Cursor, Seek, SeekFrom};
|
||||||
use byteorder::{BE, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BE, ReadBytesExt, WriteBytesExt};
|
||||||
use opentype::{OpenTypeReader, Outlines, TableRecord, Tag};
|
use opentype::{Error as OpentypeError, OpenTypeReader, Outlines, TableRecord, Tag};
|
||||||
use opentype::tables::{Header, MacStyleFlags, Name, NameEntry, CharMap,
|
use opentype::tables::{Header, Name, CharMap, MaximumProfile, HorizontalMetrics, Post, OS2};
|
||||||
MaximumProfile, HorizontalMetrics, Post, OS2};
|
use opentype::tables::{MacStyleFlags, NameEntry};
|
||||||
use crate::doc::Size;
|
use crate::doc::Size;
|
||||||
|
|
||||||
|
|
||||||
@ -588,8 +588,7 @@ impl<T> TakeInvalid<T> for Option<T> {
|
|||||||
|
|
||||||
type FontResult<T> = Result<T, FontError>;
|
type FontResult<T> = Result<T, FontError>;
|
||||||
|
|
||||||
/// The error type for font subsetting.
|
/// The error type for font operations.
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum FontError {
|
pub enum FontError {
|
||||||
/// The font file is incorrect.
|
/// The font file is incorrect.
|
||||||
InvalidFont(String),
|
InvalidFont(String),
|
||||||
@ -601,9 +600,6 @@ pub enum FontError {
|
|||||||
MissingCharacter(char),
|
MissingCharacter(char),
|
||||||
/// An I/O Error occured while reading the font program.
|
/// An I/O Error occured while reading the font program.
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
__Extensible,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for FontError {
|
impl error::Error for FontError {
|
||||||
@ -619,18 +615,23 @@ impl error::Error for FontError {
|
|||||||
impl fmt::Display for FontError {
|
impl fmt::Display for FontError {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use FontError::*;
|
|
||||||
match self {
|
match self {
|
||||||
InvalidFont(message) => write!(f, "invalid font: {}", message),
|
FontError::InvalidFont(message) => write!(f, "invalid font: {}", message),
|
||||||
MissingTable(table) => write!(f, "missing table: {}", table),
|
FontError::MissingTable(table) => write!(f, "missing table: {}", table),
|
||||||
UnsupportedTable(table) => write!(f, "unsupported table: {}", table),
|
FontError::UnsupportedTable(table) => write!(f, "unsupported table: {}", table),
|
||||||
MissingCharacter(c) => write!(f, "missing character: '{}'", c),
|
FontError::MissingCharacter(c) => write!(f, "missing character: '{}'", c),
|
||||||
Io(err) => fmt::Display::fmt(err, f),
|
FontError::Io(err) => write!(f, "io error: {}", err),
|
||||||
__Extensible => panic!("tried to display extensible variant"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
impl From<io::Error> for FontError {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(err: io::Error) -> FontError {
|
fn from(err: io::Error) -> FontError {
|
||||||
@ -638,13 +639,12 @@ impl From<io::Error> for FontError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<opentype::Error> for FontError {
|
impl From<OpentypeError> for FontError {
|
||||||
fn from(err: opentype::Error) -> FontError {
|
fn from(err: OpentypeError) -> FontError {
|
||||||
use opentype::Error::*;
|
|
||||||
match err {
|
match err {
|
||||||
InvalidFont(message) => FontError::InvalidFont(message),
|
OpentypeError::InvalidFont(message) => FontError::InvalidFont(message),
|
||||||
MissingTable(tag) => FontError::MissingTable(tag.to_string()),
|
OpentypeError::MissingTable(tag) => FontError::MissingTable(tag.to_string()),
|
||||||
Io(err) => FontError::Io(err),
|
OpentypeError::Io(err) => FontError::Io(err),
|
||||||
_ => panic!("unexpected extensible variant"),
|
_ => panic!("unexpected extensible variant"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
36
src/lib.rs
36
src/lib.rs
@ -7,17 +7,17 @@
|
|||||||
//! ```
|
//! ```
|
||||||
//! use typeset::Compiler;
|
//! use typeset::Compiler;
|
||||||
//!
|
//!
|
||||||
|
//! // Minimal source code for our document.
|
||||||
|
//! let src = "Hello World from Typeset!";
|
||||||
|
//!
|
||||||
//! // Create an output file.
|
//! // Create an output file.
|
||||||
//! # /*
|
//! # /*
|
||||||
//! let mut file = std::fs::File::create("hello-typeset.pdf").unwrap();
|
//! let mut file = std::fs::File::create("hello-typeset.pdf").unwrap();
|
||||||
//! # */
|
//! # */
|
||||||
//! # let mut file = std::fs::File::create("../target/typeset-hello.pdf").unwrap();
|
//! # let mut file = std::fs::File::create("../target/typeset-hello.pdf").unwrap();
|
||||||
//!
|
//!
|
||||||
//! // Create a compiler and export a PDF.
|
//! // Create a compiler and write the document into a file as a PDF.
|
||||||
//! let src = "Hello World from Typeset!";
|
|
||||||
//! let compiler = Compiler::new();
|
//! let compiler = Compiler::new();
|
||||||
//!
|
|
||||||
//! // Write the document into a file as a PDF.
|
|
||||||
//! compiler.write_pdf(src, &mut file).unwrap();
|
//! compiler.write_pdf(src, &mut file).unwrap();
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ mod utility;
|
|||||||
|
|
||||||
pub use crate::parsing::{Tokens, ParseError};
|
pub use crate::parsing::{Tokens, ParseError};
|
||||||
pub use crate::engine::TypesetError;
|
pub use crate::engine::TypesetError;
|
||||||
pub use crate::pdf::PdfWritingError;
|
pub use crate::pdf::PdfError;
|
||||||
|
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -74,8 +74,8 @@ impl Compiler {
|
|||||||
|
|
||||||
/// Return the abstract syntax tree representation of the document.
|
/// Return the abstract syntax tree representation of the document.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn parse<'s>(&self, source: &'s str) -> Result<SyntaxTree<'s>, Error> {
|
pub fn parse<'s>(&self, source: &'s str) -> Result<SyntaxTree<'s>, ParseError> {
|
||||||
Parser::new(self.tokenize(source)).parse().map_err(Into::into)
|
Parser::new(self.tokenize(source)).parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the abstract typesetted representation of the document.
|
/// Return the abstract typesetted representation of the document.
|
||||||
@ -92,8 +92,7 @@ impl Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The error type for compilation.
|
/// The general error type for compilation.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// An error that occured while transforming source code into
|
/// An error that occured while transforming source code into
|
||||||
/// an abstract syntax tree.
|
/// an abstract syntax tree.
|
||||||
@ -101,7 +100,7 @@ pub enum Error {
|
|||||||
/// An error that occured while typesetting into an abstract document.
|
/// An error that occured while typesetting into an abstract document.
|
||||||
Typeset(TypesetError),
|
Typeset(TypesetError),
|
||||||
/// An error that occured while writing the document as a _PDF_.
|
/// An error that occured while writing the document as a _PDF_.
|
||||||
PdfWrite(PdfWritingError)
|
Pdf(PdfError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for Error {
|
impl error::Error for Error {
|
||||||
@ -110,7 +109,7 @@ impl error::Error for Error {
|
|||||||
match self {
|
match self {
|
||||||
Error::Parse(err) => Some(err),
|
Error::Parse(err) => Some(err),
|
||||||
Error::Typeset(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 {
|
match self {
|
||||||
Error::Parse(err) => write!(f, "parse error: {}", err),
|
Error::Parse(err) => write!(f, "parse error: {}", err),
|
||||||
Error::Typeset(err) => write!(f, "typeset 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 {
|
impl From<ParseError> for Error {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(err: ParseError) -> Error {
|
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]
|
#[inline]
|
||||||
fn from(err: PdfWritingError) -> Error {
|
fn from(err: PdfError) -> Error {
|
||||||
Error::PdfWrite(err)
|
Error::Pdf(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +359,6 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item = Token<'s>> {
|
|||||||
type ParseResult<T> = std::result::Result<T, ParseError>;
|
type ParseResult<T> = std::result::Result<T, ParseError>;
|
||||||
|
|
||||||
/// The error type for parsing.
|
/// The error type for parsing.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct ParseError {
|
pub struct ParseError {
|
||||||
/// A message describing the error.
|
/// A message describing the error.
|
||||||
message: String,
|
message: String,
|
||||||
@ -368,11 +367,18 @@ pub struct ParseError {
|
|||||||
impl error::Error for ParseError {}
|
impl error::Error for ParseError {}
|
||||||
|
|
||||||
impl fmt::Display for ParseError {
|
impl fmt::Display for ParseError {
|
||||||
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.write_str(&self.message)
|
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)]
|
#[cfg(test)]
|
||||||
mod token_tests {
|
mod token_tests {
|
||||||
@ -491,12 +497,12 @@ mod parse_tests {
|
|||||||
|
|
||||||
/// Test if the source code parses into the syntax tree.
|
/// Test if the source code parses into the syntax tree.
|
||||||
fn test(src: &str, tree: SyntaxTree) {
|
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.
|
/// Test if the source parses into the error.
|
||||||
fn test_err(src: &str, err: ParseError) {
|
fn test_err(src: &str, err: &str) {
|
||||||
assert_eq!(Parser::new(Tokens::new(src)).parse(), Err(err));
|
assert_eq!(Parser::new(Tokens::new(src)).parse().unwrap_err().message, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Short cut macro to create a syntax tree.
|
/// Short cut macro to create a syntax tree.
|
||||||
@ -577,17 +583,9 @@ mod parse_tests {
|
|||||||
/// Tests whether errors get reported correctly.
|
/// Tests whether errors get reported correctly.
|
||||||
#[test]
|
#[test]
|
||||||
fn parse_errors() {
|
fn parse_errors() {
|
||||||
test_err("No functions here]", ParseError {
|
test_err("No functions here]", "unexpected closing bracket");
|
||||||
message: "unexpected closing bracket".to_owned(),
|
test_err("[hello][world", "expected closing bracket");
|
||||||
});
|
test_err("[hello world", "expected closing bracket");
|
||||||
test_err("[hello][world", ParseError {
|
test_err("[ no-name][Why?]", "expected identifier");
|
||||||
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(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
67
src/pdf.rs
67
src/pdf.rs
@ -4,12 +4,12 @@ use std::collections::HashSet;
|
|||||||
use std::error;
|
use std::error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use pdf::{PdfWriter, Reference, Rect, Version, Trailer};
|
use pdf::{PdfWriter, Reference, Rect, Version, Trailer, DocumentCatalog};
|
||||||
use pdf::{DocumentCatalog, PageTree, Page, Resource, Text, Content};
|
use pdf::{PageTree, Page, Resource, Text, Content};
|
||||||
use pdf::font::{Type0Font, CMapEncoding, CIDFont, CIDFontType, CIDSystemInfo,
|
use pdf::font::{Type0Font, CMapEncoding, CIDFont, CIDFontType, CIDSystemInfo};
|
||||||
WidthRecord, FontDescriptor, FontFlags, EmbeddedFont, GlyphUnit};
|
use pdf::font::{WidthRecord, FontDescriptor, FontFlags, EmbeddedFont, GlyphUnit};
|
||||||
use crate::doc::{Document, Size, Text as DocText, TextCommand as DocTextCommand};
|
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.
|
/// Writes documents in the _PDF_ format.
|
||||||
@ -279,34 +279,53 @@ impl std::ops::Deref for PdfFont {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Result type used for parsing.
|
/// 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.
|
/// The error type for _PDF_ creation.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
pub enum PdfError {
|
||||||
pub struct PdfWritingError {
|
/// An error occured while subsetting the font for the _PDF_.
|
||||||
/// A message describing the error.
|
Font(FontError),
|
||||||
message: String,
|
/// An I/O Error on the underlying writable occured.
|
||||||
|
Io(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for PdfWritingError {}
|
impl error::Error for PdfError {
|
||||||
|
|
||||||
impl From<io::Error> for PdfWritingError {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(err: io::Error) -> PdfWritingError {
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||||
PdfWritingError { message: format!("{}", err) }
|
match self {
|
||||||
|
PdfError::Font(err) => Some(err),
|
||||||
|
PdfError::Io(err) => Some(err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<crate::font::FontError> for PdfWritingError {
|
impl fmt::Display for PdfError {
|
||||||
#[inline]
|
|
||||||
fn from(err: crate::font::FontError) -> PdfWritingError {
|
|
||||||
PdfWritingError { message: format!("{}", err) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for PdfWritingError {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user