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 4 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]] [[package]]
name = "snekdown" name = "snekdown"
version = "0.15.0" version = "0.15.1"
dependencies = [ dependencies = [
"chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)",

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

@ -2,6 +2,7 @@ use crate::format::PlaceholderTemplate;
use crate::parsing::bibliography::{BibEntry, BibReference}; use crate::parsing::bibliography::{BibEntry, BibReference};
use crate::parsing::configuration::Value; use crate::parsing::configuration::Value;
use crate::parsing::elements::*; use crate::parsing::elements::*;
use crate::parsing::templates::{Template, TemplateVariable};
use htmlescape::{encode_attribute, encode_minimal}; use htmlescape::{encode_attribute, encode_minimal};
use minify::html::minify; use minify::html::minify;
use std::cell::RefCell; use std::cell::RefCell;
@ -40,7 +41,7 @@ impl ToHtml for Line {
Line::Ruler(ruler) => ruler.to_html(), Line::Ruler(ruler) => ruler.to_html(),
Line::Anchor(anchor) => anchor.to_html(), Line::Anchor(anchor) => anchor.to_html(),
Line::Centered(centered) => centered.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::Underlined(under) => under.to_html(),
Inline::Bold(bold) => bold.to_html(), Inline::Bold(bold) => bold.to_html(),
Inline::Image(img) => img.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::Superscript(superscript) => superscript.to_html(),
Inline::Checkbox(checkbox) => checkbox.to_html(), Inline::Checkbox(checkbox) => checkbox.to_html(),
Inline::Emoji(emoji) => emoji.to_html(), Inline::Emoji(emoji) => emoji.to_html(),
Inline::Colored(colored) => colored.to_html(), Inline::Colored(colored) => colored.to_html(),
Inline::BibReference(bibref) => bibref.lock().unwrap().to_html(), Inline::BibReference(bibref) => bibref.read().unwrap().to_html(),
Inline::TemplateVar(var) => var.lock().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::Quote(quote) => quote.to_html(),
Block::Section(section) => section.to_html(), Block::Section(section) => section.to_html(),
Block::Import(import) => import.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 { match self {
MetadataValue::String(string) => encode_minimal(string), MetadataValue::String(string) => encode_minimal(string),
MetadataValue::Integer(num) => format!("{}", num), 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::Bool(b) => format!("{}", b),
MetadataValue::Float(f) => format!("{}", f), MetadataValue::Float(f) => format!("{}", f),
MetadataValue::Template(t) => t.to_html(), MetadataValue::Template(t) => t.to_html(),
@ -123,7 +124,7 @@ impl ToHtml for Document {
impl ToHtml for Import { impl ToHtml for Import {
fn to_html(&self) -> String { fn to_html(&self) -> String {
let anchor = self.anchor.lock().unwrap(); let anchor = self.anchor.read().unwrap();
if let Some(document) = &anchor.document { if let Some(document) = &anchor.document {
document.to_html() document.to_html()
} else { } else {
@ -485,7 +486,7 @@ impl ToHtml for BibEntry {
return "".to_string(); return "".to_string();
} }
if let Some(display) = &self.display { if let Some(display) = &self.display {
let display = display.lock().unwrap(); let display = display.read().unwrap();
if let Value::Template(template) = display.get() { if let Value::Template(template) = display.get() {
let replacements = self let replacements = self
.as_map() .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::configuration::{ConfigRefEntry, Configuration, Value};
use crate::parsing::elements::Metadata; use crate::parsing::elements::Metadata;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, RwLock};
const B_NUMBER: &str = "number"; const B_NUMBER: &str = "number";
const B_AUTHOR: &str = "author"; const B_AUTHOR: &str = "author";
@ -31,14 +31,14 @@ pub struct BibEntry {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct BibReference { pub struct BibReference {
pub(crate) key: String, 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>, pub(crate) display: Option<ConfigRefEntry>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Bibliography { pub struct Bibliography {
entries: HashMap<String, Arc<Mutex<BibEntry>>>, entries: HashMap<String, Arc<RwLock<BibEntry>>>,
references: Vec<Arc<Mutex<BibReference>>>, references: Vec<Arc<RwLock<BibReference>>>,
} }
impl BibEntry { impl BibEntry {
@ -110,7 +110,7 @@ impl BibEntry {
pub fn is_visible(&self) -> bool { pub fn is_visible(&self) -> bool {
if let Some(hide_cfg) = &self.hide_unused { 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 let Value::Bool(b) = hide_cfg.get() {
if *b && self.ref_count == 0 { if *b && self.ref_count == 0 {
return false; return false;
@ -132,15 +132,15 @@ impl BibReference {
} }
/// sets the reference to the bib entry /// 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) self.reference_entry = Some(entry)
} }
pub(crate) fn get_formatted(&self) -> String { pub(crate) fn get_formatted(&self) -> String {
if let Some(entry) = &self.reference_entry { if let Some(entry) = &self.reference_entry {
let entry = entry.lock().unwrap(); let entry = entry.read().unwrap();
if let Some(display) = &self.display { 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()); let mut template = PlaceholderTemplate::new(display.get().as_string());
template.set_replacements(entry.as_map()); template.set_replacements(entry.as_map());
return template.render(); return template.render();
@ -163,10 +163,10 @@ impl Bibliography {
pub(crate) fn assign_entry_data(&mut self) { pub(crate) fn assign_entry_data(&mut self) {
let mut count = 0; let mut count = 0;
self.references.iter().for_each(|e| { 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) { 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; let ref_count = entry_raw.ref_count;
entry_raw.set_ref_count(ref_count + 1); entry_raw.set_ref_count(ref_count + 1);
} }
@ -174,7 +174,7 @@ impl Bibliography {
} }
}); });
self.entries.iter().for_each(|(_, e)| { self.entries.iter().for_each(|(_, e)| {
let mut entry = e.lock().unwrap(); let mut entry = e.write().unwrap();
if entry.is_visible() { if entry.is_visible() {
count += 1; count += 1;
entry.set_number(count) 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) self.references.push(entry)
} }
pub fn add_bib_entry(&mut self, entry: Arc<Mutex<BibEntry>>) { pub fn add_bib_entry(&mut self, entry: Arc<RwLock<BibEntry>>) {
let key = entry.lock().unwrap().key.clone(); let key = entry.read().unwrap().key.clone();
self.entries.insert(key, entry); self.entries.insert(key, entry);
} }

@ -2,9 +2,10 @@ use crate::parsing::configuration::config::RootConfig;
use crate::parsing::configuration::keys::{ use crate::parsing::configuration::keys::{
BIB_DISPLAY, BIB_HIDE_UNUSED, BIB_REF_DISPLAY, META_AUTHOR, META_DATE, META_TITLE, 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::collections::HashMap;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, RwLock};
pub mod config; pub mod config;
pub(crate) mod keys; pub(crate) mod keys;
@ -23,11 +24,11 @@ pub struct ConfigEntry {
inner: Value, inner: Value,
} }
pub type ConfigRefEntry = Arc<Mutex<ConfigEntry>>; pub type ConfigRefEntry = Arc<RwLock<ConfigEntry>>;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Configuration { pub struct Configuration {
config: Arc<Mutex<HashMap<String, ConfigRefEntry>>>, config: Arc<RwLock<HashMap<String, ConfigRefEntry>>>,
} }
impl Value { impl Value {
@ -59,7 +60,7 @@ impl ConfigEntry {
impl Configuration { impl Configuration {
pub fn new() -> Self { pub fn new() -> Self {
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 /// returns the value of a config entry
pub fn get_entry(&self, key: &str) -> Option<ConfigEntry> { 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) { if let Some(entry) = config.get(key) {
let value = entry.lock().unwrap(); let value = entry.read().unwrap();
Some(value.clone()) Some(value.clone())
} else { } else {
None None
@ -109,7 +110,7 @@ impl Configuration {
/// returns a config entry that is a reference to a value /// returns a config entry that is a reference to a value
pub fn get_ref_entry(&self, key: &str) -> Option<ConfigRefEntry> { 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()) { if let Some(entry) = config.get(&key.to_string()) {
Some(Arc::clone(entry)) Some(Arc::clone(entry))
} else { } else {
@ -119,13 +120,13 @@ impl Configuration {
/// Sets a config parameter /// Sets a config parameter
pub fn set(&mut self, key: &str, value: Value) { 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()) { if let Some(entry) = config.get(&key.to_string()) {
entry.lock().unwrap().set(value) entry.write().unwrap().set(value)
} else { } else {
config.insert( config.insert(
key.to_string(), 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::bibliography::{BibEntry, BibReference, Bibliography};
use crate::parsing::configuration::Configuration; use crate::parsing::configuration::Configuration;
use crate::parsing::placeholders::ProcessPlaceholders; use crate::parsing::placeholders::ProcessPlaceholders;
use crate::parsing::templates::{Template, TemplateVariable};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, RwLock};
pub const SECTION: &str = "section"; pub const SECTION: &str = "section";
pub const PARAGRAPH: &str = "paragraph"; pub const PARAGRAPH: &str = "paragraph";
@ -19,7 +20,7 @@ pub enum MetadataValue {
Integer(i64), Integer(i64),
Float(f64), Float(f64),
Bool(bool), Bool(bool),
Placeholder(Arc<Mutex<Placeholder>>), Placeholder(Arc<RwLock<Placeholder>>),
Template(Template), Template(Template),
} }
@ -39,7 +40,7 @@ pub enum Block {
CodeBlock(CodeBlock), CodeBlock(CodeBlock),
Quote(Quote), Quote(Quote),
Import(Import), Import(Import),
Placeholder(Arc<Mutex<Placeholder>>), Placeholder(Arc<RwLock<Placeholder>>),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -48,7 +49,7 @@ pub enum Line {
Ruler(Ruler), Ruler(Ruler),
Anchor(Anchor), Anchor(Anchor),
Centered(Centered), Centered(Centered),
BibEntry(Arc<Mutex<BibEntry>>), BibEntry(Arc<RwLock<BibEntry>>),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -56,7 +57,7 @@ pub struct Document {
pub elements: Vec<Block>, pub elements: Vec<Block>,
pub(crate) is_root: bool, pub(crate) is_root: bool,
pub(crate) path: Option<String>, pub(crate) path: Option<String>,
pub(crate) placeholders: Vec<Arc<Mutex<Placeholder>>>, pub(crate) placeholders: Vec<Arc<RwLock<Placeholder>>>,
pub config: Configuration, pub config: Configuration,
pub bibliography: Bibliography, pub bibliography: Bibliography,
} }
@ -125,7 +126,7 @@ pub struct Quote {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Import { pub struct Import {
pub(crate) path: String, pub(crate) path: String,
pub(crate) anchor: Arc<Mutex<ImportAnchor>>, pub(crate) anchor: Arc<RwLock<ImportAnchor>>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -157,12 +158,12 @@ pub enum Inline {
Superscript(SuperscriptText), Superscript(SuperscriptText),
Url(Url), Url(Url),
Image(Image), Image(Image),
Placeholder(Arc<Mutex<Placeholder>>), Placeholder(Arc<RwLock<Placeholder>>),
Checkbox(Checkbox), Checkbox(Checkbox),
Emoji(Emoji), Emoji(Emoji),
Colored(Colored), Colored(Colored),
BibReference(Arc<Mutex<BibReference>>), BibReference(Arc<RwLock<BibReference>>),
TemplateVar(Arc<Mutex<TemplateVariable>>), TemplateVar(Arc<RwLock<TemplateVariable>>),
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -247,20 +248,6 @@ pub struct Colored {
pub(crate) color: String, 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 // implementations
impl Document { impl Document {
@ -279,7 +266,7 @@ impl Document {
self.elements.push(element) 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); self.placeholders.push(placeholder);
} }
@ -295,7 +282,7 @@ impl Document {
} }
} }
Block::Import(imp) => { Block::Import(imp) => {
let anchor = imp.anchor.lock().unwrap(); let anchor = imp.anchor.read().unwrap();
if let Some(doc) = &anchor.document { if let Some(doc) = &anchor.document {
list.items.append(&mut doc.create_toc(ordered).items) list.items.append(&mut doc.create_toc(ordered).items)
} }
@ -334,7 +321,7 @@ impl Document {
} }
Block::Import(imp) => { Block::Import(imp) => {
let arc_anchor = Arc::clone(&imp.anchor); 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 { if let Some(doc) = &mut anchor.document {
self.placeholders.append(&mut doc.placeholders); self.placeholders.append(&mut doc.placeholders);
self.bibliography.combine(&mut doc.bibliography); self.bibliography.combine(&mut doc.bibliography);
@ -415,11 +402,11 @@ impl Section {
if section.header.size == self.header.size + 1 { if section.header.size == self.header.size + 1 {
self.elements.push(Block::Section(section)) self.elements.push(Block::Section(section))
} else { } 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| { let iterator = self.elements.iter_mut().rev().filter(|e| {
if let Block::Section(sec) = e { if let Block::Section(sec) = e {
if sec.header.size > section.header.size { if sec.header.size > section.header.size {
has_parent.lock().unwrap().store(true, Ordering::Relaxed); has_parent.write().unwrap().store(true, Ordering::Relaxed);
true true
} else { } else {
false 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 { for sec in iterator {
if let Block::Section(sec) = sec { if let Block::Section(sec) = sec {
if sec.header.size < section.header.size { 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 super::tokens::*;
use crate::parsing::bibliography::BibReference; use crate::parsing::bibliography::BibReference;
use crate::parsing::configuration::keys::BIB_REF_DISPLAY; use crate::parsing::configuration::keys::BIB_REF_DISPLAY;
use crate::parsing::templates::TemplateVariable;
use crate::parsing::utils::{ParseError, ParseResult}; use crate::parsing::utils::{ParseError, ParseResult};
use crate::Parser; use crate::Parser;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, RwLock};
pub(crate) trait ParseInline { pub(crate) trait ParseInline {
fn parse_surrounded(&mut self, surrounding: &char) -> ParseResult<Inline>; 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_superscript(&mut self) -> ParseResult<SuperscriptText>;
fn parse_emoji(&mut self) -> ParseResult<Emoji>; fn parse_emoji(&mut self) -> ParseResult<Emoji>;
fn parse_colored(&mut self) -> ParseResult<Colored>; fn parse_colored(&mut self) -> ParseResult<Colored>;
fn parse_bibref(&mut self) -> ParseResult<Arc<Mutex<BibReference>>>; fn parse_bibref(&mut self) -> ParseResult<Arc<RwLock<BibReference>>>;
fn parse_template_variable(&mut self) -> ParseResult<Arc<Mutex<TemplateVariable>>>; fn parse_template_variable(&mut self) -> ParseResult<Arc<RwLock<TemplateVariable>>>;
fn parse_plain(&mut self) -> ParseResult<PlainText>; 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; let start_index = self.index;
self.assert_special_sequence(&SQ_BIBREF_START, start_index)?; self.assert_special_sequence(&SQ_BIBREF_START, start_index)?;
self.skip_char(); self.skip_char();
let key = self.get_string_until_or_revert(&[BIBREF_CLOSE], &[SPACE, LB], start_index)?; let key = self.get_string_until_or_revert(&[BIBREF_CLOSE], &[SPACE, LB], start_index)?;
self.skip_char(); self.skip_char();
let ref_entry = Arc::new(Mutex::new(BibReference::new( let ref_entry = Arc::new(RwLock::new(BibReference::new(
key, key,
self.document.config.get_ref_entry(BIB_REF_DISPLAY), self.document.config.get_ref_entry(BIB_REF_DISPLAY),
))); )));
@ -256,7 +257,7 @@ impl ParseInline for Parser {
} }
/// parses a template variable {prefix{name}suffix} /// 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; let start_index = self.index;
self.assert_special(&TEMP_VAR_OPEN, start_index)?; self.assert_special(&TEMP_VAR_OPEN, start_index)?;
self.skip_char(); self.skip_char();
@ -266,7 +267,7 @@ impl ParseInline for Parser {
self.skip_char(); self.skip_char();
let suffix = self.get_string_until_or_revert(&[TEMP_VAR_CLOSE], &[LB], start_index)?; let suffix = self.get_string_until_or_revert(&[TEMP_VAR_CLOSE], &[LB], start_index)?;
self.skip_char(); self.skip_char();
Ok(Arc::new(Mutex::new(TemplateVariable { Ok(Arc::new(RwLock::new(TemplateVariable {
value: None, value: None,
name, name,
prefix, prefix,

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

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

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