port over the equals/not equals helpers.

master
Tom Alexander 4 years ago
parent c8de395038
commit 8cbb31251c
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE

@ -22,7 +22,7 @@ use std::rc::Rc;
#[derive(Debug)]
pub struct ParametersContext<'a> {
params: HashMap<&'a str, BreadcrumbTreeElement<'a>>,
params: HashMap<&'a str, (&'a RValue<'a>, BreadcrumbTreeElement<'a>)>,
}
impl<'a> ParametersContext<'a> {
@ -39,7 +39,7 @@ impl<'a> ParametersContext<'a> {
// then those are resolved at the time of access rather than
// the time of assignment, so we leave them into their
// original IntoContextElement state.
let rendered_params: HashMap<&'a str, BreadcrumbTreeElement<'a>> = params
let rendered_params: HashMap<&'a str, (&'a RValue<'a>, BreadcrumbTreeElement<'a>)> = params
.iter()
.map(|kvpair| {
let k = kvpair.key;
@ -55,7 +55,7 @@ impl<'a> ParametersContext<'a> {
Some(BreadcrumbTreeElement::from_borrowed(&kvpair.value))
}
};
v.map(|some_v| (k, some_v))
v.map(|some_v| (k, (&kvpair.value, some_v)))
})
// TODO: Should a None value here be the same as a key not existing, or should we store the Nones?
.filter_map(|pair| pair)
@ -65,6 +65,10 @@ impl<'a> ParametersContext<'a> {
params: rendered_params,
}
}
pub fn get_original_rvalue(&self, segment: &str) -> Option<&'a RValue<'a>> {
self.params.get(segment).map(|(rvalue, _bte)| *rvalue)
}
}
impl<'a> IntoContextElement for ParametersContext<'a> {
@ -81,7 +85,7 @@ impl<'a> Walkable for ParametersContext<'a> {
fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
self.params
.get(segment)
.map(|bte| bte.borrow())
.map(|(_rvalue, bte)| bte.borrow())
.ok_or(WalkError::CantWalk)
}

@ -2,14 +2,17 @@ use crate::parser::template;
use crate::parser::Body;
use crate::parser::DustTag;
use crate::parser::Filter;
use crate::parser::KVPair;
use crate::parser::PartialNameElement;
use crate::parser::Path;
use crate::parser::RValue;
use crate::parser::Special;
use crate::parser::Template;
use crate::parser::TemplateElement;
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
use crate::renderer::context_element::ContextElement;
use crate::renderer::context_element::IntoContextElement;
use crate::renderer::context_element::Walkable;
use crate::renderer::errors::CompileError;
use crate::renderer::errors::RenderError;
use crate::renderer::errors::WalkError;
@ -362,6 +365,124 @@ impl<'a> DustRenderer<'a> {
),
};
}
DustTag::DTHelperEquals(parameterized_block) => {
let new_breadcrumbs = self.new_breadcrumbs_partial(
breadcrumbs,
breadcrumbs,
None,
&parameterized_block.explicit_context,
);
let param_map =
ParametersContext::new(self, breadcrumbs, &parameterized_block.params);
// Special case: when comparing two RVPaths, if the
// path is equal then dust assumes the values are
// equal (otherwise, non-scalar values are
// automatically not equal)
if Self::are_paths_identical(&param_map, "key", "value") {
return match &parameterized_block.contents {
None => Ok("".to_owned()),
Some(body) => {
let rendered_content = self.render_body(
body,
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
blocks,
)?;
Ok(rendered_content)
}
};
}
let left_side = match param_map
.walk("key")
.map(|ice| ice.into_context_element(self, breadcrumbs))
{
Err(WalkError::CantWalk) | Ok(None) => return Ok("".to_owned()),
Ok(Some(res)) => res,
};
let right_side = param_map
.walk("value")
.map(|ice| ice.into_context_element(self, breadcrumbs));
if Ok(Some(left_side.get_context_element_reference()))
== right_side.as_ref().map(|maybe_ice| {
maybe_ice
.as_ref()
.map(|ice| ice.get_context_element_reference())
})
{
return self.render_maybe_body(
&parameterized_block.contents,
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
blocks,
);
} else {
return self.render_maybe_body(
&parameterized_block.else_contents,
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
blocks,
);
}
}
DustTag::DTHelperNotEquals(parameterized_block) => {
let new_breadcrumbs = self.new_breadcrumbs_partial(
breadcrumbs,
breadcrumbs,
None,
&parameterized_block.explicit_context,
);
let param_map =
ParametersContext::new(self, breadcrumbs, &parameterized_block.params);
// Special case: when comparing two RVPaths, if the
// path is equal then dust assumes the values are
// equal (otherwise, non-scalar values are
// automatically not equal)
if Self::are_paths_identical(&param_map, "key", "value") {
return match &parameterized_block.else_contents {
None => Ok("".to_owned()),
Some(body) => {
let rendered_content = self.render_body(
body,
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
blocks,
)?;
Ok(rendered_content)
}
};
}
let left_side = match param_map
.walk("key")
.map(|ice| ice.into_context_element(self, breadcrumbs))
{
Err(WalkError::CantWalk) | Ok(None) => return Ok("".to_owned()),
Ok(Some(res)) => res,
};
let right_side = param_map
.walk("value")
.map(|ice| ice.into_context_element(self, breadcrumbs));
if Ok(Some(left_side.get_context_element_reference()))
!= right_side.as_ref().map(|maybe_ice| {
maybe_ice
.as_ref()
.map(|ice| ice.get_context_element_reference())
})
{
return self.render_maybe_body(
&parameterized_block.contents,
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
blocks,
);
} else {
return self.render_maybe_body(
&parameterized_block.else_contents,
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
blocks,
);
}
}
_ => panic!("Unsupported tag"),
}
Ok("".to_owned())
@ -472,6 +593,26 @@ impl<'a> DustRenderer<'a> {
Some(new_stack)
}
fn are_paths_identical<'b>(
param_map: &ParametersContext<'b>,
left_key: &str,
right_key: &str,
) -> bool {
match (
param_map.get_original_rvalue(left_key),
param_map.get_original_rvalue(right_key),
) {
(None, _) => false,
(_, None) => false,
(Some(key_rval), Some(value_rval)) => match (key_rval, value_rval) {
(RValue::RVPath(key_path), RValue::RVPath(value_path)) => {
key_path.keys == value_path.keys
}
_ => false,
},
}
}
fn preprocess_filters(filters: &Vec<Filter>) -> Vec<Filter> {
let mut final_filters: Vec<Filter> = filters
.into_iter()

Loading…
Cancel
Save