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.
pub(crate) struct Engine<'a> {
pub struct Engine<'t> {
// Immutable
tree: &'a SyntaxTree<'a>,
ctx: &'a Context<'a>,
tree: &'t SyntaxTree<'t>,
ctx: &'t Context<'t>,
// Mutable
fonts: Vec<Font>,
@ -23,22 +23,22 @@ pub(crate) struct Engine<'a> {
current_width: Size,
}
impl<'a> Engine<'a> {
impl<'t> Engine<'t> {
/// 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 {
tree,
ctx: context,
fonts: Vec::new(),
fonts: vec![],
active_font: 0,
text_commands: Vec::new(),
text_commands: vec![],
current_line: String::new(),
current_width: Size::zero(),
}
}
/// Generate the abstract document.
pub fn typeset(mut self) -> TypeResult<Document> {
pub(crate) fn typeset(mut self) -> TypeResult<Document> {
// Load font defined by style
let mut font = None;
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.
#[derive(Copy, Clone, PartialEq)]
#[derive(Copy, Clone, PartialEq, Default)]
pub struct Size {
/// The size in typographic points (1/72 inches).
points: f32,
@ -62,6 +62,7 @@ impl Debug for Size {
}
impl PartialOrd for Size {
#[inline]
fn partial_cmp(&self, other: &Size) -> Option<Ordering> {
self.points.partial_cmp(&other.points)
}
@ -70,12 +71,14 @@ impl PartialOrd for Size {
impl Neg for Size {
type Output = Size;
#[inline]
fn neg(self) -> Size {
Size { points: -self.points }
}
}
impl Sum for Size {
#[inline]
fn sum<I>(iter: I) -> Size where I: Iterator<Item=Size> {
iter.fold(Size::zero(), Add::add)
}

View File

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

View File

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

View File

@ -2,13 +2,14 @@
//!
//! # Compilation
//! - **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
//! a syntax tree. The structures describing the tree can be found in the [`syntax`] module.
//! [iterator of tokens](crate::parsing::Tokens). Then the [parser](crate::parsing::Parser)
//! 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
//! 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.
//! - **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_.
//!
//! # Example
@ -82,7 +83,7 @@ impl<'p> Compiler<'p> {
Compiler {
context: Context {
style: Style::default(),
font_providers: Vec::new(),
font_providers: vec![],
}
}
}

View File

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

View File

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

View File

@ -49,7 +49,7 @@ pub struct Spline<'s, T> {
}
/// 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> {
/// A substring.
Value(&'s str),