aboutsummaryrefslogtreecommitdiff
path: root/src/template.rs
diff options
context:
space:
mode:
authorRuben Beltran del Rio <git@r.bdr.sh>2024-03-08 14:53:01 +0100
committerRuben Beltran del Rio <git@r.bdr.sh>2024-03-08 14:53:01 +0100
commitf6a545b00a4046879b7cc25c06c37bb6b6880b43 (patch)
treebc7da8066c080ff850d1e423c0e33bd5fb83e095 /src/template.rs
parent2998247083406f914b3647cedd19abf5507bf2c6 (diff)
Use serde and time
Diffstat (limited to 'src/template.rs')
-rw-r--r--src/template.rs94
1 files changed, 93 insertions, 1 deletions
diff --git a/src/template.rs b/src/template.rs
index 37906ed..0332506 100644
--- a/src/template.rs
+++ b/src/template.rs
@@ -1,3 +1,4 @@
+use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;
use std::io::Read;
@@ -29,7 +30,7 @@ impl std::fmt::Display for Token {
write!(f, "\n]]]")
},
Token::IteratorDirective{collection, member_label, children} => {
- write!(f, "IteratorDirective {}: {} [[[\n", collection, member_label)?;
+ write!(f, "{} in {}\n", collection, member_label)?;
for child in children {
write!(f, "\t{}\n", child)?;
}
@@ -39,10 +40,101 @@ impl std::fmt::Display for Token {
}
}
+#[derive(Clone)]
+pub enum TemplateValue {
+ String(String),
+ Unsigned(u64),
+ Bool(bool),
+ Collection(Vec<TemplateContext>),
+ Context(TemplateContext)
+}
+
+impl TemplateValue {
+ fn render(&self) -> String {
+ match self {
+ TemplateValue::String(string) => string.to_string(),
+ TemplateValue::Unsigned(number) => format!("{}", number),
+ TemplateValue::Bool(bool) => format!("{}", bool),
+ _ => "".to_string()
+ }
+ }
+}
+
+pub type TemplateContext = HashMap<String, TemplateValue>;
+
+struct TemplateContextGetter {}
+impl TemplateContextGetter {
+ fn get(context: &TemplateContext, path: &str) -> Option<TemplateValue> {
+ let path_parts: Vec<&str> = path.split('.').collect();
+ TemplateContextGetter::recursively_get_value(context, &path_parts)
+ }
+
+ fn recursively_get_value(context: &TemplateContext, path: &[&str]) -> Option<TemplateValue> {
+ match context.get(path[0]) {
+ Some(TemplateValue::Context(next)) if path.len() > 1 => TemplateContextGetter::recursively_get_value(next, &path[1..]),
+ Some(value) if path.len() == 1 => Some(value.clone()),
+ _ => None
+ }
+ }
+}
+
pub struct ParsedTemplate {
pub tokens: Vec<Token>
}
+impl ParsedTemplate {
+ pub fn render(&self, context: &TemplateContext) -> String {
+ ParsedTemplate::render_tokens(&self.tokens, context)
+ }
+
+ pub fn render_tokens(tokens: &Vec<Token>, context: &TemplateContext) -> String {
+ let mut rendered_template: String = String::new();
+ for token in tokens {
+ match token {
+ Token::Text(contents) => rendered_template.push_str(&contents),
+ Token::DisplayDirective { content } => {
+ match TemplateContextGetter::get(context, &content) {
+ Some(value) => rendered_template.push_str(&value.render()),
+ None => panic!("{} is not a valid key", content)
+ }
+ },
+ Token::ConditionalDirective { condition, children} => {
+ let mut negator = false;
+ let mut condition = condition.to_string();
+ if condition.starts_with('!') {
+ negator = true;
+ condition = condition[1..].to_string();
+ }
+ match TemplateContextGetter::get(context, &condition) {
+ Some(TemplateValue::Bool(value)) => {
+ if negator ^ value {
+ rendered_template.push_str(&ParsedTemplate::render_tokens(children, context))
+ }
+ },
+ _ => panic!("{} is not a boolean value", condition)
+ }
+ },
+ Token::IteratorDirective { collection, member_label, children } => {
+ match TemplateContextGetter::get(context, &collection) {
+ Some(TemplateValue::Collection(collection)) => {
+ for member in collection {
+ let mut child_context = context.clone();
+ child_context.insert(
+ member_label.to_string(),
+ TemplateValue::Context(member)
+ );
+ rendered_template.push_str(&ParsedTemplate::render_tokens(&children, &child_context))
+ }
+ },
+ _ => panic!("{} is not a collection", collection)
+ }
+ }
+ }
+ }
+ rendered_template
+ }
+}
+
pub fn parse(template: &str) -> ParsedTemplate {
let mut tokens = Vec::new();
tokenize(template, &mut tokens);