Make things more consistent ♻

This commit is contained in:
Laurenz 2019-03-30 20:51:09 +01:00
parent adfd7dd073
commit 5ca303ecad
8 changed files with 61 additions and 58 deletions

View File

@ -10,10 +10,10 @@ pub use size::Size;
/// The core typesetting engine, transforming an abstract syntax tree into a document. /// The core typesetting engine, transforming an abstract syntax tree into a document.
pub(crate) struct Engine<'a> { pub struct Engine<'t> {
// Immutable // Immutable
tree: &'a SyntaxTree<'a>, tree: &'t SyntaxTree<'t>,
ctx: &'a Context<'a>, ctx: &'t Context<'t>,
// Mutable // Mutable
fonts: Vec<Font>, fonts: Vec<Font>,
@ -23,22 +23,22 @@ pub(crate) struct Engine<'a> {
current_width: Size, current_width: Size,
} }
impl<'a> Engine<'a> { impl<'t> Engine<'t> {
/// Create a new generator from a syntax tree. /// Create a new generator from a syntax tree.
pub fn new(tree: &'a SyntaxTree<'a>, context: &'a Context<'a>) -> Engine<'a> { pub(crate) fn new(tree: &'t SyntaxTree<'t>, context: &'t Context<'t>) -> Engine<'t> {
Engine { Engine {
tree, tree,
ctx: context, ctx: context,
fonts: Vec::new(), fonts: vec![],
active_font: 0, active_font: 0,
text_commands: Vec::new(), text_commands: vec![],
current_line: String::new(), current_line: String::new(),
current_width: Size::zero(), current_width: Size::zero(),
} }
} }
/// Generate the abstract document. /// Generate the abstract document.
pub fn typeset(mut self) -> TypeResult<Document> { pub(crate) fn typeset(mut self) -> TypeResult<Document> {
// Load font defined by style // Load font defined by style
let mut font = None; let mut font = None;
let filter = FontFilter::new(&self.ctx.style.font_families); let filter = FontFilter::new(&self.ctx.style.font_families);

View File

@ -5,7 +5,7 @@ use std::ops::*;
/// A general size (unit of length) type. /// A general size (unit of length) type.
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq, Default)]
pub struct Size { pub struct Size {
/// The size in typographic points (1/72 inches). /// The size in typographic points (1/72 inches).
points: f32, points: f32,
@ -62,6 +62,7 @@ impl Debug for Size {
} }
impl PartialOrd for Size { impl PartialOrd for Size {
#[inline]
fn partial_cmp(&self, other: &Size) -> Option<Ordering> { fn partial_cmp(&self, other: &Size) -> Option<Ordering> {
self.points.partial_cmp(&other.points) self.points.partial_cmp(&other.points)
} }
@ -70,12 +71,14 @@ impl PartialOrd for Size {
impl Neg for Size { impl Neg for Size {
type Output = Size; type Output = Size;
#[inline]
fn neg(self) -> Size { fn neg(self) -> Size {
Size { points: -self.points } Size { points: -self.points }
} }
} }
impl Sum for Size { impl Sum for Size {
#[inline]
fn sum<I>(iter: I) -> Size where I: Iterator<Item=Size> { fn sum<I>(iter: I) -> Size where I: Iterator<Item=Size> {
iter.fold(Size::zero(), Add::add) iter.fold(Size::zero(), Add::add)
} }

View File

@ -40,7 +40,7 @@ struct PdfEngine<'d, W: Write> {
} }
/// Offsets for the various groups of ids. /// Offsets for the various groups of ids.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct Offsets { struct Offsets {
catalog: Ref, catalog: Ref,
page_tree: Ref, page_tree: Ref,

View File

@ -143,8 +143,8 @@ impl Font {
loca: None, loca: None,
glyphs: Vec::with_capacity(chars.len()), glyphs: Vec::with_capacity(chars.len()),
chars, chars,
records: Vec::new(), records: vec![],
body: Vec::new(), body: vec![],
}; };
subsetter.subset(needed_tables, optional_tables) subsetter.subset(needed_tables, optional_tables)
@ -152,7 +152,7 @@ impl Font {
} }
/// Font metrics relevant to the typesetting engine. /// Font metrics relevant to the typesetting engine.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub struct FontMetrics { pub struct FontMetrics {
/// Whether the font is italic. /// Whether the font is italic.
pub is_italic: bool, pub is_italic: bool,
@ -275,10 +275,10 @@ macro_rules! font_info {
} }
/// Criteria to filter fonts. /// Criteria to filter fonts.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct FontFilter<'a> { pub struct FontFilter<'a> {
/// A fallback list of font families we accept. The first family in this list, that also /// A fallback list of font families to accept. The first family in this list, that also
/// satisfies the other conditions shall be returned. /// satisfies the other conditions, shall be returned.
pub families: &'a [FontFamily], pub families: &'a [FontFamily],
/// If some, matches only italic/non-italic fonts, otherwise any. /// If some, matches only italic/non-italic fonts, otherwise any.
pub italic: Option<bool>, pub italic: Option<bool>,
@ -298,13 +298,6 @@ impl<'a> FontFilter<'a> {
} }
} }
/// Whether this filter matches the given info.
pub fn matches(&self, info: &FontInfo) -> bool {
self.italic.map(|i| i == info.italic).unwrap_or(true)
&& self.bold.map(|i| i == info.bold).unwrap_or(true)
&& self.families.iter().any(|family| info.families.contains(family))
}
/// Set the italic value to something. /// Set the italic value to something.
pub fn italic(&mut self, italic: bool) -> &mut Self { pub fn italic(&mut self, italic: bool) -> &mut Self {
self.italic = Some(italic); self self.italic = Some(italic); self
@ -314,6 +307,13 @@ impl<'a> FontFilter<'a> {
pub fn bold(&mut self, bold: bool) -> &mut Self { pub fn bold(&mut self, bold: bool) -> &mut Self {
self.bold = Some(bold); self self.bold = Some(bold); self
} }
/// Whether this filter matches the given info.
pub fn matches(&self, info: &FontInfo) -> bool {
self.italic.map(|i| i == info.italic).unwrap_or(true)
&& self.bold.map(|i| i == info.bold).unwrap_or(true)
&& self.families.iter().any(|family| info.families.contains(family))
}
} }
/// A family of fonts (either generic or named). /// A family of fonts (either generic or named).
@ -326,6 +326,7 @@ pub enum FontFamily {
} }
/// A font provider serving fonts from a folder on the local file system. /// A font provider serving fonts from a folder on the local file system.
#[derive(Debug)]
pub struct FileSystemFontProvider { pub struct FileSystemFontProvider {
base: PathBuf, base: PathBuf,
paths: Vec<PathBuf>, paths: Vec<PathBuf>,
@ -346,29 +347,36 @@ impl FileSystemFontProvider {
/// ("NotoSans-Italic.ttf", font_info!(["NotoSans", SansSerif], italic)), /// ("NotoSans-Italic.ttf", font_info!(["NotoSans", SansSerif], italic)),
/// ]); /// ]);
/// ``` /// ```
#[inline]
pub fn new<B, I, P>(base: B, infos: I) -> FileSystemFontProvider pub fn new<B, I, P>(base: B, infos: I) -> FileSystemFontProvider
where where
B: Into<PathBuf>, B: Into<PathBuf>,
I: IntoIterator<Item = (P, FontInfo)>, I: IntoIterator<Item = (P, FontInfo)>,
P: Into<PathBuf>, P: Into<PathBuf>,
{ {
let mut paths = Vec::new(); // Find out how long the iterator is at least, to reserve the correct
let mut font_infos = Vec::new(); // capacity for the vectors.
let iter = infos.into_iter();
let min = iter.size_hint().0;
for (path, info) in infos.into_iter() { // Split the iterator into two seperated vectors.
let mut paths = Vec::with_capacity(min);
let mut infos = Vec::with_capacity(min);
for (path, info) in iter {
paths.push(path.into()); paths.push(path.into());
font_infos.push(info); infos.push(info);
} }
FileSystemFontProvider { FileSystemFontProvider {
base: base.into(), base: base.into(),
paths, paths,
infos: font_infos, infos,
} }
} }
} }
impl FontProvider for FileSystemFontProvider { impl FontProvider for FileSystemFontProvider {
#[inline]
fn get(&self, info: &FontInfo) -> Option<Box<dyn FontData>> { fn get(&self, info: &FontInfo) -> Option<Box<dyn FontData>> {
let index = self.infos.iter().position(|i| i == info)?; let index = self.infos.iter().position(|i| i == info)?;
let path = &self.paths[index]; let path = &self.paths[index];
@ -376,16 +384,17 @@ impl FontProvider for FileSystemFontProvider {
Some(Box::new(file) as Box<FontData>) Some(Box::new(file) as Box<FontData>)
} }
#[inline]
fn available<'a>(&'a self) -> &'a [FontInfo] { fn available<'a>(&'a self) -> &'a [FontInfo] {
&self.infos &self.infos
} }
} }
#[derive(Debug)] #[derive(Debug)]
struct Subsetter<'p> { struct Subsetter<'d> {
// Original font // Original font
font: &'p Font, font: &'d Font,
reader: OpenTypeReader<Cursor<&'p [u8]>>, reader: OpenTypeReader<Cursor<&'d [u8]>>,
outlines: Outlines, outlines: Outlines,
tables: Vec<TableRecord>, tables: Vec<TableRecord>,
cmap: Option<CharMap>, cmap: Option<CharMap>,
@ -399,7 +408,7 @@ struct Subsetter<'p> {
body: Vec<u8>, body: Vec<u8>,
} }
impl<'p> Subsetter<'p> { impl<'d> Subsetter<'d> {
fn subset<I1, S1, I2, S2>(mut self, needed_tables: I1, optional_tables: I2) fn subset<I1, S1, I2, S2>(mut self, needed_tables: I1, optional_tables: I2)
-> FontResult<Font> -> FontResult<Font>
where where
@ -726,7 +735,7 @@ impl<'p> Subsetter<'p> {
})) }))
} }
fn get_table_data(&self, tag: Tag) -> FontResult<&'p [u8]> { fn get_table_data(&self, tag: Tag) -> FontResult<&'d [u8]> {
let record = match self.tables.binary_search_by_key(&tag, |r| r.tag) { let record = match self.tables.binary_search_by_key(&tag, |r| r.tag) {
Ok(index) => &self.tables[index], Ok(index) => &self.tables[index],
Err(_) => return Err(FontError::MissingTable(tag.to_string())), Err(_) => return Err(FontError::MissingTable(tag.to_string())),

View File

@ -2,13 +2,14 @@
//! //!
//! # Compilation //! # Compilation
//! - **Parsing:** The parsing step first transforms a plain string into an //! - **Parsing:** The parsing step first transforms a plain string into an
//! [iterator of tokens](crate::parsing::Tokens). Then the parser operates on that to construct //! [iterator of tokens](crate::parsing::Tokens). Then the [parser](crate::parsing::Parser)
//! a syntax tree. The structures describing the tree can be found in the [`syntax`] module. //! operates on that to construct a syntax tree. The structures describing the tree can be found
//! in the [syntax] module.
//! - **Typesetting:** The next step is to transform the syntax tree into a portable representation //! - **Typesetting:** The next step is to transform the syntax tree into a portable representation
//! of the typesetted document. Types for these can be found in the [`doc`] module. This //! of the typesetted document. Types for these can be found in the [doc] module. This
//! representation contains already the finished layout. //! representation contains already the finished layout.
//! - **Exporting:** The finished document can then be exported into supported formats. Submodules //! - **Exporting:** The finished document can then be exported into supported formats. Submodules
//! for the supported formats are located in the [`export`] module. Currently the only supported //! for the supported formats are located in the [export] module. Currently the only supported
//! format is _PDF_. //! format is _PDF_.
//! //!
//! # Example //! # Example
@ -82,7 +83,7 @@ impl<'p> Compiler<'p> {
Compiler { Compiler {
context: Context { context: Context {
style: Style::default(), style: Style::default(),
font_providers: Vec::new(), font_providers: vec![],
} }
} }
} }

View File

@ -44,7 +44,6 @@ enum TokensState<'s> {
} }
impl PartialEq for TokensState<'_> { impl PartialEq for TokensState<'_> {
#[inline]
fn eq(&self, other: &TokensState) -> bool { fn eq(&self, other: &TokensState) -> bool {
use TokensState as TS; use TokensState as TS;
@ -184,26 +183,22 @@ impl<'s> Tokens<'s> {
} }
/// Advance the iterator by one step. /// Advance the iterator by one step.
#[inline]
fn advance(&mut self) { fn advance(&mut self) {
self.words.next(); self.words.next();
} }
/// Switch to the given state. /// Switch to the given state.
#[inline]
fn switch(&mut self, mut state: TokensState<'s>) { fn switch(&mut self, mut state: TokensState<'s>) {
swap(&mut state, &mut self.state); swap(&mut state, &mut self.state);
self.stack.push(state); self.stack.push(state);
} }
/// Go back to the top-of-stack state. /// Go back to the top-of-stack state.
#[inline]
fn unswitch(&mut self) { fn unswitch(&mut self) {
self.state = self.stack.pop().unwrap_or(TokensState::Body); self.state = self.stack.pop().unwrap_or(TokensState::Body);
} }
/// Advance and return the given token. /// Advance and return the given token.
#[inline]
fn consumed(&mut self, token: Token<'s>) -> Token<'s> { fn consumed(&mut self, token: Token<'s>) -> Token<'s> {
self.advance(); self.advance();
token token
@ -211,8 +206,8 @@ impl<'s> Tokens<'s> {
} }
/// Transforms token streams to syntax trees. /// Transforms token streams to syntax trees.
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct Parser<'s, T> where T: Iterator<Item = Token<'s>> { pub struct Parser<'s, T> where T: Iterator<Item=Token<'s>> {
tokens: Peekable<T>, tokens: Peekable<T>,
state: ParserState, state: ParserState,
stack: Vec<Function<'s>>, stack: Vec<Function<'s>>,
@ -220,7 +215,7 @@ pub struct Parser<'s, T> where T: Iterator<Item = Token<'s>> {
} }
/// The state the parser is in. /// The state the parser is in.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum ParserState { enum ParserState {
/// The base state of the parser. /// The base state of the parser.
Body, Body,
@ -228,9 +223,9 @@ enum ParserState {
Function, Function,
} }
impl<'s, T> Parser<'s, T> where T: Iterator<Item = Token<'s>> { impl<'s, T> Parser<'s, T> where T: Iterator<Item=Token<'s>> {
/// Create a new parser from a type that emits results of tokens. /// Create a new parser from a type that emits results of tokens.
pub fn new(tokens: T) -> Parser<'s, T> { pub(crate) fn new(tokens: T) -> Parser<'s, T> {
Parser { Parser {
tokens: tokens.peekable(), tokens: tokens.peekable(),
state: ParserState::Body, state: ParserState::Body,
@ -240,13 +235,13 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item = Token<'s>> {
} }
/// Parse into an abstract syntax tree. /// Parse into an abstract syntax tree.
pub fn parse(mut self) -> ParseResult<SyntaxTree<'s>> { pub(crate) fn parse(mut self) -> ParseResult<SyntaxTree<'s>> {
use ParserState as PS; use ParserState as PS;
while let Some(token) = self.tokens.next() { while let Some(token) = self.tokens.next() {
// Comment // Comment
if token == Token::Hashtag { if token == Token::Hashtag {
self.skip_while(|t| *t != Token::Newline); self.skip_while(|&t| t != Token::Newline);
self.advance(); self.advance();
} }
@ -314,13 +309,11 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item = Token<'s>> {
} }
/// Advance the iterator by one step. /// Advance the iterator by one step.
#[inline]
fn advance(&mut self) { fn advance(&mut self) {
self.tokens.next(); self.tokens.next();
} }
/// Skip tokens until the condition is met. /// Skip tokens until the condition is met.
#[inline]
fn skip_while<F>(&mut self, f: F) where F: Fn(&Token) -> bool { fn skip_while<F>(&mut self, f: F) where F: Fn(&Token) -> bool {
while let Some(token) = self.tokens.peek() { while let Some(token) = self.tokens.peek() {
if !f(token) { if !f(token) {
@ -331,16 +324,14 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item = Token<'s>> {
} }
/// Switch the state. /// Switch the state.
#[inline]
fn switch(&mut self, state: ParserState) { fn switch(&mut self, state: ParserState) {
self.state = state; self.state = state;
} }
/// Append a node to the top-of-stack function or the main tree itself. /// Append a node to the top-of-stack function or the main tree itself.
#[inline]
fn append(&mut self, node: Node<'s>) { fn append(&mut self, node: Node<'s>) {
let tree = match self.stack.last_mut() { let tree = match self.stack.last_mut() {
Some(func) => func.body.get_or_insert_with(|| SyntaxTree::new()), Some(func) => func.body.as_mut().unwrap(),
None => &mut self.tree, None => &mut self.tree,
}; };
@ -348,7 +339,6 @@ impl<'s, T> Parser<'s, T> where T: Iterator<Item = Token<'s>> {
} }
/// Gives a parsing error with a message. /// Gives a parsing error with a message.
#[inline]
fn err<R, S: Into<String>>(&self, message: S) -> ParseResult<R> { fn err<R, S: Into<String>>(&self, message: S) -> ParseResult<R> {
Err(ParseError { message: message.into() }) Err(ParseError { message: message.into() })
} }

View File

@ -2,7 +2,7 @@
/// A logical unit of the incoming text stream. /// A logical unit of the incoming text stream.
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Token<'s> { pub enum Token<'s> {
/// One or more whitespace (non-newline) codepoints. /// One or more whitespace (non-newline) codepoints.
Space, Space,

View File

@ -49,7 +49,7 @@ pub struct Spline<'s, T> {
} }
/// Represents either a splitted substring or a splinor. /// Represents either a splitted substring or a splinor.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum Splined<'s, T> { pub enum Splined<'s, T> {
/// A substring. /// A substring.
Value(&'s str), Value(&'s str),