From f386e5c31b820eb2f92aa1128d2ec237612a8b13 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 17:12:15 -0400 Subject: [PATCH 01/31] Adding trait to cast to Any. --- src/renderer/context_element.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index d49c562..f00f56c 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -1,6 +1,7 @@ use crate::parser::Filter; use crate::renderer::errors::RenderError; use crate::renderer::errors::WalkError; +use std::any::Any; use std::fmt::Debug; pub trait ContextElement: Debug + Walkable + Renderable + Loopable {} @@ -26,6 +27,10 @@ pub trait Loopable { fn get_loop_elements(&self) -> Vec<&dyn ContextElement>; } +pub trait CompareContextElement { + fn to_any(&self) -> &dyn Any; +} + // impl PartialEq for dyn ContextElement { // fn eq(&self, other: &dyn ContextElement) -> bool { // todo!() From 876bced18846b836921144b7ba7462d7c4acd5a7 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 18:10:17 -0400 Subject: [PATCH 02/31] Converting RValues. --- src/renderer/parameters_context.rs | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index c2aa6d0..289afba 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -9,6 +9,41 @@ use crate::renderer::WalkError; use crate::renderer::Walkable; use std::collections::HashMap; +/// Copy the data from an RValue to an Owned struct +/// +/// In order to get comparisons to work for our `ContextElement` trait +/// objects, we need to be able to use `std::any::Any`. Unfortunately, +/// `Any` requires that the structs do not have a lifetime (so they +/// will have a `'static` lifetime. This means that we cannot have a +/// `<'a>` appended to the struct type, so the struct cannot contain +/// any borrows. Rather than impose the copy cost in the parser, we +/// are imposing the cost of copying the data in the renderer because +/// the parser has no reason to not be able to reference data from the +/// input string. +pub enum OwnedRValue { + RVPath(OwnedPath), + RVString(String), +} + +pub struct OwnedPath { + pub keys: Vec, +} + +impl From> for OwnedRValue { + fn from(original: RValue<'_>) -> Self { + match original { + RValue::RVString(text) => OwnedRValue::RVString(text.to_owned()), + RValue::RVPath(path) => OwnedRValue::RVPath(OwnedPath { + keys: path.keys.iter().map(|k| k.to_string()).collect(), + }), + } + } +} + +pub struct NewParametersContext { + params: HashMap, +} + #[derive(Clone, Debug)] pub struct ParametersContext<'a> { params: HashMap<&'a str, &'a RValue<'a>>, From 9573480973ae71ed6db51e445c4f5eb03eeacbf3 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 18:19:06 -0400 Subject: [PATCH 03/31] converting the parameters --- src/renderer/parameters_context.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 289afba..60b98d3 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -29,8 +29,8 @@ pub struct OwnedPath { pub keys: Vec, } -impl From> for OwnedRValue { - fn from(original: RValue<'_>) -> Self { +impl From<&RValue<'_>> for OwnedRValue { + fn from(original: &RValue<'_>) -> Self { match original { RValue::RVString(text) => OwnedRValue::RVString(text.to_owned()), RValue::RVPath(path) => OwnedRValue::RVPath(OwnedPath { @@ -42,6 +42,24 @@ impl From> for OwnedRValue { pub struct NewParametersContext { params: HashMap, + breadcrumbs: Vec>, +} + +impl NewParametersContext { + pub fn new( + breadcrumbs: &Vec<&dyn ContextElement>, + params: &Vec, + ) -> NewParametersContext { + let owned_params: HashMap = params + .iter() + .map(|kvpair| (kvpair.key.to_string(), OwnedRValue::from(&kvpair.value))) + .collect(); + + NewParametersContext { + params: owned_params, + breadcrumbs: Vec::new(), + } + } } #[derive(Clone, Debug)] From b9cfa56c2fa7a99b4fd70c477ec479dfadcfd356 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 18:35:24 -0400 Subject: [PATCH 04/31] May have to use unsafe code. --- src/renderer/parameters_context.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 60b98d3..2453d4a 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -55,6 +55,13 @@ impl NewParametersContext { .map(|kvpair| (kvpair.key.to_string(), OwnedRValue::from(&kvpair.value))) .collect(); + let x: String = "foo".to_owned(); + let y: &dyn ContextElement = &x as _; + let owned_y: Box = Box::new(*y.clone()); + + // let owned_breadcrumbs: Vec> = + // breadcrumbs.iter().map(|ce| Box::new(*ce.clone())).collect(); + NewParametersContext { params: owned_params, breadcrumbs: Vec::new(), From 6fb329388f55bae9dd174c1fc57dc19544ffbe06 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 18:45:54 -0400 Subject: [PATCH 05/31] Not having much luck. --- src/renderer/parameters_context.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 2453d4a..cf8feb3 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -57,7 +57,11 @@ impl NewParametersContext { let x: String = "foo".to_owned(); let y: &dyn ContextElement = &x as _; - let owned_y: Box = Box::new(*y.clone()); + // let owned_y: Box = Box::new(*y.clone()); + // unsafe { + // let ce = &mut *y.clone() as *mut dyn ContextElement; + // Box::from_raw(ce); + // } // let owned_breadcrumbs: Vec> = // breadcrumbs.iter().map(|ce| Box::new(*ce.clone())).collect(); From 5c79b436a0b8716861b27a02c5e116f7ac5d29b8 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 19:01:02 -0400 Subject: [PATCH 06/31] Commenting out the parameterscontext type. --- src/renderer/context_element.rs | 15 ++++- src/renderer/parameters_context.rs | 94 +++++++++++++++--------------- src/renderer/renderer.rs | 6 +- 3 files changed, 65 insertions(+), 50 deletions(-) diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index f00f56c..4440e31 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -4,7 +4,10 @@ use crate::renderer::errors::WalkError; use std::any::Any; use std::fmt::Debug; -pub trait ContextElement: Debug + Walkable + Renderable + Loopable {} +pub trait ContextElement: + Debug + Walkable + Renderable + Loopable + IntoBoxedContextElement +{ +} pub trait Walkable { fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError>; @@ -31,6 +34,16 @@ pub trait CompareContextElement { fn to_any(&self) -> &dyn Any; } +pub trait IntoBoxedContextElement { + fn to_box(self) -> Box; +} + +impl IntoBoxedContextElement for C { + fn to_box(self) -> Box { + Box::new(self) + } +} + // impl PartialEq for dyn ContextElement { // fn eq(&self, other: &dyn ContextElement) -> bool { // todo!() diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index cf8feb3..f69314d 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -1,6 +1,7 @@ use crate::parser::KVPair; use crate::parser::{Filter, RValue}; use crate::renderer::context_element::ContextElement; +use crate::renderer::context_element::IntoBoxedContextElement; use crate::renderer::walking::walk_path; use crate::renderer::Loopable; use crate::renderer::RenderError; @@ -57,6 +58,7 @@ impl NewParametersContext { let x: String = "foo".to_owned(); let y: &dyn ContextElement = &x as _; + let z: Box = y.clone().to_box(); // let owned_y: Box = Box::new(*y.clone()); // unsafe { // let ce = &mut *y.clone() as *mut dyn ContextElement; @@ -73,57 +75,57 @@ impl NewParametersContext { } } -#[derive(Clone, Debug)] -pub struct ParametersContext<'a> { - params: HashMap<&'a str, &'a RValue<'a>>, - breadcrumbs: &'a Vec<&'a dyn ContextElement>, -} +// #[derive(Clone, Debug)] +// pub struct ParametersContext<'a> { +// params: HashMap<&'a str, &'a RValue<'a>>, +// breadcrumbs: &'a Vec<&'a dyn ContextElement>, +// } -impl<'a> ParametersContext<'a> { - pub fn new( - breadcrumbs: &'a Vec<&'a dyn ContextElement>, - params: &'a Vec>, - ) -> ParametersContext<'a> { - let param_map = params - .iter() - .map(|pair: &KVPair<'a>| (pair.key, &pair.value)) - .collect(); - ParametersContext { - params: param_map, - breadcrumbs: breadcrumbs, - } - } -} +// impl<'a> ParametersContext<'a> { +// pub fn new( +// breadcrumbs: &'a Vec<&'a dyn ContextElement>, +// params: &'a Vec>, +// ) -> ParametersContext<'a> { +// let param_map = params +// .iter() +// .map(|pair: &KVPair<'a>| (pair.key, &pair.value)) +// .collect(); +// ParametersContext { +// params: param_map, +// breadcrumbs: breadcrumbs, +// } +// } +// } -impl<'a> ContextElement for ParametersContext<'a> {} +// impl<'a> ContextElement for ParametersContext<'a> {} -impl<'a> Renderable for ParametersContext<'a> { - fn render(&self, _filters: &Vec) -> Result { - // TODO: Would this even ever be called? Won't matter, but I'd - // like to know. Since it is injected 1 above the current - // context, we wouldn't be able to access it with `{.}`. - Ok("[object Object]".to_owned()) - } -} +// impl<'a> Renderable for ParametersContext<'a> { +// fn render(&self, _filters: &Vec) -> Result { +// // TODO: Would this even ever be called? Won't matter, but I'd +// // like to know. Since it is injected 1 above the current +// // context, we wouldn't be able to access it with `{.}`. +// Ok("[object Object]".to_owned()) +// } +// } -impl<'a> Loopable for ParametersContext<'a> { - fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { - // TODO: Would this even ever be called? Won't matter, but I'd - // like to know. Since it is injected 1 above the current - // context, we wouldn't be able to access it with `{.}`. - vec![self] - } -} +// impl<'a> Loopable for ParametersContext<'a> { +// fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { +// // TODO: Would this even ever be called? Won't matter, but I'd +// // like to know. Since it is injected 1 above the current +// // context, we wouldn't be able to access it with `{.}`. +// vec![self] +// } +// } -impl<'a> Walkable for ParametersContext<'a> { - fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { - let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?; - match rval { - RValue::RVPath(path) => walk_path(self.breadcrumbs, &path.keys), - RValue::RVString(text) => Ok(text), - } - } -} +// impl<'a> Walkable for ParametersContext<'a> { +// fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { +// let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?; +// match rval { +// RValue::RVPath(path) => walk_path(self.breadcrumbs, &path.keys), +// RValue::RVString(text) => Ok(text), +// } +// } +// } impl ContextElement for String {} diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 4e3d9f8..76e6317 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -12,7 +12,7 @@ use crate::renderer::errors::RenderError; use crate::renderer::errors::WalkError; use crate::renderer::inline_partial_tree::extract_inline_partials; use crate::renderer::inline_partial_tree::InlinePartialTreeElement; -use crate::renderer::parameters_context::ParametersContext; +// use crate::renderer::parameters_context::ParametersContext; use crate::renderer::walking::walk_path; use std::collections::HashMap; @@ -194,9 +194,9 @@ impl<'a> DustRenderer<'a> { self.render_template(&partial.name, breadcrumbs, Some(blocks))?; return Ok(rendered_content); } else { - let injected_context = ParametersContext::new(breadcrumbs, &partial.params); + // let injected_context = ParametersContext::new(breadcrumbs, &partial.params); let mut new_breadcrumbs = breadcrumbs.clone(); - new_breadcrumbs.insert(new_breadcrumbs.len() - 1, &injected_context); + // new_breadcrumbs.insert(new_breadcrumbs.len() - 1, &injected_context); let rendered_content = self.render_template(&partial.name, &new_breadcrumbs, Some(blocks))?; return Ok(rendered_content); From c96b2257d7b10540328c6ca3ba8552b001610608 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 19:07:41 -0400 Subject: [PATCH 07/31] Compiling. Need to see if I can do a generic implemented of IntoBoxedContextElement for all objects implementing Copy, and I need to implement the compare code to make sure this all works before I start integrating this more. --- src/bin.rs | 7 +++++++ src/renderer/context_element.rs | 8 +------- src/renderer/mod.rs | 1 + src/renderer/parameters_context.rs | 22 +++++++++------------- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/bin.rs b/src/bin.rs index 12e1bd3..1f8fcd7 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -1,5 +1,6 @@ extern crate nom; +use crate::renderer::IntoBoxedContextElement; use parser::Filter; use renderer::compile_template; use renderer::CompiledTemplate; @@ -137,3 +138,9 @@ impl Loopable for serde_json::Value { } } } + +impl IntoBoxedContextElement for serde_json::Value { + fn clone_to_box(&self) -> Box { + Box::new(self.clone()) + } +} diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index 4440e31..7c53e8f 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -35,13 +35,7 @@ pub trait CompareContextElement { } pub trait IntoBoxedContextElement { - fn to_box(self) -> Box; -} - -impl IntoBoxedContextElement for C { - fn to_box(self) -> Box { - Box::new(self) - } + fn clone_to_box(&self) -> Box; } // impl PartialEq for dyn ContextElement { diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 70f423b..946f770 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -8,6 +8,7 @@ mod renderer; mod walking; pub use context_element::ContextElement; +pub use context_element::IntoBoxedContextElement; pub use context_element::Loopable; pub use context_element::Renderable; pub use context_element::Walkable; diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index f69314d..5f4c6a8 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -55,22 +55,12 @@ impl NewParametersContext { .iter() .map(|kvpair| (kvpair.key.to_string(), OwnedRValue::from(&kvpair.value))) .collect(); - - let x: String = "foo".to_owned(); - let y: &dyn ContextElement = &x as _; - let z: Box = y.clone().to_box(); - // let owned_y: Box = Box::new(*y.clone()); - // unsafe { - // let ce = &mut *y.clone() as *mut dyn ContextElement; - // Box::from_raw(ce); - // } - - // let owned_breadcrumbs: Vec> = - // breadcrumbs.iter().map(|ce| Box::new(*ce.clone())).collect(); + let owned_breadcrumbs: Vec> = + breadcrumbs.iter().map(|ce| ce.clone_to_box()).collect(); NewParametersContext { params: owned_params, - breadcrumbs: Vec::new(), + breadcrumbs: owned_breadcrumbs, } } } @@ -150,3 +140,9 @@ impl Walkable for String { Err(WalkError::CantWalk) } } + +impl IntoBoxedContextElement for String { + fn clone_to_box(&self) -> Box { + Box::new(self.clone()) + } +} From 8fd2a9cf39adbfe7a643c51b150f02ab047d90de Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 19:16:55 -0400 Subject: [PATCH 08/31] tentatively seems to be working. --- src/bin.rs | 15 +++++++++++++++ src/renderer/context_element.rs | 4 +++- src/renderer/mod.rs | 1 + src/renderer/parameters_context.rs | 15 +++++++++++++++ src/renderer/renderer.rs | 3 +++ 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/bin.rs b/src/bin.rs index 1f8fcd7..d6f9f64 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -1,5 +1,6 @@ extern crate nom; +use crate::renderer::CompareContextElement; use crate::renderer::IntoBoxedContextElement; use parser::Filter; use renderer::compile_template; @@ -11,6 +12,7 @@ use renderer::RenderError; use renderer::Renderable; use renderer::WalkError; use renderer::Walkable; +use std::any::Any; use std::env; use std::fs; use std::io::{self, Read}; @@ -144,3 +146,16 @@ impl IntoBoxedContextElement for serde_json::Value { Box::new(self.clone()) } } + +impl CompareContextElement for serde_json::Value { + fn to_any(&self) -> &dyn Any { + self + } + + fn equals(&self, other: &dyn ContextElement) -> bool { + other + .to_any() + .downcast_ref::() + .map_or(false, |a| self == a) + } +} diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index 7c53e8f..c201d4e 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -5,7 +5,7 @@ use std::any::Any; use std::fmt::Debug; pub trait ContextElement: - Debug + Walkable + Renderable + Loopable + IntoBoxedContextElement + Debug + Walkable + Renderable + Loopable + IntoBoxedContextElement + CompareContextElement { } @@ -32,6 +32,8 @@ pub trait Loopable { pub trait CompareContextElement { fn to_any(&self) -> &dyn Any; + + fn equals(&self, other: &dyn ContextElement) -> bool; } pub trait IntoBoxedContextElement { diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 946f770..82a97e6 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -7,6 +7,7 @@ mod parameters_context; mod renderer; mod walking; +pub use context_element::CompareContextElement; pub use context_element::ContextElement; pub use context_element::IntoBoxedContextElement; pub use context_element::Loopable; diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 5f4c6a8..6cdf05b 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -1,5 +1,6 @@ use crate::parser::KVPair; use crate::parser::{Filter, RValue}; +use crate::renderer::context_element::CompareContextElement; use crate::renderer::context_element::ContextElement; use crate::renderer::context_element::IntoBoxedContextElement; use crate::renderer::walking::walk_path; @@ -8,6 +9,7 @@ use crate::renderer::RenderError; use crate::renderer::Renderable; use crate::renderer::WalkError; use crate::renderer::Walkable; +use std::any::Any; use std::collections::HashMap; /// Copy the data from an RValue to an Owned struct @@ -146,3 +148,16 @@ impl IntoBoxedContextElement for String { Box::new(self.clone()) } } + +impl CompareContextElement for String { + fn to_any(&self) -> &dyn Any { + self + } + + fn equals(&self, other: &dyn ContextElement) -> bool { + other + .to_any() + .downcast_ref::() + .map_or(false, |a| self == a) + } +} diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 76e6317..4f39135 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -245,6 +245,9 @@ impl<'a> DustRenderer<'a> { RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), }, }; + if left_side.unwrap().equals(right_side.unwrap()) { + panic!("testing"); + } // let x = WalkError::CantWalk; // let y = WalkError::CantWalk; // if x == y { From e986a1ba7acc299b2f758be73b763974aab2af24 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 20:58:47 -0400 Subject: [PATCH 09/31] PartialEq compiling with double lifetimes. --- src/renderer/context_element.rs | 10 +++++----- src/renderer/renderer.rs | 5 ++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index c201d4e..823534a 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -40,8 +40,8 @@ pub trait IntoBoxedContextElement { fn clone_to_box(&self) -> Box; } -// impl PartialEq for dyn ContextElement { -// fn eq(&self, other: &dyn ContextElement) -> bool { -// todo!() -// } -// } +impl<'a, 'b> PartialEq<&'b dyn ContextElement> for &'a dyn ContextElement { + fn eq(&self, other: &&'b dyn ContextElement) -> bool { + false + } +} diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 4f39135..835cf2d 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -245,7 +245,10 @@ impl<'a> DustRenderer<'a> { RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), }, }; - if left_side.unwrap().equals(right_side.unwrap()) { + // if left_side.unwrap().equals(right_side.unwrap()) { + // panic!("testing"); + // } + if left_side.unwrap() == right_side.unwrap() { panic!("testing"); } // let x = WalkError::CantWalk; From 7f896855376aef9a5fcdcd6b41d9599529b64ed6 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 21:00:06 -0400 Subject: [PATCH 10/31] PartialEq implemented too. --- src/renderer/context_element.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index 823534a..6279a58 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -42,6 +42,6 @@ pub trait IntoBoxedContextElement { impl<'a, 'b> PartialEq<&'b dyn ContextElement> for &'a dyn ContextElement { fn eq(&self, other: &&'b dyn ContextElement) -> bool { - false + self.equals(*other) } } From ba79369b5aab4a7b970745ccee65fa0e2bcac435 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 21:00:52 -0400 Subject: [PATCH 11/31] PartialEq works with results too. --- src/renderer/renderer.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 835cf2d..4b96703 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -248,7 +248,10 @@ impl<'a> DustRenderer<'a> { // if left_side.unwrap().equals(right_side.unwrap()) { // panic!("testing"); // } - if left_side.unwrap() == right_side.unwrap() { + // if left_side.unwrap() == right_side.unwrap() { + // panic!("testing"); + // } + if left_side == right_side { panic!("testing"); } // let x = WalkError::CantWalk; From 256051220d3a0b8ea2b0ac1389d7fe3a043afd46 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 21:07:31 -0400 Subject: [PATCH 12/31] Generic implementation of CloneIntoBoxedContextElement. --- src/bin.rs | 8 +------- src/renderer/context_element.rs | 10 ++++++++-- src/renderer/mod.rs | 2 +- src/renderer/parameters_context.rs | 8 +------- src/renderer/renderer.rs | 14 -------------- 5 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/bin.rs b/src/bin.rs index d6f9f64..3f669d4 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -1,7 +1,7 @@ extern crate nom; +use crate::renderer::CloneIntoBoxedContextElement; use crate::renderer::CompareContextElement; -use crate::renderer::IntoBoxedContextElement; use parser::Filter; use renderer::compile_template; use renderer::CompiledTemplate; @@ -141,12 +141,6 @@ impl Loopable for serde_json::Value { } } -impl IntoBoxedContextElement for serde_json::Value { - fn clone_to_box(&self) -> Box { - Box::new(self.clone()) - } -} - impl CompareContextElement for serde_json::Value { fn to_any(&self) -> &dyn Any { self diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index 6279a58..a9ab8bd 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -5,7 +5,7 @@ use std::any::Any; use std::fmt::Debug; pub trait ContextElement: - Debug + Walkable + Renderable + Loopable + IntoBoxedContextElement + CompareContextElement + Debug + Walkable + Renderable + Loopable + CloneIntoBoxedContextElement + CompareContextElement { } @@ -36,10 +36,16 @@ pub trait CompareContextElement { fn equals(&self, other: &dyn ContextElement) -> bool; } -pub trait IntoBoxedContextElement { +pub trait CloneIntoBoxedContextElement { fn clone_to_box(&self) -> Box; } +impl CloneIntoBoxedContextElement for C { + fn clone_to_box(&self) -> Box { + Box::new(self.clone()) + } +} + impl<'a, 'b> PartialEq<&'b dyn ContextElement> for &'a dyn ContextElement { fn eq(&self, other: &&'b dyn ContextElement) -> bool { self.equals(*other) diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 82a97e6..45dbdfd 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -7,9 +7,9 @@ mod parameters_context; mod renderer; mod walking; +pub use context_element::CloneIntoBoxedContextElement; pub use context_element::CompareContextElement; pub use context_element::ContextElement; -pub use context_element::IntoBoxedContextElement; pub use context_element::Loopable; pub use context_element::Renderable; pub use context_element::Walkable; diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 6cdf05b..ca421bc 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -1,8 +1,8 @@ use crate::parser::KVPair; use crate::parser::{Filter, RValue}; +use crate::renderer::context_element::CloneIntoBoxedContextElement; use crate::renderer::context_element::CompareContextElement; use crate::renderer::context_element::ContextElement; -use crate::renderer::context_element::IntoBoxedContextElement; use crate::renderer::walking::walk_path; use crate::renderer::Loopable; use crate::renderer::RenderError; @@ -143,12 +143,6 @@ impl Walkable for String { } } -impl IntoBoxedContextElement for String { - fn clone_to_box(&self) -> Box { - Box::new(self.clone()) - } -} - impl CompareContextElement for String { fn to_any(&self) -> &dyn Any { self diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 4b96703..a5309f3 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -245,23 +245,9 @@ impl<'a> DustRenderer<'a> { RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), }, }; - // if left_side.unwrap().equals(right_side.unwrap()) { - // panic!("testing"); - // } - // if left_side.unwrap() == right_side.unwrap() { - // panic!("testing"); - // } if left_side == right_side { panic!("testing"); } - // let x = WalkError::CantWalk; - // let y = WalkError::CantWalk; - // if x == y { - // panic!("placeholder"); - // } - // if left_side.unwrap() == right_side.unwrap() { - // panic!("placeholder"); - // } } _ => (), // TODO: Implement the rest } From 32abe41e1a3775bff71a620ae02367aff8b30499 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 21:10:48 -0400 Subject: [PATCH 13/31] Generic implementation of CompareContextElement. --- src/bin.rs | 13 ------------- src/renderer/context_element.rs | 13 +++++++++++++ src/renderer/parameters_context.rs | 13 ------------- 3 files changed, 13 insertions(+), 26 deletions(-) diff --git a/src/bin.rs b/src/bin.rs index 3f669d4..661670d 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -140,16 +140,3 @@ impl Loopable for serde_json::Value { } } } - -impl CompareContextElement for serde_json::Value { - fn to_any(&self) -> &dyn Any { - self - } - - fn equals(&self, other: &dyn ContextElement) -> bool { - other - .to_any() - .downcast_ref::() - .map_or(false, |a| self == a) - } -} diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index a9ab8bd..29ca430 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -46,6 +46,19 @@ impl CloneIntoBoxedContextElement for C { } } +impl CompareContextElement for C { + fn to_any(&self) -> &dyn Any { + self + } + + fn equals(&self, other: &dyn ContextElement) -> bool { + other + .to_any() + .downcast_ref::() + .map_or(false, |a| self == a) + } +} + impl<'a, 'b> PartialEq<&'b dyn ContextElement> for &'a dyn ContextElement { fn eq(&self, other: &&'b dyn ContextElement) -> bool { self.equals(*other) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index ca421bc..e9dd02c 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -142,16 +142,3 @@ impl Walkable for String { Err(WalkError::CantWalk) } } - -impl CompareContextElement for String { - fn to_any(&self) -> &dyn Any { - self - } - - fn equals(&self, other: &dyn ContextElement) -> bool { - other - .to_any() - .downcast_ref::() - .map_or(false, |a| self == a) - } -} From 137e7887a03e4571ced1371eb1a0a497b1248075 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 21:14:51 -0400 Subject: [PATCH 14/31] Finish implementing DTHelperEquals. --- src/renderer/renderer.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index a5309f3..a0b8a73 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -246,7 +246,21 @@ impl<'a> DustRenderer<'a> { }, }; if left_side == right_side { - panic!("testing"); + match ¶meterized_block.contents { + None => return Ok("".to_owned()), + Some(body) => { + let rendered_content = self.render_body(body, breadcrumbs, blocks)?; + return Ok(rendered_content); + } + } + } else { + match ¶meterized_block.else_contents { + None => return Ok("".to_owned()), + Some(body) => { + let rendered_content = self.render_body(body, breadcrumbs, blocks)?; + return Ok(rendered_content); + } + } } } _ => (), // TODO: Implement the rest From 4e274b9ea53067a75953fd2ade933277e9059273 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 21:28:47 -0400 Subject: [PATCH 15/31] Running into the walking issue again. --- src/renderer/parameters_context.rs | 51 ++++++++++++++++++++++++++++++ src/renderer/renderer.rs | 6 ++-- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index e9dd02c..1a5af63 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -23,11 +23,13 @@ use std::collections::HashMap; /// are imposing the cost of copying the data in the renderer because /// the parser has no reason to not be able to reference data from the /// input string. +#[derive(Clone, Debug, PartialEq)] pub enum OwnedRValue { RVPath(OwnedPath), RVString(String), } +#[derive(Clone, Debug, PartialEq)] pub struct OwnedPath { pub keys: Vec, } @@ -43,6 +45,7 @@ impl From<&RValue<'_>> for OwnedRValue { } } +#[derive(Debug)] pub struct NewParametersContext { params: HashMap, breadcrumbs: Vec>, @@ -67,6 +70,54 @@ impl NewParametersContext { } } +impl ContextElement for NewParametersContext {} + +impl Renderable for NewParametersContext { + fn render(&self, _filters: &Vec) -> Result { + // TODO: Would this even ever be called? Won't matter, but I'd + // like to know. Since it is injected 1 above the current + // context, we wouldn't be able to access it with `{.}`. + Ok("[object Object]".to_owned()) + } +} + +impl Loopable for NewParametersContext { + fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { + // TODO: Would this even ever be called? Won't matter, but I'd + // like to know. Since it is injected 1 above the current + // context, we wouldn't be able to access it with `{.}`. + vec![self] + } +} + +impl Walkable for NewParametersContext { + fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { + let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?; + match rval { + OwnedRValue::RVPath(path) => walk_path(self.breadcrumbs, &path.keys), + OwnedRValue::RVString(text) => Ok(text), + } + } +} + +impl Clone for NewParametersContext { + fn clone(&self) -> Self { + // TODO: What is this doing, really? + *self + } +} + +impl CompareContextElement for NewParametersContext { + fn to_any(&self) -> &dyn Any { + self + } + + fn equals(&self, other: &dyn ContextElement) -> bool { + // TODO: Does this ever happen? perhaps I should have a panic here. + false + } +} + // #[derive(Clone, Debug)] // pub struct ParametersContext<'a> { // params: HashMap<&'a str, &'a RValue<'a>>, diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index a0b8a73..8d66251 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -12,7 +12,7 @@ use crate::renderer::errors::RenderError; use crate::renderer::errors::WalkError; use crate::renderer::inline_partial_tree::extract_inline_partials; use crate::renderer::inline_partial_tree::InlinePartialTreeElement; -// use crate::renderer::parameters_context::ParametersContext; +use crate::renderer::parameters_context::NewParametersContext; use crate::renderer::walking::walk_path; use std::collections::HashMap; @@ -194,9 +194,9 @@ impl<'a> DustRenderer<'a> { self.render_template(&partial.name, breadcrumbs, Some(blocks))?; return Ok(rendered_content); } else { - // let injected_context = ParametersContext::new(breadcrumbs, &partial.params); + let injected_context = NewParametersContext::new(breadcrumbs, &partial.params); let mut new_breadcrumbs = breadcrumbs.clone(); - // new_breadcrumbs.insert(new_breadcrumbs.len() - 1, &injected_context); + new_breadcrumbs.insert(new_breadcrumbs.len() - 1, &injected_context); let rendered_content = self.render_template(&partial.name, &new_breadcrumbs, Some(blocks))?; return Ok(rendered_content); From dade738f55bf2c6d142f060ad7f4b25e86d08e36 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 21:34:18 -0400 Subject: [PATCH 16/31] The structure is all there, just need to implement owned_walk_path and clone on NewParametersContext. --- src/renderer/parameters_context.rs | 10 +++++++--- src/renderer/walking.rs | 8 ++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 1a5af63..f6045b7 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -3,6 +3,7 @@ use crate::parser::{Filter, RValue}; use crate::renderer::context_element::CloneIntoBoxedContextElement; use crate::renderer::context_element::CompareContextElement; use crate::renderer::context_element::ContextElement; +use crate::renderer::walking::owned_walk_path; use crate::renderer::walking::walk_path; use crate::renderer::Loopable; use crate::renderer::RenderError; @@ -94,7 +95,7 @@ impl Walkable for NewParametersContext { fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?; match rval { - OwnedRValue::RVPath(path) => walk_path(self.breadcrumbs, &path.keys), + OwnedRValue::RVPath(path) => owned_walk_path(&self.breadcrumbs, &path.keys), OwnedRValue::RVString(text) => Ok(text), } } @@ -102,8 +103,11 @@ impl Walkable for NewParametersContext { impl Clone for NewParametersContext { fn clone(&self) -> Self { - // TODO: What is this doing, really? - *self + // TODO: Implement clone + NewParametersContext { + params: HashMap::new(), + breadcrumbs: Vec::new(), + } } } diff --git a/src/renderer/walking.rs b/src/renderer/walking.rs index feadce3..942db87 100644 --- a/src/renderer/walking.rs +++ b/src/renderer/walking.rs @@ -51,3 +51,11 @@ pub fn walk_path<'a>( } Err(WalkError::CantWalk) } + +pub fn owned_walk_path<'a>( + breadcrumbs: &Vec>, + path: &Vec, +) -> Result<&'a dyn ContextElement, WalkError> { + // TODO: Implement owned_walk_path + Err(WalkError::CantWalk) +} From 798d84828ec1506648ad766e4a179e79580109e7 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 21:38:37 -0400 Subject: [PATCH 17/31] Implemented owned_walk_path. --- src/renderer/walking.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/renderer/walking.rs b/src/renderer/walking.rs index 942db87..cc91047 100644 --- a/src/renderer/walking.rs +++ b/src/renderer/walking.rs @@ -53,9 +53,21 @@ pub fn walk_path<'a>( } pub fn owned_walk_path<'a>( - breadcrumbs: &Vec>, + breadcrumbs: &'a Vec>, path: &Vec, ) -> Result<&'a dyn ContextElement, WalkError> { - // TODO: Implement owned_walk_path + let path_reference: Vec<&str> = path.iter().map(|p| &p[..]).collect(); + for context in breadcrumbs.iter().rev() { + match walk_path_from_single_level(context.as_ref(), &path_reference) { + // If no walking was done at all, keep looping + WalkResult::NoWalk => {} + // If we partially walked then stop trying to find + // anything + WalkResult::PartialWalk => { + return Err(WalkError::CantWalk); + } + WalkResult::FullyWalked(new_context) => return Ok(new_context), + } + } Err(WalkError::CantWalk) } From d5e0c93205c96dee7652f9afd9a4a9c8e25e7709 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 21:45:06 -0400 Subject: [PATCH 18/31] Comparisons between json strings vs rvalue literals is not working as I had hoped. --- src/renderer/renderer.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 8d66251..9f9b49b 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -245,6 +245,7 @@ impl<'a> DustRenderer<'a> { RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), }, }; + println!("Comparing {:?} to {:?}", left_side, right_side); if left_side == right_side { match ¶meterized_block.contents { None => return Ok("".to_owned()), From 9baa669dea8e603b9dd6c48fbb3a539127ce70bf Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 22:04:41 -0400 Subject: [PATCH 19/31] Separating out CastToAny. --- src/bin.rs | 6 ++++++ src/renderer/context_element.rs | 26 +++++++++++++++++--------- src/renderer/parameters_context.rs | 17 ++++++++++++++++- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/src/bin.rs b/src/bin.rs index 661670d..47c977b 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -140,3 +140,9 @@ impl Loopable for serde_json::Value { } } } + +impl CompareContextElement for serde_json::Value { + fn equals(&self, other: &dyn ContextElement) -> bool { + false + } +} diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index 29ca430..8701711 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -30,9 +30,11 @@ pub trait Loopable { fn get_loop_elements(&self) -> Vec<&dyn ContextElement>; } -pub trait CompareContextElement { +pub trait CastToAny { fn to_any(&self) -> &dyn Any; +} +pub trait CompareContextElement: CastToAny { fn equals(&self, other: &dyn ContextElement) -> bool; } @@ -46,19 +48,25 @@ impl CloneIntoBoxedContextElement for C { } } -impl CompareContextElement for C { +impl CastToAny for C { fn to_any(&self) -> &dyn Any { self } - - fn equals(&self, other: &dyn ContextElement) -> bool { - other - .to_any() - .downcast_ref::() - .map_or(false, |a| self == a) - } } +// impl CompareContextElement for C { +// fn to_any(&self) -> &dyn Any { +// self +// } + +// fn equals(&self, other: &dyn ContextElement) -> bool { +// other +// .to_any() +// .downcast_ref::() +// .map_or(false, |a| self == a) +// } +// } + impl<'a, 'b> PartialEq<&'b dyn ContextElement> for &'a dyn ContextElement { fn eq(&self, other: &&'b dyn ContextElement) -> bool { self.equals(*other) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index f6045b7..6d525ca 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -1,5 +1,6 @@ use crate::parser::KVPair; use crate::parser::{Filter, RValue}; +use crate::renderer::context_element::CastToAny; use crate::renderer::context_element::CloneIntoBoxedContextElement; use crate::renderer::context_element::CompareContextElement; use crate::renderer::context_element::ContextElement; @@ -111,11 +112,13 @@ impl Clone for NewParametersContext { } } -impl CompareContextElement for NewParametersContext { +impl CastToAny for NewParametersContext { fn to_any(&self) -> &dyn Any { self } +} +impl CompareContextElement for NewParametersContext { fn equals(&self, other: &dyn ContextElement) -> bool { // TODO: Does this ever happen? perhaps I should have a panic here. false @@ -197,3 +200,15 @@ impl Walkable for String { Err(WalkError::CantWalk) } } + +impl CompareContextElement for String { + fn equals(&self, other: &dyn ContextElement) -> bool { + // If its a String then compare them directly, otherwise defer + // to the other type's implementation of CompareContextElement + // since the end user could add any type. + match other.to_any().downcast_ref::() { + None => other.equals(self), + Some(other_string) => self == other_string, + } + } +} From 2fb7ca9db730d4c4b41edebf022ef5e844c330b4 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 22:05:48 -0400 Subject: [PATCH 20/31] Making CastToAny more generic. --- src/renderer/context_element.rs | 2 +- src/renderer/parameters_context.rs | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index 8701711..0b1c304 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -48,7 +48,7 @@ impl CloneIntoBoxedContextElement for C { } } -impl CastToAny for C { +impl CastToAny for C { fn to_any(&self) -> &dyn Any { self } diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 6d525ca..af08de0 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -112,12 +112,6 @@ impl Clone for NewParametersContext { } } -impl CastToAny for NewParametersContext { - fn to_any(&self) -> &dyn Any { - self - } -} - impl CompareContextElement for NewParametersContext { fn equals(&self, other: &dyn ContextElement) -> bool { // TODO: Does this ever happen? perhaps I should have a panic here. From 6261f7881cb477e7a3e6cfe9c7d985d95754cad7 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 22:14:07 -0400 Subject: [PATCH 21/31] Manual equals is working! --- src/bin.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/bin.rs b/src/bin.rs index 47c977b..9c17df6 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -143,6 +143,26 @@ impl Loopable for serde_json::Value { impl CompareContextElement for serde_json::Value { fn equals(&self, other: &dyn ContextElement) -> bool { - false + match self { + serde_json::Value::Null => false, + serde_json::Value::Bool(boolean) => false, + serde_json::Value::Number(_num) => false, + serde_json::Value::String(string_value) => { + // Handle json string + match other.to_any().downcast_ref::() { + None => (), + Some(other_json_value) => return self == other_json_value, + } + // Handle rust string (for string literals) + match other.to_any().downcast_ref::() { + None => (), + Some(other_string) => return string_value == other_string, + } + // Otherwise we know of no other string types + false + } + serde_json::Value::Array(array_value) => false, + serde_json::Value::Object(_obj) => false, + } } } From 75ba35a42277ecfb4f3741df927f841ceded60a3 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 22:20:39 -0400 Subject: [PATCH 22/31] Cleaning up. --- src/renderer/context_element.rs | 13 -------- src/renderer/parameters_context.rs | 52 ------------------------------ 2 files changed, 65 deletions(-) diff --git a/src/renderer/context_element.rs b/src/renderer/context_element.rs index 0b1c304..3db0f27 100644 --- a/src/renderer/context_element.rs +++ b/src/renderer/context_element.rs @@ -54,19 +54,6 @@ impl CastToAny for C { } } -// impl CompareContextElement for C { -// fn to_any(&self) -> &dyn Any { -// self -// } - -// fn equals(&self, other: &dyn ContextElement) -> bool { -// other -// .to_any() -// .downcast_ref::() -// .map_or(false, |a| self == a) -// } -// } - impl<'a, 'b> PartialEq<&'b dyn ContextElement> for &'a dyn ContextElement { fn eq(&self, other: &&'b dyn ContextElement) -> bool { self.equals(*other) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index af08de0..b2081d6 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -119,58 +119,6 @@ impl CompareContextElement for NewParametersContext { } } -// #[derive(Clone, Debug)] -// pub struct ParametersContext<'a> { -// params: HashMap<&'a str, &'a RValue<'a>>, -// breadcrumbs: &'a Vec<&'a dyn ContextElement>, -// } - -// impl<'a> ParametersContext<'a> { -// pub fn new( -// breadcrumbs: &'a Vec<&'a dyn ContextElement>, -// params: &'a Vec>, -// ) -> ParametersContext<'a> { -// let param_map = params -// .iter() -// .map(|pair: &KVPair<'a>| (pair.key, &pair.value)) -// .collect(); -// ParametersContext { -// params: param_map, -// breadcrumbs: breadcrumbs, -// } -// } -// } - -// impl<'a> ContextElement for ParametersContext<'a> {} - -// impl<'a> Renderable for ParametersContext<'a> { -// fn render(&self, _filters: &Vec) -> Result { -// // TODO: Would this even ever be called? Won't matter, but I'd -// // like to know. Since it is injected 1 above the current -// // context, we wouldn't be able to access it with `{.}`. -// Ok("[object Object]".to_owned()) -// } -// } - -// impl<'a> Loopable for ParametersContext<'a> { -// fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { -// // TODO: Would this even ever be called? Won't matter, but I'd -// // like to know. Since it is injected 1 above the current -// // context, we wouldn't be able to access it with `{.}`. -// vec![self] -// } -// } - -// impl<'a> Walkable for ParametersContext<'a> { -// fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { -// let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?; -// match rval { -// RValue::RVPath(path) => walk_path(self.breadcrumbs, &path.keys), -// RValue::RVString(text) => Ok(text), -// } -// } -// } - impl ContextElement for String {} impl Renderable for String { From 6297fa01898bddf163887f5a2f492c41a5ba9bd1 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 22:21:18 -0400 Subject: [PATCH 23/31] Rename NewParametersContext to ParametersContext. --- src/renderer/parameters_context.rs | 22 +++++++++++----------- src/renderer/renderer.rs | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index b2081d6..3649044 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -48,16 +48,16 @@ impl From<&RValue<'_>> for OwnedRValue { } #[derive(Debug)] -pub struct NewParametersContext { +pub struct ParametersContext { params: HashMap, breadcrumbs: Vec>, } -impl NewParametersContext { +impl ParametersContext { pub fn new( breadcrumbs: &Vec<&dyn ContextElement>, params: &Vec, - ) -> NewParametersContext { + ) -> ParametersContext { let owned_params: HashMap = params .iter() .map(|kvpair| (kvpair.key.to_string(), OwnedRValue::from(&kvpair.value))) @@ -65,16 +65,16 @@ impl NewParametersContext { let owned_breadcrumbs: Vec> = breadcrumbs.iter().map(|ce| ce.clone_to_box()).collect(); - NewParametersContext { + ParametersContext { params: owned_params, breadcrumbs: owned_breadcrumbs, } } } -impl ContextElement for NewParametersContext {} +impl ContextElement for ParametersContext {} -impl Renderable for NewParametersContext { +impl Renderable for ParametersContext { fn render(&self, _filters: &Vec) -> Result { // TODO: Would this even ever be called? Won't matter, but I'd // like to know. Since it is injected 1 above the current @@ -83,7 +83,7 @@ impl Renderable for NewParametersContext { } } -impl Loopable for NewParametersContext { +impl Loopable for ParametersContext { fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { // TODO: Would this even ever be called? Won't matter, but I'd // like to know. Since it is injected 1 above the current @@ -92,7 +92,7 @@ impl Loopable for NewParametersContext { } } -impl Walkable for NewParametersContext { +impl Walkable for ParametersContext { fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?; match rval { @@ -102,17 +102,17 @@ impl Walkable for NewParametersContext { } } -impl Clone for NewParametersContext { +impl Clone for ParametersContext { fn clone(&self) -> Self { // TODO: Implement clone - NewParametersContext { + ParametersContext { params: HashMap::new(), breadcrumbs: Vec::new(), } } } -impl CompareContextElement for NewParametersContext { +impl CompareContextElement for ParametersContext { fn equals(&self, other: &dyn ContextElement) -> bool { // TODO: Does this ever happen? perhaps I should have a panic here. false diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 9f9b49b..c91587b 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -12,7 +12,7 @@ use crate::renderer::errors::RenderError; use crate::renderer::errors::WalkError; use crate::renderer::inline_partial_tree::extract_inline_partials; use crate::renderer::inline_partial_tree::InlinePartialTreeElement; -use crate::renderer::parameters_context::NewParametersContext; +use crate::renderer::parameters_context::ParametersContext; use crate::renderer::walking::walk_path; use std::collections::HashMap; @@ -194,7 +194,7 @@ impl<'a> DustRenderer<'a> { self.render_template(&partial.name, breadcrumbs, Some(blocks))?; return Ok(rendered_content); } else { - let injected_context = NewParametersContext::new(breadcrumbs, &partial.params); + let injected_context = ParametersContext::new(breadcrumbs, &partial.params); let mut new_breadcrumbs = breadcrumbs.clone(); new_breadcrumbs.insert(new_breadcrumbs.len() - 1, &injected_context); let rendered_content = From 46bb5558ac829de7d724a5d62b9e74174670f812 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 22:26:47 -0400 Subject: [PATCH 24/31] Going to a more generic equality comparison for json. --- src/bin.rs | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/src/bin.rs b/src/bin.rs index 9c17df6..5555061 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -143,26 +143,16 @@ impl Loopable for serde_json::Value { impl CompareContextElement for serde_json::Value { fn equals(&self, other: &dyn ContextElement) -> bool { - match self { - serde_json::Value::Null => false, - serde_json::Value::Bool(boolean) => false, - serde_json::Value::Number(_num) => false, - serde_json::Value::String(string_value) => { - // Handle json string - match other.to_any().downcast_ref::() { - None => (), - Some(other_json_value) => return self == other_json_value, - } - // Handle rust string (for string literals) - match other.to_any().downcast_ref::() { - None => (), - Some(other_string) => return string_value == other_string, - } - // Otherwise we know of no other string types - false - } - serde_json::Value::Array(array_value) => false, - serde_json::Value::Object(_obj) => false, + // Handle other serde_json::Value + match other.to_any().downcast_ref::() { + None => (), + Some(other_json_value) => return self == other_json_value, } + // Handle string literals + match other.to_any().downcast_ref::() { + None => (), + Some(other_string) => return self.as_str().map_or(false, |s| s == other_string), + } + false } } From 68639481f535566bfd125b6bb3a283d97f27e3b8 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 22:35:17 -0400 Subject: [PATCH 25/31] Implement a real clone for ParametersContext. --- src/renderer/parameters_context.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 3649044..a9b52f5 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -54,10 +54,7 @@ pub struct ParametersContext { } impl ParametersContext { - pub fn new( - breadcrumbs: &Vec<&dyn ContextElement>, - params: &Vec, - ) -> ParametersContext { + pub fn new(breadcrumbs: &Vec<&dyn ContextElement>, params: &Vec) -> ParametersContext { let owned_params: HashMap = params .iter() .map(|kvpair| (kvpair.key.to_string(), OwnedRValue::from(&kvpair.value))) @@ -104,10 +101,19 @@ impl Walkable for ParametersContext { impl Clone for ParametersContext { fn clone(&self) -> Self { - // TODO: Implement clone + let new_params: HashMap = self + .params + .iter() + .map(|(k, v)| (k.clone(), v.clone())) + .collect(); + let new_breadcrumbs: Vec> = self + .breadcrumbs + .iter() + .map(|bread| bread.clone_to_box()) + .collect(); ParametersContext { - params: HashMap::new(), - breadcrumbs: Vec::new(), + params: new_params, + breadcrumbs: new_breadcrumbs, } } } From 7dd824ab4f82ce6870deca6987c376b5ccecc9e3 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 22:40:47 -0400 Subject: [PATCH 26/31] cleaning up. --- src/bin.rs | 2 -- src/renderer/parameters_context.rs | 4 ---- src/renderer/renderer.rs | 1 - 3 files changed, 7 deletions(-) diff --git a/src/bin.rs b/src/bin.rs index 5555061..298751c 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -1,6 +1,5 @@ extern crate nom; -use crate::renderer::CloneIntoBoxedContextElement; use crate::renderer::CompareContextElement; use parser::Filter; use renderer::compile_template; @@ -12,7 +11,6 @@ use renderer::RenderError; use renderer::Renderable; use renderer::WalkError; use renderer::Walkable; -use std::any::Any; use std::env; use std::fs; use std::io::{self, Read}; diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index a9b52f5..59d97de 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -1,17 +1,13 @@ use crate::parser::KVPair; use crate::parser::{Filter, RValue}; -use crate::renderer::context_element::CastToAny; -use crate::renderer::context_element::CloneIntoBoxedContextElement; use crate::renderer::context_element::CompareContextElement; use crate::renderer::context_element::ContextElement; use crate::renderer::walking::owned_walk_path; -use crate::renderer::walking::walk_path; use crate::renderer::Loopable; use crate::renderer::RenderError; use crate::renderer::Renderable; use crate::renderer::WalkError; use crate::renderer::Walkable; -use std::any::Any; use std::collections::HashMap; /// Copy the data from an RValue to an Owned struct diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index c91587b..ad622a7 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -245,7 +245,6 @@ impl<'a> DustRenderer<'a> { RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), }, }; - println!("Comparing {:?} to {:?}", left_side, right_side); if left_side == right_side { match ¶meterized_block.contents { None => return Ok("".to_owned()), From 79099a8654fbeef74699e147bceb3d5ebc1c540e Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 23:01:14 -0400 Subject: [PATCH 27/31] Parsing positive integers. --- src/parser/parser.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 538e159..b4f533e 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -2,11 +2,11 @@ use nom::branch::alt; use nom::bytes::complete::escaped_transform; use nom::bytes::complete::is_a; use nom::bytes::complete::is_not; -use nom::bytes::complete::{tag, take_until, take_until_parser_matches}; +use nom::bytes::complete::{tag, take_until, take_until_parser_matches, take_while}; use nom::character::complete::line_ending; use nom::character::complete::multispace0; use nom::character::complete::one_of; -use nom::character::complete::{space0, space1}; +use nom::character::complete::{digit1, space0, space1}; use nom::combinator::all_consuming; use nom::combinator::map; use nom::combinator::opt; @@ -122,6 +122,7 @@ pub struct Partial<'a> { pub enum RValue<'a> { RVPath(Path<'a>), RVString(String), + RVPositiveInteger(u64), } #[derive(Clone, Debug, PartialEq)] @@ -210,6 +211,16 @@ fn path(i: &str) -> IResult<&str, Path> { ))(i) } +fn postitive_integer_literal(i: &str) -> IResult<&str, RValue> { + map( + verify( + map(digit1, |number_string: &str| number_string.parse::()), + |parse_result| parse_result.is_ok(), + ), + |parsed_number| RValue::RVPositiveInteger(parsed_number.unwrap()), + )(i) +} + /// Either a literal or a path to a value fn rvalue(i: &str) -> IResult<&str, RValue> { alt(( @@ -906,6 +917,8 @@ mod tests { ); } + // TODO: Add test for integer literals + #[test] fn test_quoted_partial() { assert_eq!( From 9ee8f41022edb497f7a5d31ccbf6ad9ba0083feb Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 23:11:16 -0400 Subject: [PATCH 28/31] Implement the render send of integer literals. --- src/bin.rs | 5 +++++ src/renderer/parameters_context.rs | 35 ++++++++++++++++++++++++++++++ src/renderer/renderer.rs | 2 ++ 3 files changed, 42 insertions(+) diff --git a/src/bin.rs b/src/bin.rs index 298751c..f764ebd 100644 --- a/src/bin.rs +++ b/src/bin.rs @@ -151,6 +151,11 @@ impl CompareContextElement for serde_json::Value { None => (), Some(other_string) => return self.as_str().map_or(false, |s| s == other_string), } + // Handle numeric literals + match other.to_any().downcast_ref::() { + None => (), + Some(other_num) => return self.as_u64().map_or(false, |n| n == *other_num), + } false } } diff --git a/src/renderer/parameters_context.rs b/src/renderer/parameters_context.rs index 59d97de..9d5d749 100644 --- a/src/renderer/parameters_context.rs +++ b/src/renderer/parameters_context.rs @@ -25,6 +25,7 @@ use std::collections::HashMap; pub enum OwnedRValue { RVPath(OwnedPath), RVString(String), + RVPositiveInteger(u64), } #[derive(Clone, Debug, PartialEq)] @@ -39,6 +40,7 @@ impl From<&RValue<'_>> for OwnedRValue { RValue::RVPath(path) => OwnedRValue::RVPath(OwnedPath { keys: path.keys.iter().map(|k| k.to_string()).collect(), }), + RValue::RVPositiveInteger(num) => OwnedRValue::RVPositiveInteger(*num), } } } @@ -91,6 +93,7 @@ impl Walkable for ParametersContext { match rval { OwnedRValue::RVPath(path) => owned_walk_path(&self.breadcrumbs, &path.keys), OwnedRValue::RVString(text) => Ok(text), + OwnedRValue::RVPositiveInteger(num) => Ok(num), } } } @@ -156,3 +159,35 @@ impl CompareContextElement for String { } } } + +impl ContextElement for u64 {} + +impl Renderable for u64 { + fn render(&self, _filters: &Vec) -> Result { + Ok(self.to_string()) + } +} + +impl Loopable for u64 { + fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { + vec![self] + } +} + +impl Walkable for u64 { + fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { + Err(WalkError::CantWalk) + } +} + +impl CompareContextElement for u64 { + fn equals(&self, other: &dyn ContextElement) -> bool { + // If its a u64 then compare them directly, otherwise defer + // to the other type's implementation of CompareContextElement + // since the end user could add any type. + match other.to_any().downcast_ref::() { + None => other.equals(self), + Some(other_num) => self == other_num, + } + } +} diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index ad622a7..117f882 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -235,6 +235,7 @@ impl<'a> DustRenderer<'a> { Some(rval) => match rval { RValue::RVString(text) => Ok(text), RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), + RValue::RVPositiveInteger(num) => Ok(num), }, }; let right_side: Result<&dyn ContextElement, WalkError> = @@ -243,6 +244,7 @@ impl<'a> DustRenderer<'a> { Some(rval) => match rval { RValue::RVString(text) => Ok(text), RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys), + RValue::RVPositiveInteger(num) => Ok(num), }, }; if left_side == right_side { From c88cab8316943769d64d7243f50dedab5675fecb Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 23:13:25 -0400 Subject: [PATCH 29/31] Hook in the integer parser. --- src/parser/parser.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index b4f533e..6f14407 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -211,13 +211,14 @@ fn path(i: &str) -> IResult<&str, Path> { ))(i) } -fn postitive_integer_literal(i: &str) -> IResult<&str, RValue> { +/// Just digits, no signs or decimals +fn postitive_integer_literal(i: &str) -> IResult<&str, u64> { map( verify( map(digit1, |number_string: &str| number_string.parse::()), |parse_result| parse_result.is_ok(), ), - |parsed_number| RValue::RVPositiveInteger(parsed_number.unwrap()), + |parsed_number| parsed_number.unwrap(), )(i) } @@ -226,6 +227,7 @@ fn rvalue(i: &str) -> IResult<&str, RValue> { alt(( map(path, RValue::RVPath), map(quoted_string, RValue::RVString), + map(postitive_integer_literal, RValue::RVPositiveInteger), ))(i) } From 6e6560c7427b198ef33a6e27f3a7292cf7832bd8 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 23:26:15 -0400 Subject: [PATCH 30/31] Revived the tests. --- src/renderer/renderer.rs | 104 +++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 58 deletions(-) diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index 117f882..e612cf5 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -292,88 +292,76 @@ mod tests { use crate::renderer::context_element::Loopable; use crate::renderer::context_element::Renderable; use crate::renderer::context_element::Walkable; + use crate::renderer::CompareContextElement; - impl ContextElement for u32 {} - impl ContextElement for &str {} - impl ContextElement for HashMap<&str, I> {} + impl ContextElement for HashMap {} - impl Renderable for u32 { - fn render(&self, _filters: &Vec) -> Result { - // TODO: handle the filters - Ok(self.to_string()) - } - } - - impl Renderable for &str { - fn render(&self, _filters: &Vec) -> Result { - // TODO: handle the filters - Ok(self.to_string()) - } - } - - impl Renderable for HashMap<&str, I> { + impl Renderable for HashMap { fn render(&self, _filters: &Vec) -> Result { // TODO: handle the filters Ok("[object Object]".to_owned()) } } - impl Walkable for HashMap<&str, I> { + impl Walkable for HashMap { fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { let child = self.get(segment).ok_or(WalkError::CantWalk)?; Ok(child) } } - impl Walkable for &str { - fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { - Err(WalkError::CantWalk) - } - } - - impl Walkable for u32 { - fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { - Err(WalkError::CantWalk) - } - } - - impl Loopable for &str { - fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { - if self.is_empty() { - Vec::new() - } else { - vec![self] - } - } - } - - impl Loopable for u32 { + impl Loopable for HashMap { fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { vec![self] } } - impl Loopable for HashMap<&str, I> { - fn get_loop_elements(&self) -> Vec<&dyn ContextElement> { - vec![self] + impl CompareContextElement for HashMap { + fn equals(&self, other: &dyn ContextElement) -> bool { + false } } #[test] fn test_walk_path() { - let context: HashMap<&str, &str> = - [("cat", "kitty"), ("dog", "doggy"), ("tiger", "murderkitty")] - .iter() - .cloned() - .collect(); - let number_context: HashMap<&str, u32> = [("cat", 1), ("dog", 2), ("tiger", 3)] - .iter() - .cloned() - .collect(); - let deep_context: HashMap<&str, HashMap<&str, &str>> = [ - ("cat", [("food", "meat")].iter().cloned().collect()), - ("dog", [("food", "meat")].iter().cloned().collect()), - ("tiger", [("food", "people")].iter().cloned().collect()), + let context: HashMap = [ + ("cat".to_string(), "kitty".to_string()), + ("dog".to_string(), "doggy".to_string()), + ("tiger".to_string(), "murderkitty".to_string()), + ] + .iter() + .cloned() + .collect(); + let number_context: HashMap = [ + ("cat".to_string(), 1), + ("dog".to_string(), 2), + ("tiger".to_string(), 3), + ] + .iter() + .cloned() + .collect(); + let deep_context: HashMap> = [ + ( + "cat".to_string(), + [("food".to_string(), "meat".to_string())] + .iter() + .cloned() + .collect(), + ), + ( + "dog".to_string(), + [("food".to_string(), "meat".to_string())] + .iter() + .cloned() + .collect(), + ), + ( + "tiger".to_string(), + [("food".to_string(), "people".to_string())] + .iter() + .cloned() + .collect(), + ), ] .iter() .cloned() From 1b63bc4083fa17eec94637d4fb6575a8a86c8357 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Sun, 10 May 2020 23:42:56 -0400 Subject: [PATCH 31/31] Add a test for integer literals. --- src/parser/parser.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/parser/parser.rs b/src/parser/parser.rs index 6f14407..3b8b30c 100644 --- a/src/parser/parser.rs +++ b/src/parser/parser.rs @@ -919,8 +919,6 @@ mod tests { ); } - // TODO: Add test for integer literals - #[test] fn test_quoted_partial() { assert_eq!( @@ -944,6 +942,29 @@ mod tests { ); } + #[test] + fn test_literals() { + assert_eq!( + dust_tag(r#"{>foo a="foo" b=179/}"#), + Ok(( + "", + DustTag::DTPartial(Partial { + name: "foo".to_owned(), + params: vec![ + KVPair { + key: "a", + value: RValue::RVString("foo".to_owned()) + }, + KVPair { + key: "b", + value: RValue::RVPositiveInteger(179) + } + ] + }) + )) + ); + } + #[test] fn test_helper() { assert_eq!(