Refactor template variable collecting and freezing

This change extracts template variable collectiong and freezing into
a different module to keep the elements module clean.
This commit also changes all Mutex'es to RwLocks to get better performance
with read-only locking (the increase is measurable even with small files).
pull/1/head
trivernis 5 years ago
parent 792d991fb2
commit 815bd26e51

2
Cargo.lock generated

@ -566,7 +566,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "snekdown"
version = "0.15.0"
version = "0.15.1"
dependencies = [
"chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
"colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)",

@ -1,6 +1,6 @@
[package]
name = "snekdown"
version = "0.15.0"
version = "0.15.1"
authors = ["trivernis <trivernis@protonmail.com>"]
edition = "2018"
license-file = "LICENSE"

@ -2,6 +2,7 @@ use crate::format::PlaceholderTemplate;
use crate::parsing::bibliography::{BibEntry, BibReference};
use crate::parsing::configuration::Value;
use crate::parsing::elements::*;
use crate::parsing::templates::{Template, TemplateVariable};
use htmlescape::{encode_attribute, encode_minimal};
use minify::html::minify;
use std::cell::RefCell;
@ -40,7 +41,7 @@ impl ToHtml for Line {
Line::Ruler(ruler) => ruler.to_html(),
Line::Anchor(anchor) => anchor.to_html(),
Line::Centered(centered) => centered.to_html(),
Line::BibEntry(bib) => bib.lock().unwrap().to_html(),
Line::BibEntry(bib) => bib.read().unwrap().to_html(),
}
}
}
@ -56,13 +57,13 @@ impl ToHtml for Inline {
Inline::Underlined(under) => under.to_html(),
Inline::Bold(bold) => bold.to_html(),
Inline::Image(img) => img.to_html(),
Inline::Placeholder(placeholder) => placeholder.lock().unwrap().to_html(),
Inline::Placeholder(placeholder) => placeholder.read().unwrap().to_html(),
Inline::Superscript(superscript) => superscript.to_html(),
Inline::Checkbox(checkbox) => checkbox.to_html(),
Inline::Emoji(emoji) => emoji.to_html(),
Inline::Colored(colored) => colored.to_html(),
Inline::BibReference(bibref) => bibref.lock().unwrap().to_html(),
Inline::TemplateVar(var) => var.lock().unwrap().to_html(),
Inline::BibReference(bibref) => bibref.read().unwrap().to_html(),
Inline::TemplateVar(var) => var.read().unwrap().to_html(),
}
}
}
@ -77,7 +78,7 @@ impl ToHtml for Block {
Block::Quote(quote) => quote.to_html(),
Block::Section(section) => section.to_html(),
Block::Import(import) => import.to_html(),
Block::Placeholder(placeholder) => placeholder.lock().unwrap().to_html(),
Block::Placeholder(placeholder) => placeholder.read().unwrap().to_html(),
}
}
}
@ -87,7 +88,7 @@ impl ToHtml for MetadataValue {
match self {
MetadataValue::String(string) => encode_minimal(string),
MetadataValue::Integer(num) => format!("{}", num),
MetadataValue::Placeholder(ph) => ph.lock().unwrap().to_html(),
MetadataValue::Placeholder(ph) => ph.read().unwrap().to_html(),
MetadataValue::Bool(b) => format!("{}", b),
MetadataValue::Float(f) => format!("{}", f),
MetadataValue::Template(t) => t.to_html(),
@ -123,7 +124,7 @@ impl ToHtml for Document {
impl ToHtml for Import {
fn to_html(&self) -> String {
let anchor = self.anchor.lock().unwrap();
let anchor = self.anchor.read().unwrap();
if let Some(document) = &anchor.document {
document.to_html()
} else {
@ -485,7 +486,7 @@ impl ToHtml for BibEntry {
return "".to_string();
}
if let Some(display) = &self.display {
let display = display.lock().unwrap();
let display = display.read().unwrap();
if let Value::Template(template) = display.get() {
let replacements = self
.as_map()

@ -3,7 +3,7 @@ use crate::parsing::configuration::keys::{BIB_DISPLAY, BIB_HIDE_UNUSED};
use crate::parsing::configuration::{ConfigRefEntry, Configuration, Value};
use crate::parsing::elements::Metadata;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, RwLock};
const B_NUMBER: &str = "number";
const B_AUTHOR: &str = "author";
@ -31,14 +31,14 @@ pub struct BibEntry {
#[derive(Clone, Debug)]
pub struct BibReference {
pub(crate) key: String,
pub(crate) reference_entry: Option<Arc<Mutex<BibEntry>>>,
pub(crate) reference_entry: Option<Arc<RwLock<BibEntry>>>,
pub(crate) display: Option<ConfigRefEntry>,
}
#[derive(Clone, Debug)]
pub struct Bibliography {
entries: HashMap<String, Arc<Mutex<BibEntry>>>,
references: Vec<Arc<Mutex<BibReference>>>,
entries: HashMap<String, Arc<RwLock<BibEntry>>>,
references: Vec<Arc<RwLock<BibReference>>>,
}
impl BibEntry {
@ -110,7 +110,7 @@ impl BibEntry {
pub fn is_visible(&self) -> bool {
if let Some(hide_cfg) = &self.hide_unused {
let hide_cfg = hide_cfg.lock().unwrap();
let hide_cfg = hide_cfg.read().unwrap();
if let Value::Bool(b) = hide_cfg.get() {
if *b && self.ref_count == 0 {
return false;
@ -132,15 +132,15 @@ impl BibReference {
}
/// sets the reference to the bib entry
pub(crate) fn set_entry(&mut self, entry: Arc<Mutex<BibEntry>>) {
pub(crate) fn set_entry(&mut self, entry: Arc<RwLock<BibEntry>>) {
self.reference_entry = Some(entry)
}
pub(crate) fn get_formatted(&self) -> String {
if let Some(entry) = &self.reference_entry {
let entry = entry.lock().unwrap();
let entry = entry.read().unwrap();
if let Some(display) = &self.display {
let display = display.lock().unwrap();
let display = display.read().unwrap();
let mut template = PlaceholderTemplate::new(display.get().as_string());
template.set_replacements(entry.as_map());
return template.render();
@ -163,10 +163,10 @@ impl Bibliography {
pub(crate) fn assign_entry_data(&mut self) {
let mut count = 0;
self.references.iter().for_each(|e| {
let mut reference = e.lock().unwrap();
let mut reference = e.write().unwrap();
if let Some(entry) = self.entries.get(&reference.key) {
{
let mut entry_raw = entry.lock().unwrap();
let mut entry_raw = entry.write().unwrap();
let ref_count = entry_raw.ref_count;
entry_raw.set_ref_count(ref_count + 1);
}
@ -174,7 +174,7 @@ impl Bibliography {
}
});
self.entries.iter().for_each(|(_, e)| {
let mut entry = e.lock().unwrap();
let mut entry = e.write().unwrap();
if entry.is_visible() {
count += 1;
entry.set_number(count)
@ -182,12 +182,12 @@ impl Bibliography {
});
}
pub fn add_ref_entry(&mut self, entry: Arc<Mutex<BibReference>>) {
pub fn add_ref_entry(&mut self, entry: Arc<RwLock<BibReference>>) {
self.references.push(entry)
}
pub fn add_bib_entry(&mut self, entry: Arc<Mutex<BibEntry>>) {
let key = entry.lock().unwrap().key.clone();
pub fn add_bib_entry(&mut self, entry: Arc<RwLock<BibEntry>>) {
let key = entry.read().unwrap().key.clone();
self.entries.insert(key, entry);
}

@ -2,9 +2,10 @@ use crate::parsing::configuration::config::RootConfig;
use crate::parsing::configuration::keys::{
BIB_DISPLAY, BIB_HIDE_UNUSED, BIB_REF_DISPLAY, META_AUTHOR, META_DATE, META_TITLE,
};
use crate::parsing::elements::{MetadataValue, Template};
use crate::parsing::elements::MetadataValue;
use crate::parsing::templates::Template;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, RwLock};
pub mod config;
pub(crate) mod keys;
@ -23,11 +24,11 @@ pub struct ConfigEntry {
inner: Value,
}
pub type ConfigRefEntry = Arc<Mutex<ConfigEntry>>;
pub type ConfigRefEntry = Arc<RwLock<ConfigEntry>>;
#[derive(Clone, Debug)]
pub struct Configuration {
config: Arc<Mutex<HashMap<String, ConfigRefEntry>>>,
config: Arc<RwLock<HashMap<String, ConfigRefEntry>>>,
}
impl Value {
@ -59,7 +60,7 @@ impl ConfigEntry {
impl Configuration {
pub fn new() -> Self {
Self {
config: Arc::new(Mutex::new(HashMap::new())),
config: Arc::new(RwLock::new(HashMap::new())),
}
}
@ -98,9 +99,9 @@ impl Configuration {
/// returns the value of a config entry
pub fn get_entry(&self, key: &str) -> Option<ConfigEntry> {
let config = self.config.lock().unwrap();
let config = self.config.read().unwrap();
if let Some(entry) = config.get(key) {
let value = entry.lock().unwrap();
let value = entry.read().unwrap();
Some(value.clone())
} else {
None
@ -109,7 +110,7 @@ impl Configuration {
/// returns a config entry that is a reference to a value
pub fn get_ref_entry(&self, key: &str) -> Option<ConfigRefEntry> {
let config = self.config.lock().unwrap();
let config = self.config.read().unwrap();
if let Some(entry) = config.get(&key.to_string()) {
Some(Arc::clone(entry))
} else {
@ -119,13 +120,13 @@ impl Configuration {
/// Sets a config parameter
pub fn set(&mut self, key: &str, value: Value) {
let mut config = self.config.lock().unwrap();
let mut config = self.config.write().unwrap();
if let Some(entry) = config.get(&key.to_string()) {
entry.lock().unwrap().set(value)
entry.write().unwrap().set(value)
} else {
config.insert(
key.to_string(),
Arc::new(Mutex::new(ConfigEntry::new(value))),
Arc::new(RwLock::new(ConfigEntry::new(value))),
);
}
}

@ -1,9 +1,10 @@
use crate::parsing::bibliography::{BibEntry, BibReference, Bibliography};
use crate::parsing::configuration::Configuration;
use crate::parsing::placeholders::ProcessPlaceholders;
use crate::parsing::templates::{Template, TemplateVariable};
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::sync::{Arc, RwLock};
pub const SECTION: &str = "section";
pub const PARAGRAPH: &str = "paragraph";
@ -19,7 +20,7 @@ pub enum MetadataValue {
Integer(i64),
Float(f64),
Bool(bool),
Placeholder(Arc<Mutex<Placeholder>>),
Placeholder(Arc<RwLock<Placeholder>>),
Template(Template),
}
@ -39,7 +40,7 @@ pub enum Block {
CodeBlock(CodeBlock),
Quote(Quote),
Import(Import),
Placeholder(Arc<Mutex<Placeholder>>),
Placeholder(Arc<RwLock<Placeholder>>),
}
#[derive(Clone, Debug)]
@ -48,7 +49,7 @@ pub enum Line {
Ruler(Ruler),
Anchor(Anchor),
Centered(Centered),
BibEntry(Arc<Mutex<BibEntry>>),
BibEntry(Arc<RwLock<BibEntry>>),
}
#[derive(Clone, Debug)]
@ -56,7 +57,7 @@ pub struct Document {
pub elements: Vec<Block>,
pub(crate) is_root: bool,
pub(crate) path: Option<String>,
pub(crate) placeholders: Vec<Arc<Mutex<Placeholder>>>,
pub(crate) placeholders: Vec<Arc<RwLock<Placeholder>>>,
pub config: Configuration,
pub bibliography: Bibliography,
}
@ -125,7 +126,7 @@ pub struct Quote {
#[derive(Clone, Debug)]
pub struct Import {
pub(crate) path: String,
pub(crate) anchor: Arc<Mutex<ImportAnchor>>,
pub(crate) anchor: Arc<RwLock<ImportAnchor>>,
}
#[derive(Clone, Debug)]
@ -157,12 +158,12 @@ pub enum Inline {
Superscript(SuperscriptText),
Url(Url),
Image(Image),
Placeholder(Arc<Mutex<Placeholder>>),
Placeholder(Arc<RwLock<Placeholder>>),
Checkbox(Checkbox),
Emoji(Emoji),
Colored(Colored),
BibReference(Arc<Mutex<BibReference>>),
TemplateVar(Arc<Mutex<TemplateVariable>>),
BibReference(Arc<RwLock<BibReference>>),
TemplateVar(Arc<RwLock<TemplateVariable>>),
}
#[derive(Clone, Debug)]
@ -247,20 +248,6 @@ pub struct Colored {
pub(crate) color: String,
}
#[derive(Clone, Debug)]
pub struct Template {
pub(crate) text: Vec<Element>,
pub(crate) variables: HashMap<String, Arc<Mutex<TemplateVariable>>>,
}
#[derive(Clone, Debug)]
pub struct TemplateVariable {
pub(crate) prefix: String,
pub(crate) name: String,
pub(crate) suffix: String,
pub(crate) value: Option<Element>,
}
// implementations
impl Document {
@ -279,7 +266,7 @@ impl Document {
self.elements.push(element)
}
pub fn add_placeholder(&mut self, placeholder: Arc<Mutex<Placeholder>>) {
pub fn add_placeholder(&mut self, placeholder: Arc<RwLock<Placeholder>>) {
self.placeholders.push(placeholder);
}
@ -295,7 +282,7 @@ impl Document {
}
}
Block::Import(imp) => {
let anchor = imp.anchor.lock().unwrap();
let anchor = imp.anchor.read().unwrap();
if let Some(doc) = &anchor.document {
list.items.append(&mut doc.create_toc(ordered).items)
}
@ -334,7 +321,7 @@ impl Document {
}
Block::Import(imp) => {
let arc_anchor = Arc::clone(&imp.anchor);
let anchor = &mut arc_anchor.lock().unwrap();
let anchor = &mut arc_anchor.write().unwrap();
if let Some(doc) = &mut anchor.document {
self.placeholders.append(&mut doc.placeholders);
self.bibliography.combine(&mut doc.bibliography);
@ -415,11 +402,11 @@ impl Section {
if section.header.size == self.header.size + 1 {
self.elements.push(Block::Section(section))
} else {
let has_parent = Mutex::new(AtomicBool::new(true));
let has_parent = RwLock::new(AtomicBool::new(true));
let iterator = self.elements.iter_mut().rev().filter(|e| {
if let Block::Section(sec) = e {
if sec.header.size > section.header.size {
has_parent.lock().unwrap().store(true, Ordering::Relaxed);
has_parent.write().unwrap().store(true, Ordering::Relaxed);
true
} else {
false
@ -429,7 +416,7 @@ impl Section {
}
});
if has_parent.lock().unwrap().load(Ordering::Relaxed) {
if has_parent.read().unwrap().load(Ordering::Relaxed) {
for sec in iterator {
if let Block::Section(sec) = sec {
if sec.header.size < section.header.size {
@ -608,208 +595,3 @@ impl Metadata for InlineMetadata {
}
}
}
impl Element {
pub fn get_template_variables(&self) -> Vec<Arc<Mutex<TemplateVariable>>> {
match self {
Element::Block(block) => block
.get_template_variables()
.iter()
.filter_map(|e| e.clone())
.collect(),
Element::Inline(inline) => vec![inline.get_template_variable()]
.iter()
.filter_map(|e| e.clone())
.collect(),
Element::Line(line) => line
.get_template_variables()
.iter()
.filter_map(|e| e.clone())
.collect(),
}
}
pub fn freeze_variables(&mut self) -> Option<Arc<Mutex<TemplateVariable>>> {
match self {
Element::Block(b) => b.freeze_template_variables(),
Element::Line(l) => l.freeze_variables(),
Element::Inline(i) => return i.freeze_variables(),
}
None
}
}
impl Block {
pub fn get_template_variables(&self) -> Vec<Option<Arc<Mutex<TemplateVariable>>>> {
match self {
Block::Section(sec) => sec
.elements
.iter()
.map(|e| e.get_template_variables())
.flatten()
.collect(),
Block::Paragraph(par) => par
.elements
.iter()
.map(|l| l.get_template_variables())
.flatten()
.collect(),
Block::Quote(q) => q
.text
.iter()
.map(|t| t.subtext.iter().map(|i| i.get_template_variable()))
.flatten()
.collect(),
_ => Vec::new(),
}
}
pub fn freeze_template_variables(&mut self) {
match self {
Block::Section(s) => s
.elements
.iter_mut()
.for_each(|b| b.freeze_template_variables()),
Block::Paragraph(p) => p.elements.iter_mut().for_each(|l| l.freeze_variables()),
Block::Quote(q) => q.text.iter_mut().for_each(|t| {
t.subtext = t
.subtext
.iter_mut()
.map(|i| {
if let Some(t) = i.freeze_variables() {
Inline::TemplateVar(t)
} else {
(*i).clone()
}
})
.collect()
}),
_ => {}
}
}
}
impl Line {
pub fn get_template_variables(&self) -> Vec<Option<Arc<Mutex<TemplateVariable>>>> {
match self {
Line::Text(line) => line
.subtext
.iter()
.map(|s| s.get_template_variable())
.collect(),
_ => Vec::new(),
}
}
pub fn freeze_variables(&mut self) {
match self {
Line::Text(text) => {
text.subtext = text
.subtext
.iter_mut()
.map(|i| {
if let Some(t) = i.freeze_variables() {
Inline::TemplateVar(t)
} else {
(*i).clone()
}
})
.collect()
}
_ => {}
}
}
}
impl Inline {
pub fn get_template_variable(&self) -> Option<Arc<Mutex<TemplateVariable>>> {
match self {
Inline::TemplateVar(temp) => Some(Arc::clone(temp)),
Inline::Colored(col) => col.value.get_template_variable(),
Inline::Superscript(sup) => sup.value.get_template_variable(),
Inline::Striked(striked) => striked.value.get_template_variable(),
Inline::Underlined(under) => under.value.get_template_variable(),
Inline::Italic(it) => it.value.get_template_variable(),
Inline::Bold(bo) => bo.value.get_template_variable(),
_ => None,
}
}
pub fn freeze_variables(&mut self) -> Option<Arc<Mutex<TemplateVariable>>> {
match self {
Inline::TemplateVar(temp) => {
let temp = temp.lock().unwrap();
return Some(Arc::new(Mutex::new((*temp).clone())));
}
Inline::Colored(col) => {
if let Some(temp) = col.value.freeze_variables() {
col.value = Box::new(Inline::TemplateVar(temp))
}
}
Inline::Superscript(sup) => {
if let Some(temp) = sup.value.freeze_variables() {
sup.value = Box::new(Inline::TemplateVar(temp))
}
}
Inline::Striked(striked) => {
if let Some(temp) = striked.value.freeze_variables() {
striked.value = Box::new(Inline::TemplateVar(temp))
}
}
Inline::Underlined(under) => {
if let Some(temp) = under.value.freeze_variables() {
under.value = Box::new(Inline::TemplateVar(temp))
}
}
Inline::Italic(it) => {
if let Some(temp) = it.value.freeze_variables() {
it.value = Box::new(Inline::TemplateVar(temp))
}
}
Inline::Bold(bo) => {
if let Some(temp) = bo.value.freeze_variables() {
bo.value = Box::new(Inline::TemplateVar(temp))
}
}
_ => {}
}
None
}
}
impl Template {
pub fn render(&self, replacements: HashMap<String, Element>) -> Vec<Element> {
replacements.iter().for_each(|(k, r)| {
if let Some(v) = self.variables.get(k) {
v.lock().unwrap().set_value(r.clone())
}
});
let elements = self
.text
.iter()
.map(|e| {
let mut e = e.clone();
if let Some(template) = e.freeze_variables() {
Element::Inline(Box::new(Inline::TemplateVar(template)))
} else {
e
}
})
.collect();
self.variables
.iter()
.for_each(|(_, v)| v.lock().unwrap().reset());
elements
}
}
impl TemplateVariable {
pub fn set_value(&mut self, value: Element) {
self.value = Some(value)
}
pub fn reset(&mut self) {
self.value = None
}
}

@ -3,9 +3,10 @@ use super::elements::*;
use super::tokens::*;
use crate::parsing::bibliography::BibReference;
use crate::parsing::configuration::keys::BIB_REF_DISPLAY;
use crate::parsing::templates::TemplateVariable;
use crate::parsing::utils::{ParseError, ParseResult};
use crate::Parser;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, RwLock};
pub(crate) trait ParseInline {
fn parse_surrounded(&mut self, surrounding: &char) -> ParseResult<Inline>;
@ -21,8 +22,8 @@ pub(crate) trait ParseInline {
fn parse_superscript(&mut self) -> ParseResult<SuperscriptText>;
fn parse_emoji(&mut self) -> ParseResult<Emoji>;
fn parse_colored(&mut self) -> ParseResult<Colored>;
fn parse_bibref(&mut self) -> ParseResult<Arc<Mutex<BibReference>>>;
fn parse_template_variable(&mut self) -> ParseResult<Arc<Mutex<TemplateVariable>>>;
fn parse_bibref(&mut self) -> ParseResult<Arc<RwLock<BibReference>>>;
fn parse_template_variable(&mut self) -> ParseResult<Arc<RwLock<TemplateVariable>>>;
fn parse_plain(&mut self) -> ParseResult<PlainText>;
}
@ -238,13 +239,13 @@ impl ParseInline for Parser {
})
}
fn parse_bibref(&mut self) -> ParseResult<Arc<Mutex<BibReference>>> {
fn parse_bibref(&mut self) -> ParseResult<Arc<RwLock<BibReference>>> {
let start_index = self.index;
self.assert_special_sequence(&SQ_BIBREF_START, start_index)?;
self.skip_char();
let key = self.get_string_until_or_revert(&[BIBREF_CLOSE], &[SPACE, LB], start_index)?;
self.skip_char();
let ref_entry = Arc::new(Mutex::new(BibReference::new(
let ref_entry = Arc::new(RwLock::new(BibReference::new(
key,
self.document.config.get_ref_entry(BIB_REF_DISPLAY),
)));
@ -256,7 +257,7 @@ impl ParseInline for Parser {
}
/// parses a template variable {prefix{name}suffix}
fn parse_template_variable(&mut self) -> ParseResult<Arc<Mutex<TemplateVariable>>> {
fn parse_template_variable(&mut self) -> ParseResult<Arc<RwLock<TemplateVariable>>> {
let start_index = self.index;
self.assert_special(&TEMP_VAR_OPEN, start_index)?;
self.skip_char();
@ -266,7 +267,7 @@ impl ParseInline for Parser {
self.skip_char();
let suffix = self.get_string_until_or_revert(&[TEMP_VAR_CLOSE], &[LB], start_index)?;
self.skip_char();
Ok(Arc::new(Mutex::new(TemplateVariable {
Ok(Arc::new(RwLock::new(TemplateVariable {
value: None,
name,
prefix,

@ -5,6 +5,7 @@ pub mod elements;
pub mod inline;
pub mod parser;
pub mod placeholders;
pub mod templates;
pub mod tokens;
#[macro_use]

@ -2,7 +2,9 @@ use super::elements::*;
use super::tokens::*;
use crate::parsing::bibliography::BibEntry;
use crate::parsing::charstate::CharStateMachine;
use crate::parsing::configuration::Configuration;
use crate::parsing::inline::ParseInline;
use crate::parsing::templates::{GetTemplateVariables, Template, TemplateVariable};
use crate::parsing::utils::{ParseError, ParseResult};
use colored::*;
use crossbeam_utils::sync::WaitGroup;
@ -11,7 +13,7 @@ use std::fs::File;
use std::io;
use std::io::{BufRead, BufReader, Cursor};
use std::path::Path;
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex, RwLock};
use std::thread;
pub struct Parser {
@ -107,6 +109,7 @@ impl Parser {
if let Some(ch) = text.get(0) {
current_char = *ch
}
let document = Document::new(!is_child);
Self {
index: 0,
text,
@ -121,12 +124,16 @@ impl Parser {
previous_char: ' ',
inline_break_at: Vec::new(),
block_break_at: Vec::new(),
document: Document::new(!is_child),
document,
reader,
parse_variables: false,
}
}
pub fn set_config(&mut self, config: Configuration) {
self.document.config = config;
}
/// Returns the text of the parser as a string
fn get_text(&self) -> String {
self.text
@ -159,7 +166,7 @@ impl Parser {
}
/// starts up a new thread to parse the imported document
fn import_document(&mut self, path: String) -> ParseResult<Arc<Mutex<ImportAnchor>>> {
fn import_document(&mut self, path: String) -> ParseResult<Arc<RwLock<ImportAnchor>>> {
let path = self.transform_path(path);
let path_info = Path::new(&path);
if !path_info.exists() || !path_info.is_file() {
@ -183,15 +190,17 @@ impl Parser {
}
paths.push(path.clone());
}
let anchor = Arc::new(Mutex::new(ImportAnchor::new()));
let anchor = Arc::new(RwLock::new(ImportAnchor::new()));
let anchor_clone = Arc::clone(&anchor);
let wg = self.wg.clone();
let paths = Arc::clone(&self.paths);
let config = self.document.config.clone();
let _ = thread::spawn(move || {
let mut parser = Parser::child_from_file(path, paths).unwrap();
parser.set_config(config);
let document = parser.parse();
anchor_clone.lock().unwrap().set_document(document);
anchor_clone.write().unwrap().set_document(document);
drop(wg);
});
@ -707,7 +716,7 @@ impl Parser {
}
}
fn parse_bib_entry(&mut self) -> ParseResult<Arc<Mutex<BibEntry>>> {
fn parse_bib_entry(&mut self) -> ParseResult<Arc<RwLock<BibEntry>>> {
let start_index = self.index;
self.seek_inline_whitespace();
self.assert_special(&BIB_KEY_OPEN, start_index)?;
@ -723,7 +732,7 @@ impl Parser {
let url = self.get_string_until_or_revert(&[LB], &[], start_index)?;
BibEntry::from_url(key, url, &self.document.config)
};
let entry_ref = Arc::new(Mutex::new(entry));
let entry_ref = Arc::new(RwLock::new(entry));
self.document
.bibliography
.add_bib_entry(Arc::clone(&entry_ref));
@ -742,7 +751,7 @@ impl Parser {
}
/// parses a placeholder element
pub(crate) fn parse_placeholder(&mut self) -> Result<Arc<Mutex<Placeholder>>, ParseError> {
pub(crate) fn parse_placeholder(&mut self) -> Result<Arc<RwLock<Placeholder>>, ParseError> {
let start_index = self.index;
self.assert_special_sequence(&SQ_PHOLDER_START, self.index)?;
self.skip_char();
@ -760,7 +769,7 @@ impl Parser {
None
};
let placeholder = Arc::new(Mutex::new(Placeholder::new(name, metadata)));
let placeholder = Arc::new(RwLock::new(Placeholder::new(name, metadata)));
self.document.add_placeholder(Arc::clone(&placeholder));
Ok(placeholder)
@ -819,14 +828,14 @@ impl Parser {
self.inline_break_at.clear();
self.assert_special(&TEMPLATE, start_index)?;
self.skip_char();
let vars: HashMap<String, Arc<Mutex<TemplateVariable>>> = elements
let vars: HashMap<String, Arc<RwLock<TemplateVariable>>> = elements
.iter()
.map(|e| e.get_template_variables())
.flatten()
.map(|e: Arc<Mutex<TemplateVariable>>| {
.map(|e: Arc<RwLock<TemplateVariable>>| {
let name;
{
name = e.lock().unwrap().name.clone();
name = e.read().unwrap().name.clone();
};
(name, e)

@ -37,7 +37,7 @@ impl ProcessPlaceholders for Document {
/// parses all placeholders and assigns values to them
fn process_placeholders(&mut self) {
self.placeholders.iter().for_each(|p| {
let mut pholder = p.lock().unwrap();
let mut pholder = p.write().unwrap();
match pholder.name.to_lowercase().as_str() {
P_TOC => {
let ordered = if let Some(meta) = &pholder.metadata {
@ -74,7 +74,7 @@ impl ProcessPlaceholders for Document {
let placeholders = self.placeholders.clone();
placeholders.iter().for_each(|p| {
let mut pholder = p.lock().unwrap();
let mut pholder = p.write().unwrap();
let name = pholder.name.clone();
if let Some(cap) = RE_SET.captures(&name) {

@ -0,0 +1,291 @@
use crate::parsing::elements::{Block, Element, Inline, Line, ListItem};
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
pub trait FreezeVariables {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>>;
}
pub trait GetTemplateVariables {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>>;
}
#[derive(Clone, Debug)]
pub struct Template {
pub(crate) text: Vec<Element>,
pub(crate) variables: HashMap<String, Arc<RwLock<TemplateVariable>>>,
}
#[derive(Clone, Debug)]
pub struct TemplateVariable {
pub(crate) prefix: String,
pub(crate) name: String,
pub(crate) suffix: String,
pub(crate) value: Option<Element>,
}
impl Template {
pub fn render(&self, replacements: HashMap<String, Element>) -> Vec<Element> {
replacements.iter().for_each(|(k, r)| {
if let Some(v) = self.variables.get(k) {
v.write().unwrap().set_value(r.clone())
}
});
let elements = self
.text
.iter()
.map(|e| {
let mut e = e.clone();
if let Some(template) = e.freeze_variables() {
Element::Inline(Box::new(Inline::TemplateVar(template)))
} else {
e
}
})
.collect();
self.variables
.iter()
.for_each(|(_, v)| v.write().unwrap().reset());
elements
}
}
impl TemplateVariable {
pub fn set_value(&mut self, value: Element) {
self.value = Some(value)
}
pub fn reset(&mut self) {
self.value = None
}
}
impl GetTemplateVariables for Inline {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>> {
match self {
Inline::TemplateVar(temp) => vec![Arc::clone(temp)],
Inline::Colored(col) => col.value.get_template_variables(),
Inline::Superscript(sup) => sup.value.get_template_variables(),
Inline::Striked(striked) => striked.value.get_template_variables(),
Inline::Underlined(under) => under.value.get_template_variables(),
Inline::Italic(it) => it.value.get_template_variables(),
Inline::Bold(bo) => bo.value.get_template_variables(),
_ => Vec::new(),
}
}
}
impl GetTemplateVariables for Line {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>> {
match self {
Line::Text(line) => line
.subtext
.iter()
.map(|s| s.get_template_variables())
.flatten()
.collect(),
Line::Centered(center) => center
.line
.subtext
.iter()
.map(|s| s.get_template_variables())
.flatten()
.collect(),
_ => Vec::new(),
}
}
}
impl GetTemplateVariables for Block {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>> {
match self {
Block::Section(sec) => sec
.elements
.iter()
.map(|e| e.get_template_variables())
.flatten()
.collect(),
Block::Paragraph(par) => par
.elements
.iter()
.map(|l| l.get_template_variables())
.flatten()
.collect(),
Block::Quote(q) => q
.text
.iter()
.map(|t| {
t.subtext
.iter()
.map(|i| i.get_template_variables())
.flatten()
})
.flatten()
.collect(),
Block::List(list) => list
.items
.iter()
.map(|item| item.get_template_variables())
.flatten()
.collect(),
_ => Vec::new(),
}
}
}
impl GetTemplateVariables for Element {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>> {
match self {
Element::Block(block) => block.get_template_variables(),
Element::Inline(inline) => inline.get_template_variables(),
Element::Line(line) => line.get_template_variables(),
}
}
}
impl FreezeVariables for Inline {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>> {
match self {
Inline::TemplateVar(temp) => {
let temp = temp.read().unwrap();
return Some(Arc::new(RwLock::new((*temp).clone())));
}
Inline::Colored(col) => {
if let Some(temp) = col.value.freeze_variables() {
col.value = Box::new(Inline::TemplateVar(temp))
}
}
Inline::Superscript(sup) => {
if let Some(temp) = sup.value.freeze_variables() {
sup.value = Box::new(Inline::TemplateVar(temp))
}
}
Inline::Striked(striked) => {
if let Some(temp) = striked.value.freeze_variables() {
striked.value = Box::new(Inline::TemplateVar(temp))
}
}
Inline::Underlined(under) => {
if let Some(temp) = under.value.freeze_variables() {
under.value = Box::new(Inline::TemplateVar(temp))
}
}
Inline::Italic(it) => {
if let Some(temp) = it.value.freeze_variables() {
it.value = Box::new(Inline::TemplateVar(temp))
}
}
Inline::Bold(bo) => {
if let Some(temp) = bo.value.freeze_variables() {
bo.value = Box::new(Inline::TemplateVar(temp))
}
}
_ => {}
}
None
}
}
impl GetTemplateVariables for ListItem {
fn get_template_variables(&self) -> Vec<Arc<RwLock<TemplateVariable>>> {
let mut inner_vars: Vec<Arc<RwLock<TemplateVariable>>> = self
.children
.iter()
.map(|child| child.get_template_variables())
.flatten()
.collect();
inner_vars.append(&mut self.text.get_template_variables());
inner_vars
}
}
impl FreezeVariables for Line {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>> {
match self {
Line::Text(text) => {
text.subtext = text
.subtext
.iter_mut()
.map(|i| {
if let Some(t) = i.freeze_variables() {
Inline::TemplateVar(t)
} else {
(*i).clone()
}
})
.collect()
}
Line::Centered(center) => {
center.line.subtext = center
.line
.subtext
.iter_mut()
.map(|i| {
if let Some(t) = i.freeze_variables() {
Inline::TemplateVar(t)
} else {
(*i).clone()
}
})
.collect()
}
_ => {}
}
None
}
}
impl FreezeVariables for Block {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>> {
match self {
Block::Section(s) => s.elements.iter_mut().for_each(|b| {
b.freeze_variables();
}),
Block::Paragraph(p) => p.elements.iter_mut().for_each(|l| {
l.freeze_variables();
}),
Block::Quote(q) => q.text.iter_mut().for_each(|t| {
t.subtext = t
.subtext
.iter_mut()
.map(|i| {
if let Some(t) = i.freeze_variables() {
Inline::TemplateVar(t)
} else {
(*i).clone()
}
})
.collect()
}),
Block::List(list) => list.items.iter_mut().for_each(|item| {
item.freeze_variables();
}),
_ => {}
};
None
}
}
impl FreezeVariables for Element {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>> {
match self {
Element::Block(b) => b.freeze_variables(),
Element::Line(l) => l.freeze_variables(),
Element::Inline(i) => return i.freeze_variables(),
};
None
}
}
impl FreezeVariables for ListItem {
fn freeze_variables(&mut self) -> Option<Arc<RwLock<TemplateVariable>>> {
self.children.iter_mut().for_each(|child| {
child.freeze_variables();
});
self.text.freeze_variables();
None
}
}
Loading…
Cancel
Save