Merge branch 'there_and_back_again' into into_context_element_breadcrumb_tree
This commit is contained in:
commit
e00f043c19
@ -21,3 +21,9 @@
|
||||
{@eq key=array_of_some_obj value=array_of_some_obj}array_of_some_obj is equal to array_of_some_obj{:else}array_of_some_obj does not equal array_of_some_obj{/eq}{~n}
|
||||
{@eq key=array_of_some_obj value=copy_array_of_some_obj}array_of_some_obj is equal to copy_array_of_some_obj{:else}array_of_some_obj does not equal copy_array_of_some_obj{/eq}{~n}
|
||||
{@eq key=array_of_some_obj value=array_of_other_obj}array_of_some_obj is equal to array_of_other_obj{:else}array_of_some_obj does not equal array_of_other_obj{/eq}{~n}
|
||||
|
||||
Do objects with different paths referencing the same variable match?{~n}
|
||||
===================================================================={~n}
|
||||
{#int renamed=some_obj}
|
||||
{@eq key=some_obj value=renamed}some_obj equals renamed{:else}some_obj does not equal renamed{/eq}{~n}
|
||||
{/int}
|
||||
|
@ -19,5 +19,14 @@
|
||||
"bar"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"some_object": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"some_same_object": {
|
||||
"foo": "bar"
|
||||
},
|
||||
"some_different_object": {
|
||||
"foo": "baz"
|
||||
}
|
||||
}
|
||||
|
@ -53,3 +53,12 @@ Reference Parameters{~n}
|
||||
{#truthy name="chris" pet="{petname}" petname="{deeperpetname}" deeperpetname="fluffy"}
|
||||
Hello {name}, nice {pet}{~n}
|
||||
{/truthy}
|
||||
|
||||
Equality{~n}
|
||||
========{~n}
|
||||
{@eq key=some_object value=some_object}some_object equals some_object{:else}some_object does not equal some_object{/eq}{~n}
|
||||
{@eq key=some_object value=some_same_object}some_object equals some_same_object{:else}some_object does not equal some_same_object{/eq}{~n}
|
||||
{@eq key=some_object value="{some_object}"}some_object equals reference(some_object){:else}some_object does not equal reference(some_object){/eq}{~n}
|
||||
{@eq key="{some_object}" value="{some_object}"}reference(some_object) equals reference(some_object){:else}reference(some_object) does not equal reference(some_object){/eq}{~n}
|
||||
{@eq key="{some_object}" value="{some_same_object}"}reference(some_object) equals reference(some_same_object){:else}reference(some_object) does not equal reference(some_same_object){/eq}{~n}
|
||||
{@eq key="{some_object}" value="{some_different_object}"}reference(some_object) equals reference(some_different_object){:else}reference(some_object) does not equal reference(some_different_object){/eq}{~n}
|
||||
|
547
src/bin.rs
547
src/bin.rs
@ -53,13 +53,12 @@ fn main() {
|
||||
compiled_templates.iter().for_each(|(name, template)| {
|
||||
dust_renderer.load_source(template, name.to_owned());
|
||||
});
|
||||
// let breadcrumbs = vec![&context as &dyn IntoContextElement];
|
||||
// println!(
|
||||
// "{}",
|
||||
// dust_renderer
|
||||
// .render(main_template_name, &breadcrumbs)
|
||||
// .expect("Failed to render")
|
||||
// );
|
||||
println!(
|
||||
"{}",
|
||||
dust_renderer
|
||||
.render(main_template_name, Some(&context))
|
||||
.expect("Failed to render")
|
||||
);
|
||||
}
|
||||
|
||||
fn template_from_file<'a>(
|
||||
@ -171,288 +170,288 @@ fn encode_uri_component(inp: &str) -> String {
|
||||
output
|
||||
}
|
||||
|
||||
// fn apply_filter(
|
||||
// json_value: &serde_json::Value,
|
||||
// filter: &Filter,
|
||||
// ) -> Result<serde_json::Value, RenderError> {
|
||||
// match (json_value, filter) {
|
||||
// // Html escape filter
|
||||
// (serde_json::Value::String(string), Filter::HtmlEncode) => {
|
||||
// Ok(serde_json::Value::String(html_escape(string)))
|
||||
// }
|
||||
// (_, Filter::HtmlEncode) => Ok(serde_json::Value::String(html_escape(
|
||||
// &json_value.render(&Vec::new())?,
|
||||
// ))),
|
||||
// // Disable html escape filter
|
||||
// (_, Filter::DisableHtmlEncode) => panic!("The |s filter is automatically removed by the renderer since it is a no-op during rendering."),
|
||||
// // Parse JSON filter
|
||||
// (serde_json::Value::String(string), Filter::JsonParse) => {
|
||||
// serde_json::from_str(&string).or(Err(RenderError::InvalidJson(string.to_owned())))
|
||||
// }
|
||||
// (_, Filter::JsonParse) => {
|
||||
// let rendered_value = json_value.render(&Vec::new())?;
|
||||
// serde_json::from_str(&rendered_value).or(Err(RenderError::InvalidJson(rendered_value)))
|
||||
// }
|
||||
// // Json Stringify filter
|
||||
// (_, Filter::JsonStringify) => {
|
||||
// Ok(serde_json::Value::String(json_value.to_string()))
|
||||
// }
|
||||
// // Javascript escape filter
|
||||
// (serde_json::Value::String(string), Filter::JavascriptStringEncode) => {
|
||||
// Ok(serde_json::Value::String(javascript_escape(string)))
|
||||
// }
|
||||
// (serde_json::Value::Bool(boolean), Filter::JavascriptStringEncode) => {
|
||||
// Ok(serde_json::Value::Bool(*boolean))
|
||||
// }
|
||||
// (serde_json::Value::Number(number), Filter::JavascriptStringEncode) => {
|
||||
// Ok(serde_json::Value::Number(number.clone()))
|
||||
// }
|
||||
// (serde_json::Value::Array(arr), Filter::JavascriptStringEncode) => {
|
||||
// Ok(serde_json::Value::Array(arr.clone()))
|
||||
// }
|
||||
// (serde_json::Value::Object(obj), Filter::JavascriptStringEncode) => {
|
||||
// Ok(serde_json::Value::Object(obj.clone()))
|
||||
// }
|
||||
// (_, Filter::JavascriptStringEncode) => Ok(serde_json::Value::String(javascript_escape(
|
||||
// &json_value.render(&Vec::new())?,
|
||||
// ))),
|
||||
// // EncodeURI filter
|
||||
// (serde_json::Value::String(string), Filter::EncodeUri) => {
|
||||
// Ok(serde_json::Value::String(encode_uri(string)))
|
||||
// }
|
||||
// (_, Filter::EncodeUri) => Ok(serde_json::Value::String(encode_uri(
|
||||
// &json_value.render(&Vec::new())?,
|
||||
// ))),
|
||||
// // EncodeURIComponent filter
|
||||
// (serde_json::Value::String(string), Filter::EncodeUriComponent) => {
|
||||
// Ok(serde_json::Value::String(encode_uri_component(string)))
|
||||
// }
|
||||
// (_, Filter::EncodeUriComponent) => Ok(serde_json::Value::String(encode_uri_component(
|
||||
// &json_value.render(&Vec::new())?,
|
||||
// ))),
|
||||
// }
|
||||
// }
|
||||
fn apply_filter(
|
||||
json_value: &serde_json::Value,
|
||||
filter: &Filter,
|
||||
) -> Result<serde_json::Value, RenderError> {
|
||||
match (json_value, filter) {
|
||||
// Html escape filter
|
||||
(serde_json::Value::String(string), Filter::HtmlEncode) => {
|
||||
Ok(serde_json::Value::String(html_escape(string)))
|
||||
}
|
||||
(_, Filter::HtmlEncode) => Ok(serde_json::Value::String(html_escape(
|
||||
&json_value.render(&Vec::new())?,
|
||||
))),
|
||||
// Disable html escape filter
|
||||
(_, Filter::DisableHtmlEncode) => panic!("The |s filter is automatically removed by the renderer since it is a no-op during rendering."),
|
||||
// Parse JSON filter
|
||||
(serde_json::Value::String(string), Filter::JsonParse) => {
|
||||
serde_json::from_str(&string).or(Err(RenderError::InvalidJson(string.to_owned())))
|
||||
}
|
||||
(_, Filter::JsonParse) => {
|
||||
let rendered_value = json_value.render(&Vec::new())?;
|
||||
serde_json::from_str(&rendered_value).or(Err(RenderError::InvalidJson(rendered_value)))
|
||||
}
|
||||
// Json Stringify filter
|
||||
(_, Filter::JsonStringify) => {
|
||||
Ok(serde_json::Value::String(json_value.to_string()))
|
||||
}
|
||||
// Javascript escape filter
|
||||
(serde_json::Value::String(string), Filter::JavascriptStringEncode) => {
|
||||
Ok(serde_json::Value::String(javascript_escape(string)))
|
||||
}
|
||||
(serde_json::Value::Bool(boolean), Filter::JavascriptStringEncode) => {
|
||||
Ok(serde_json::Value::Bool(*boolean))
|
||||
}
|
||||
(serde_json::Value::Number(number), Filter::JavascriptStringEncode) => {
|
||||
Ok(serde_json::Value::Number(number.clone()))
|
||||
}
|
||||
(serde_json::Value::Array(arr), Filter::JavascriptStringEncode) => {
|
||||
Ok(serde_json::Value::Array(arr.clone()))
|
||||
}
|
||||
(serde_json::Value::Object(obj), Filter::JavascriptStringEncode) => {
|
||||
Ok(serde_json::Value::Object(obj.clone()))
|
||||
}
|
||||
(_, Filter::JavascriptStringEncode) => Ok(serde_json::Value::String(javascript_escape(
|
||||
&json_value.render(&Vec::new())?,
|
||||
))),
|
||||
// EncodeURI filter
|
||||
(serde_json::Value::String(string), Filter::EncodeUri) => {
|
||||
Ok(serde_json::Value::String(encode_uri(string)))
|
||||
}
|
||||
(_, Filter::EncodeUri) => Ok(serde_json::Value::String(encode_uri(
|
||||
&json_value.render(&Vec::new())?,
|
||||
))),
|
||||
// EncodeURIComponent filter
|
||||
(serde_json::Value::String(string), Filter::EncodeUriComponent) => {
|
||||
Ok(serde_json::Value::String(encode_uri_component(string)))
|
||||
}
|
||||
(_, Filter::EncodeUriComponent) => Ok(serde_json::Value::String(encode_uri_component(
|
||||
&json_value.render(&Vec::new())?,
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
// fn apply_filters(
|
||||
// json_value: &serde_json::Value,
|
||||
// filters: &[Filter],
|
||||
// ) -> Result<serde_json::Value, RenderError> {
|
||||
// let mut final_value: serde_json::Value = apply_filter(json_value, &filters[0])?;
|
||||
fn apply_filters(
|
||||
json_value: &serde_json::Value,
|
||||
filters: &[Filter],
|
||||
) -> Result<serde_json::Value, RenderError> {
|
||||
let mut final_value: serde_json::Value = apply_filter(json_value, &filters[0])?;
|
||||
|
||||
// for filter in &filters[1..] {
|
||||
// final_value = apply_filter(&final_value, filter)?;
|
||||
// }
|
||||
for filter in &filters[1..] {
|
||||
final_value = apply_filter(&final_value, filter)?;
|
||||
}
|
||||
|
||||
// Ok(final_value)
|
||||
// }
|
||||
Ok(final_value)
|
||||
}
|
||||
|
||||
// impl ContextElement for serde_json::Value {}
|
||||
impl ContextElement for serde_json::Value {}
|
||||
|
||||
// impl Truthiness for serde_json::Value {
|
||||
// fn is_truthy(&self) -> bool {
|
||||
// match self {
|
||||
// serde_json::Value::Null => false,
|
||||
// serde_json::Value::Bool(boolean) => *boolean,
|
||||
// serde_json::Value::Number(_num) => true,
|
||||
// serde_json::Value::String(string_value) => !string_value.is_empty(),
|
||||
// serde_json::Value::Array(array_value) => !array_value.is_empty(),
|
||||
// serde_json::Value::Object(_obj) => true,
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
impl Truthiness for serde_json::Value {
|
||||
fn is_truthy(&self) -> bool {
|
||||
match self {
|
||||
serde_json::Value::Null => false,
|
||||
serde_json::Value::Bool(boolean) => *boolean,
|
||||
serde_json::Value::Number(_num) => true,
|
||||
serde_json::Value::String(string_value) => !string_value.is_empty(),
|
||||
serde_json::Value::Array(array_value) => !array_value.is_empty(),
|
||||
serde_json::Value::Object(_obj) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl Renderable for serde_json::Value {
|
||||
// fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
|
||||
// let after_apply = if _filters.is_empty() {
|
||||
// None
|
||||
// } else {
|
||||
// Some(apply_filters(self, _filters)?)
|
||||
// };
|
||||
impl Renderable for serde_json::Value {
|
||||
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
|
||||
let after_apply = if _filters.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(apply_filters(self, _filters)?)
|
||||
};
|
||||
|
||||
// match after_apply.as_ref().unwrap_or(self) {
|
||||
// serde_json::Value::Null => Ok("".to_owned()),
|
||||
// serde_json::Value::Bool(boolean) => Ok(boolean.to_string()),
|
||||
// serde_json::Value::Number(num) => Ok(num.to_string()),
|
||||
// serde_json::Value::String(string) => Ok(string.to_string()),
|
||||
// serde_json::Value::Array(arr) => {
|
||||
// // TODO: Handle the filters instead of passing a Vec::new()
|
||||
// let rendered: Result<Vec<String>, RenderError> =
|
||||
// arr.iter().map(|val| val.render(&Vec::new())).collect();
|
||||
// let rendered_slice: &[String] = &rendered?;
|
||||
// Ok(rendered_slice.join(","))
|
||||
// }
|
||||
// serde_json::Value::Object(_obj) => Ok("[object Object]".to_owned()),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
match after_apply.as_ref().unwrap_or(self) {
|
||||
serde_json::Value::Null => Ok("".to_owned()),
|
||||
serde_json::Value::Bool(boolean) => Ok(boolean.to_string()),
|
||||
serde_json::Value::Number(num) => Ok(num.to_string()),
|
||||
serde_json::Value::String(string) => Ok(string.to_string()),
|
||||
serde_json::Value::Array(arr) => {
|
||||
// TODO: Handle the filters instead of passing a Vec::new()
|
||||
let rendered: Result<Vec<String>, RenderError> =
|
||||
arr.iter().map(|val| val.render(&Vec::new())).collect();
|
||||
let rendered_slice: &[String] = &rendered?;
|
||||
Ok(rendered_slice.join(","))
|
||||
}
|
||||
serde_json::Value::Object(_obj) => Ok("[object Object]".to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl Walkable for serde_json::Value {
|
||||
// fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
|
||||
// match self {
|
||||
// serde_json::Value::Null => Err(WalkError::CantWalk),
|
||||
// serde_json::Value::Bool(_boolean) => Err(WalkError::CantWalk),
|
||||
// serde_json::Value::Number(_num) => Err(WalkError::CantWalk),
|
||||
// serde_json::Value::String(_string) => Err(WalkError::CantWalk),
|
||||
// serde_json::Value::Array(_arr) => Err(WalkError::CantWalk),
|
||||
// serde_json::Value::Object(obj) => obj
|
||||
// .get(segment)
|
||||
// .map(|val| val as _)
|
||||
// .ok_or(WalkError::CantWalk),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
impl Walkable for serde_json::Value {
|
||||
fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
|
||||
match self {
|
||||
serde_json::Value::Null => Err(WalkError::CantWalk),
|
||||
serde_json::Value::Bool(_boolean) => Err(WalkError::CantWalk),
|
||||
serde_json::Value::Number(_num) => Err(WalkError::CantWalk),
|
||||
serde_json::Value::String(_string) => Err(WalkError::CantWalk),
|
||||
serde_json::Value::Array(_arr) => Err(WalkError::CantWalk),
|
||||
serde_json::Value::Object(obj) => obj
|
||||
.get(segment)
|
||||
.map(|val| val as _)
|
||||
.ok_or(WalkError::CantWalk),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl Loopable for serde_json::Value {
|
||||
// fn get_loop_elements(&self) -> Vec<&dyn ContextElement> {
|
||||
// match self {
|
||||
// serde_json::Value::Array(array_value) => array_value.iter().map(|x| x as _).collect(),
|
||||
// _ => Vec::new(),
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
impl Loopable for serde_json::Value {
|
||||
fn get_loop_elements(&self) -> Vec<&dyn ContextElement> {
|
||||
match self {
|
||||
serde_json::Value::Array(array_value) => array_value.iter().map(|x| x as _).collect(),
|
||||
_ => Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl CompareContextElement for serde_json::Value {
|
||||
// fn equals(&self, other: &dyn ContextElement) -> bool {
|
||||
// // println!("equals json {:?} | {:?}", self, other);
|
||||
// // Handle other serde_json::Value
|
||||
// match other.to_any().downcast_ref::<Self>() {
|
||||
// None => (),
|
||||
// Some(other_json_value) => match (self, other_json_value) {
|
||||
// // Non-scalar values not caught in the renderer by the
|
||||
// // identical-path shortcut are always not equal.
|
||||
// (serde_json::Value::Array(_), _)
|
||||
// | (_, serde_json::Value::Array(_))
|
||||
// | (serde_json::Value::Object(_), _)
|
||||
// | (_, serde_json::Value::Object(_)) => return false,
|
||||
// _ => return self == other_json_value,
|
||||
// },
|
||||
// }
|
||||
// // Handle literals
|
||||
// match other.to_any().downcast_ref::<OwnedLiteral>() {
|
||||
// None => (),
|
||||
// Some(OwnedLiteral::LString(other_string)) => {
|
||||
// return self.as_str().map_or(false, |s| s == other_string)
|
||||
// }
|
||||
// Some(OwnedLiteral::LPositiveInteger(other_num)) => {
|
||||
// return self.as_u64().map_or(false, |n| n == *other_num)
|
||||
// }
|
||||
// }
|
||||
// false
|
||||
// }
|
||||
impl CompareContextElement for serde_json::Value {
|
||||
fn equals(&self, other: &dyn ContextElement) -> bool {
|
||||
// println!("equals json {:?} | {:?}", self, other);
|
||||
// Handle other serde_json::Value
|
||||
match other.to_any().downcast_ref::<Self>() {
|
||||
None => (),
|
||||
Some(other_json_value) => match (self, other_json_value) {
|
||||
// Non-scalar values not caught in the renderer by the
|
||||
// identical-path shortcut are always not equal.
|
||||
(serde_json::Value::Array(_), _)
|
||||
| (_, serde_json::Value::Array(_))
|
||||
| (serde_json::Value::Object(_), _)
|
||||
| (_, serde_json::Value::Object(_)) => return false,
|
||||
_ => return self == other_json_value,
|
||||
},
|
||||
}
|
||||
// Handle literals
|
||||
match other.to_any().downcast_ref::<OwnedLiteral>() {
|
||||
None => (),
|
||||
Some(OwnedLiteral::LString(other_string)) => {
|
||||
return self.as_str().map_or(false, |s| s == other_string)
|
||||
}
|
||||
Some(OwnedLiteral::LPositiveInteger(other_num)) => {
|
||||
return self.as_u64().map_or(false, |n| n == *other_num)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
||||
// // println!("partial_compare json {:?} | {:?}", self, other);
|
||||
// // Handle type coerced objects
|
||||
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
||||
// println!("partial_compare json {:?} | {:?}", self, other);
|
||||
// Handle type coerced objects
|
||||
|
||||
// // When doing a greater than or less than comparison,
|
||||
// // javascript coerces objects into "[object Object]".
|
||||
// if let serde_json::Value::Object(_) = self {
|
||||
// return OwnedLiteral::LString(self.render(&Vec::new()).unwrap_or("".to_owned()))
|
||||
// .partial_compare(other);
|
||||
// }
|
||||
// When doing a greater than or less than comparison,
|
||||
// javascript coerces objects into "[object Object]".
|
||||
if let serde_json::Value::Object(_) = self {
|
||||
return OwnedLiteral::LString(self.render(&Vec::new()).unwrap_or("".to_owned()))
|
||||
.partial_compare(other);
|
||||
}
|
||||
|
||||
// // When doing a greater than or less than comparison
|
||||
// // javascript turns arrays into strings.
|
||||
// if let serde_json::Value::Array(_) = self {
|
||||
// return OwnedLiteral::LString(self.render(&Vec::new()).unwrap_or("".to_owned()))
|
||||
// .partial_compare(other);
|
||||
// }
|
||||
// When doing a greater than or less than comparison
|
||||
// javascript turns arrays into strings.
|
||||
if let serde_json::Value::Array(_) = self {
|
||||
return OwnedLiteral::LString(self.render(&Vec::new()).unwrap_or("".to_owned()))
|
||||
.partial_compare(other);
|
||||
}
|
||||
|
||||
// // Handle other serde_json::Value
|
||||
// match other.to_any().downcast_ref::<Self>() {
|
||||
// None => (),
|
||||
// Some(other_json_value) => {
|
||||
// return match (self, other_json_value) {
|
||||
// (
|
||||
// serde_json::Value::Bool(self_boolean),
|
||||
// serde_json::Value::Bool(other_boolean),
|
||||
// ) => self_boolean.partial_cmp(other_boolean),
|
||||
// (
|
||||
// serde_json::Value::Number(self_number),
|
||||
// serde_json::Value::Number(other_number),
|
||||
// ) => return compare_json_numbers(self_number, other_number),
|
||||
// (
|
||||
// serde_json::Value::String(self_string),
|
||||
// serde_json::Value::Number(other_number),
|
||||
// ) => return compare_json_numbers(self_string, other_number),
|
||||
// (
|
||||
// serde_json::Value::Number(self_number),
|
||||
// serde_json::Value::String(other_string),
|
||||
// ) => return compare_json_numbers(self_number, other_string),
|
||||
// (
|
||||
// serde_json::Value::String(self_string),
|
||||
// serde_json::Value::String(other_string),
|
||||
// ) => self_string.partial_cmp(other_string),
|
||||
// (
|
||||
// serde_json::Value::Array(self_array),
|
||||
// serde_json::Value::Array(other_array),
|
||||
// ) => {
|
||||
// return self
|
||||
// .render(&Vec::new())
|
||||
// .unwrap_or("".to_owned())
|
||||
// .partial_cmp(
|
||||
// &other_json_value
|
||||
// .render(&Vec::new())
|
||||
// .unwrap_or("".to_owned()),
|
||||
// )
|
||||
// }
|
||||
// _ => None,
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// // Handle literals
|
||||
// match other.to_any().downcast_ref::<OwnedLiteral>() {
|
||||
// None => (),
|
||||
// Some(other_literal) => match (self, other_literal) {
|
||||
// (serde_json::Value::String(self_string), OwnedLiteral::LString(other_string)) => {
|
||||
// return self_string.partial_cmp(other_string)
|
||||
// }
|
||||
// (
|
||||
// serde_json::Value::String(self_string),
|
||||
// OwnedLiteral::LPositiveInteger(other_num),
|
||||
// ) => return compare_json_numbers(self_string, other_literal),
|
||||
// (serde_json::Value::Number(self_num), OwnedLiteral::LString(other_string)) => {
|
||||
// return compare_json_numbers(self_num, other_string)
|
||||
// }
|
||||
// (
|
||||
// serde_json::Value::Number(self_num),
|
||||
// OwnedLiteral::LPositiveInteger(other_num),
|
||||
// ) => return compare_json_numbers(self_num, other_literal),
|
||||
// (serde_json::Value::Array(_), _) => {
|
||||
// // TODO
|
||||
// todo!()
|
||||
// }
|
||||
// (serde_json::Value::Object(_), _) => {
|
||||
// // TODO
|
||||
// todo!()
|
||||
// }
|
||||
// (serde_json::Value::Bool(_), _) => {
|
||||
// // TODO
|
||||
// todo!()
|
||||
// }
|
||||
// (serde_json::Value::Null, _) => {
|
||||
// // TODO
|
||||
// todo!()
|
||||
// }
|
||||
// },
|
||||
// }
|
||||
// None
|
||||
// }
|
||||
// }
|
||||
// Handle other serde_json::Value
|
||||
match other.to_any().downcast_ref::<Self>() {
|
||||
None => (),
|
||||
Some(other_json_value) => {
|
||||
return match (self, other_json_value) {
|
||||
(
|
||||
serde_json::Value::Bool(self_boolean),
|
||||
serde_json::Value::Bool(other_boolean),
|
||||
) => self_boolean.partial_cmp(other_boolean),
|
||||
(
|
||||
serde_json::Value::Number(self_number),
|
||||
serde_json::Value::Number(other_number),
|
||||
) => return compare_json_numbers(self_number, other_number),
|
||||
(
|
||||
serde_json::Value::String(self_string),
|
||||
serde_json::Value::Number(other_number),
|
||||
) => return compare_json_numbers(self_string, other_number),
|
||||
(
|
||||
serde_json::Value::Number(self_number),
|
||||
serde_json::Value::String(other_string),
|
||||
) => return compare_json_numbers(self_number, other_string),
|
||||
(
|
||||
serde_json::Value::String(self_string),
|
||||
serde_json::Value::String(other_string),
|
||||
) => self_string.partial_cmp(other_string),
|
||||
(
|
||||
serde_json::Value::Array(self_array),
|
||||
serde_json::Value::Array(other_array),
|
||||
) => {
|
||||
return self
|
||||
.render(&Vec::new())
|
||||
.unwrap_or("".to_owned())
|
||||
.partial_cmp(
|
||||
&other_json_value
|
||||
.render(&Vec::new())
|
||||
.unwrap_or("".to_owned()),
|
||||
)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
}
|
||||
// Handle literals
|
||||
match other.to_any().downcast_ref::<OwnedLiteral>() {
|
||||
None => (),
|
||||
Some(other_literal) => match (self, other_literal) {
|
||||
(serde_json::Value::String(self_string), OwnedLiteral::LString(other_string)) => {
|
||||
return self_string.partial_cmp(other_string)
|
||||
}
|
||||
(
|
||||
serde_json::Value::String(self_string),
|
||||
OwnedLiteral::LPositiveInteger(other_num),
|
||||
) => return compare_json_numbers(self_string, other_literal),
|
||||
(serde_json::Value::Number(self_num), OwnedLiteral::LString(other_string)) => {
|
||||
return compare_json_numbers(self_num, other_string)
|
||||
}
|
||||
(
|
||||
serde_json::Value::Number(self_num),
|
||||
OwnedLiteral::LPositiveInteger(other_num),
|
||||
) => return compare_json_numbers(self_num, other_literal),
|
||||
(serde_json::Value::Array(_), _) => {
|
||||
// TODO
|
||||
todo!()
|
||||
}
|
||||
(serde_json::Value::Object(_), _) => {
|
||||
// TODO
|
||||
todo!()
|
||||
}
|
||||
(serde_json::Value::Bool(_), _) => {
|
||||
// TODO
|
||||
todo!()
|
||||
}
|
||||
(serde_json::Value::Null, _) => {
|
||||
// TODO
|
||||
todo!()
|
||||
}
|
||||
},
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// /// Create a new vec by of references to the serde_json::Values as
|
||||
// /// ContextElement trait objects so we can use its implementation of
|
||||
// /// PartialOrd.
|
||||
// ///
|
||||
// /// You cannot implement a trait you do not define for a type you do
|
||||
// /// not define, so I cannot implement PartialOrd for
|
||||
// /// serde_json::value. Instead, I just re-use the PartialOrd
|
||||
// /// implementation for ContextElement which unfortunately has extra
|
||||
// /// overhead of downcasting. This would be a good spot for
|
||||
// /// optimization.
|
||||
// fn convert_vec_to_context_element(array: &Vec<serde_json::Value>) -> Vec<&dyn ContextElement> {
|
||||
// array.iter().map(|v| v as _).collect()
|
||||
// }
|
||||
/// Create a new vec by of references to the serde_json::Values as
|
||||
/// ContextElement trait objects so we can use its implementation of
|
||||
/// PartialOrd.
|
||||
///
|
||||
/// You cannot implement a trait you do not define for a type you do
|
||||
/// not define, so I cannot implement PartialOrd for
|
||||
/// serde_json::value. Instead, I just re-use the PartialOrd
|
||||
/// implementation for ContextElement which unfortunately has extra
|
||||
/// overhead of downcasting. This would be a good spot for
|
||||
/// optimization.
|
||||
fn convert_vec_to_context_element(array: &Vec<serde_json::Value>) -> Vec<&dyn ContextElement> {
|
||||
array.iter().map(|v| v as _).collect()
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum JsonNumber {
|
||||
|
@ -5,11 +5,6 @@ use crate::renderer::context_element::IntoRcIce;
|
||||
use std::borrow::Borrow;
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct BreadcrumbTree<'a> {
|
||||
parent: Option<&'a BreadcrumbTree<'a>>,
|
||||
element: BreadcrumbTreeElement<'a>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BreadcrumbTreeElement<'a> {
|
||||
// Using Rc so that when we need to create BreadcrumbTrees with
|
||||
@ -54,43 +49,6 @@ impl<'a> From<IceResult<'a>> for BreadcrumbTreeElement<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BreadcrumbTree<'a> {
|
||||
pub fn new(parent: Option<&'a BreadcrumbTree>, element: BreadcrumbTreeElement<'a>) -> Self {
|
||||
BreadcrumbTree {
|
||||
parent: parent,
|
||||
element: element,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_ice(&self) -> &dyn IntoContextElement {
|
||||
self.element.borrow()
|
||||
}
|
||||
|
||||
pub fn get_parent(&self) -> Option<&BreadcrumbTree> {
|
||||
self.parent
|
||||
}
|
||||
|
||||
pub fn get_element(&self) -> &BreadcrumbTreeElement<'a> {
|
||||
&self.element
|
||||
}
|
||||
|
||||
pub fn ice_iter(&'a self) -> impl Iterator<Item = &dyn IntoContextElement> {
|
||||
self.breadcrumb_iter().map(|b| b.get_ice())
|
||||
}
|
||||
|
||||
pub fn breadcrumb_iter(&'a self) -> BreadcrumbTreeIterator<'a> {
|
||||
BreadcrumbTreeIterator(Some(self))
|
||||
}
|
||||
|
||||
pub fn clone_to_new_parent(&self, parent: Option<&'a BreadcrumbTree>) -> Self {
|
||||
// TODO: Maybe not needed anymore?
|
||||
BreadcrumbTree {
|
||||
parent: parent,
|
||||
element: self.element.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Borrow<dyn IntoContextElement + 'a> for BreadcrumbTreeElement<'a> {
|
||||
fn borrow(&self) -> &(dyn IntoContextElement + 'a) {
|
||||
match self {
|
||||
@ -99,24 +57,3 @@ impl<'a> Borrow<dyn IntoContextElement + 'a> for BreadcrumbTreeElement<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a BreadcrumbTree<'a> {
|
||||
type Item = &'a BreadcrumbTree<'a>;
|
||||
type IntoIter = BreadcrumbTreeIterator<'a>;
|
||||
|
||||
fn into_iter(self) -> BreadcrumbTreeIterator<'a> {
|
||||
self.breadcrumb_iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct BreadcrumbTreeIterator<'a>(Option<&'a BreadcrumbTree<'a>>);
|
||||
|
||||
impl<'a> Iterator for BreadcrumbTreeIterator<'a> {
|
||||
type Item = &'a BreadcrumbTree<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let ret = self.0;
|
||||
self.0 = self.0.map(|node| node.get_parent()).flatten();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::parser::Filter;
|
||||
use crate::renderer::breadcrumb_tree::BreadcrumbTree;
|
||||
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
|
||||
use crate::renderer::errors::RenderError;
|
||||
use crate::renderer::errors::WalkError;
|
||||
use crate::renderer::DustRenderer;
|
||||
@ -106,7 +106,7 @@ pub trait IntoContextElement: Debug + Walkable /* + CloneIntoBoxedContextElement
|
||||
fn into_context_element<'a>(
|
||||
&'a self,
|
||||
renderer: &DustRenderer,
|
||||
breadcrumbs: Option<&'a BreadcrumbTree<'a>>,
|
||||
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
) -> Option<IceResult<'a>>;
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ impl<C: ContextElement> IntoContextElement for C {
|
||||
fn into_context_element<'a>(
|
||||
&'a self,
|
||||
renderer: &DustRenderer,
|
||||
breadcrumbs: Option<&'a BreadcrumbTree<'a>>,
|
||||
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
) -> Option<IceResult<'a>> {
|
||||
Some(IceResult::from_borrowed(self))
|
||||
}
|
||||
@ -161,7 +161,7 @@ impl<'a> IntoContextElement for IceResult<'a> {
|
||||
fn into_context_element<'b>(
|
||||
&'b self,
|
||||
renderer: &DustRenderer,
|
||||
breadcrumbs: Option<&'b BreadcrumbTree<'b>>,
|
||||
breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
|
||||
) -> Option<IceResult<'b>> {
|
||||
match self {
|
||||
IceResult::Owned(rc_ce) => Some(IceResult::from_borrowed(rc_ce.as_ref())),
|
||||
|
@ -1,6 +1,9 @@
|
||||
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
|
||||
use crate::renderer::context_element::CompareContextElement;
|
||||
use crate::renderer::context_element::ContextElement;
|
||||
use crate::renderer::context_element::IceResult;
|
||||
use crate::renderer::context_element::IntoContextElement;
|
||||
use crate::renderer::DustRenderer;
|
||||
use crate::renderer::Loopable;
|
||||
use crate::renderer::RenderError;
|
||||
use crate::renderer::Renderable;
|
||||
@ -16,7 +19,7 @@ use std::cmp::Ordering;
|
||||
/// Functions the same as the injected parameters contexts for
|
||||
/// helpers/partials with parameters but this has no need for storing
|
||||
/// breadcrumbs since its simply storing two integers.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug)]
|
||||
pub struct IterationContext {
|
||||
idx: OwnedLiteral,
|
||||
len: OwnedLiteral,
|
||||
@ -32,32 +35,13 @@ impl IterationContext {
|
||||
}
|
||||
}
|
||||
|
||||
impl ContextElement for IterationContext {}
|
||||
|
||||
impl Truthiness for IterationContext {
|
||||
fn is_truthy(&self) -> bool {
|
||||
// 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 `{.}`.
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderable for IterationContext {
|
||||
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
|
||||
// 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 IterationContext {
|
||||
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::new()
|
||||
impl IntoContextElement for IterationContext {
|
||||
fn into_context_element<'b>(
|
||||
&'b self,
|
||||
renderer: &DustRenderer,
|
||||
breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
|
||||
) -> Option<IceResult<'b>> {
|
||||
panic!("into_context_element cannot be called on pseudo elements");
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,15 +58,3 @@ impl Walkable for IterationContext {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl CompareContextElement for IterationContext {
|
||||
fn equals(&self, other: &dyn ContextElement) -> bool {
|
||||
// TODO: Does this ever happen? perhaps I should have a panic here.
|
||||
false
|
||||
}
|
||||
|
||||
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
||||
// TODO: Does this ever happen? perhaps I should have a panic here.
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ mod breadcrumb_tree;
|
||||
mod context_element;
|
||||
mod errors;
|
||||
mod inline_partial_tree;
|
||||
// mod iteration_context;
|
||||
mod iteration_context;
|
||||
mod parameters_context;
|
||||
mod renderer;
|
||||
mod tree_walking;
|
||||
|
@ -2,7 +2,6 @@ use crate::parser::Filter;
|
||||
use crate::parser::KVPair;
|
||||
use crate::parser::OwnedLiteral;
|
||||
use crate::parser::RValue;
|
||||
use crate::renderer::breadcrumb_tree::BreadcrumbTree;
|
||||
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
|
||||
use crate::renderer::context_element::CompareContextElement;
|
||||
use crate::renderer::context_element::ContextElement;
|
||||
@ -23,13 +22,13 @@ use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ParametersContext<'a> {
|
||||
params: HashMap<&'a str, BreadcrumbTreeElement<'a>>,
|
||||
params: HashMap<&'a str, (&'a RValue<'a>, Option<BreadcrumbTreeElement<'a>>)>,
|
||||
}
|
||||
|
||||
impl<'a> ParametersContext<'a> {
|
||||
pub fn new(
|
||||
renderer: &DustRenderer,
|
||||
breadcrumbs: Option<&'a BreadcrumbTree>,
|
||||
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
params: &'a Vec<KVPair>,
|
||||
) -> Self {
|
||||
// If the parameter is a Path, then we resolve it immediately
|
||||
@ -40,7 +39,8 @@ 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>, Option<BreadcrumbTreeElement<'a>>)> =
|
||||
params
|
||||
.iter()
|
||||
.map(|kvpair| {
|
||||
let k = kvpair.key;
|
||||
@ -56,23 +56,29 @@ impl<'a> ParametersContext<'a> {
|
||||
Some(BreadcrumbTreeElement::from_borrowed(&kvpair.value))
|
||||
}
|
||||
};
|
||||
v.map(|some_v| (k, some_v))
|
||||
(k, (&kvpair.value, 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)
|
||||
.collect();
|
||||
|
||||
ParametersContext {
|
||||
params: rendered_params,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_original_rvalue(&self, segment: &str) -> Option<&'a RValue<'a>> {
|
||||
self.params.get(segment).map(|(rvalue, _bte)| *rvalue)
|
||||
}
|
||||
|
||||
pub fn contains_key(&self, segment: &str) -> bool {
|
||||
self.params.contains_key(segment)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoContextElement for ParametersContext<'a> {
|
||||
fn into_context_element<'b>(
|
||||
&'b self,
|
||||
renderer: &DustRenderer,
|
||||
breadcrumbs: Option<&'b BreadcrumbTree<'b>>,
|
||||
breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
|
||||
) -> Option<IceResult<'b>> {
|
||||
panic!("into_context_element cannot be called on pseudo elements");
|
||||
}
|
||||
@ -80,10 +86,10 @@ impl<'a> IntoContextElement for ParametersContext<'a> {
|
||||
|
||||
impl<'a> Walkable for ParametersContext<'a> {
|
||||
fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
|
||||
self.params
|
||||
.get(segment)
|
||||
.map(|bte| bte.borrow())
|
||||
.ok_or(WalkError::CantWalk)
|
||||
match self.params.get(segment).map(|(_rvalue, bte)| bte) {
|
||||
Some(Some(bte)) => Ok(bte.borrow()),
|
||||
_ => Err(WalkError::CantWalk),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_pseudo_element(&self) -> bool {
|
||||
@ -95,7 +101,7 @@ impl<'a> IntoContextElement for RValue<'a> {
|
||||
fn into_context_element<'b>(
|
||||
&'b self,
|
||||
renderer: &DustRenderer,
|
||||
breadcrumbs: Option<&'b BreadcrumbTree<'b>>,
|
||||
breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
|
||||
) -> Option<IceResult<'b>> {
|
||||
match self {
|
||||
RValue::RVLiteral(owned_literal) => Some(IceResult::from_borrowed(owned_literal)),
|
||||
|
@ -2,20 +2,24 @@ 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::BreadcrumbTree;
|
||||
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
|
||||
use crate::renderer::context_element::ContextElement;
|
||||
use crate::renderer::context_element::IceResult;
|
||||
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;
|
||||
use crate::renderer::inline_partial_tree::extract_inline_partials;
|
||||
use crate::renderer::inline_partial_tree::InlinePartialTreeElement;
|
||||
use crate::renderer::iteration_context::IterationContext;
|
||||
use crate::renderer::parameters_context::ParametersContext;
|
||||
use crate::renderer::tree_walking::walk_path;
|
||||
use std::borrow::Borrow;
|
||||
@ -49,15 +53,16 @@ impl<'a> DustRenderer<'a> {
|
||||
where
|
||||
C: IntoContextElement,
|
||||
{
|
||||
let breadcrumbs =
|
||||
context.map(|ctx| BreadcrumbTree::new(None, BreadcrumbTreeElement::from_borrowed(ctx)));
|
||||
let breadcrumbs = context
|
||||
.map(|ctx| vec![BreadcrumbTreeElement::from_borrowed(ctx)])
|
||||
.unwrap_or(Vec::new());
|
||||
self.render_template(name, breadcrumbs.as_ref(), None)
|
||||
}
|
||||
|
||||
pub fn render_template(
|
||||
&'a self,
|
||||
name: &str,
|
||||
breadcrumbs: Option<&'a BreadcrumbTree>,
|
||||
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
blocks: Option<&'a InlinePartialTreeElement<'a>>,
|
||||
) -> Result<String, RenderError> {
|
||||
let main_template = match self.templates.get(name) {
|
||||
@ -78,7 +83,7 @@ impl<'a> DustRenderer<'a> {
|
||||
fn render_maybe_body(
|
||||
&'a self,
|
||||
body: &'a Option<Body>,
|
||||
breadcrumbs: Option<&'a BreadcrumbTree>,
|
||||
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
blocks: &'a BlockContext<'a>,
|
||||
) -> Result<String, RenderError> {
|
||||
match body {
|
||||
@ -90,7 +95,7 @@ impl<'a> DustRenderer<'a> {
|
||||
fn render_body(
|
||||
&'a self,
|
||||
body: &'a Body,
|
||||
breadcrumbs: Option<&'a BreadcrumbTree>,
|
||||
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
blocks: &'a BlockContext<'a>,
|
||||
) -> Result<String, RenderError> {
|
||||
let mut output = String::new();
|
||||
@ -110,7 +115,7 @@ impl<'a> DustRenderer<'a> {
|
||||
pub fn render_partial_name(
|
||||
&'a self,
|
||||
body: &'a Vec<PartialNameElement>,
|
||||
breadcrumbs: Option<&'a BreadcrumbTree>,
|
||||
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
) -> Result<String, RenderError> {
|
||||
let converted_to_template_elements: Vec<TemplateElement<'a>> =
|
||||
body.into_iter().map(|e| e.into()).collect();
|
||||
@ -118,7 +123,7 @@ impl<'a> DustRenderer<'a> {
|
||||
// cannot contain blocks or inline partials, so we use a blank
|
||||
// BlockContext.
|
||||
let empty_block_context = BlockContext {
|
||||
breadcrumbs: None,
|
||||
breadcrumbs: &Vec::new(),
|
||||
blocks: &InlinePartialTreeElement::new(None, HashMap::new()),
|
||||
};
|
||||
self.render_body(
|
||||
@ -133,7 +138,7 @@ impl<'a> DustRenderer<'a> {
|
||||
fn render_tag(
|
||||
&'a self,
|
||||
tag: &'a DustTag,
|
||||
breadcrumbs: Option<&'a BreadcrumbTree>,
|
||||
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
blocks: &'a BlockContext<'a>,
|
||||
) -> Result<String, RenderError> {
|
||||
match tag {
|
||||
@ -170,8 +175,7 @@ impl<'a> DustRenderer<'a> {
|
||||
let val = walk_path(breadcrumbs, &container.path.keys)
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
match val {
|
||||
Err(WalkError::CantWalk) => {
|
||||
// TODO
|
||||
Err(WalkError::CantWalk) | Ok(None) => {
|
||||
let new_breadcrumbs = self.new_breadcrumbs_section(
|
||||
breadcrumbs,
|
||||
None,
|
||||
@ -179,34 +183,485 @@ impl<'a> DustRenderer<'a> {
|
||||
&container.explicit_context,
|
||||
None,
|
||||
);
|
||||
return self.render_maybe_body(
|
||||
&container.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
}
|
||||
Ok(final_val) => {
|
||||
// TODO
|
||||
Ok(Some(final_val)) => {
|
||||
let context_element = final_val.get_context_element_reference();
|
||||
return if context_element.is_truthy() {
|
||||
match &container.contents {
|
||||
None => Ok("".to_owned()),
|
||||
Some(body) => {
|
||||
let loop_elements: Vec<&dyn ContextElement> =
|
||||
context_element.get_loop_elements();
|
||||
if loop_elements.is_empty() {
|
||||
// Scalar value
|
||||
let new_breadcrumbs = self.new_breadcrumbs_section(
|
||||
breadcrumbs,
|
||||
None,
|
||||
Some(&injected_context),
|
||||
&container.explicit_context,
|
||||
Some(context_element),
|
||||
);
|
||||
self.render_body(
|
||||
body,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
)
|
||||
} else {
|
||||
// Array-like value
|
||||
let total_length = loop_elements.len();
|
||||
let rendered_results: Result<Vec<String>, RenderError> =
|
||||
loop_elements
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, array_elem)| {
|
||||
let index_context =
|
||||
IterationContext::new(i, total_length);
|
||||
let new_breadcrumbs = self
|
||||
.new_breadcrumbs_section(
|
||||
breadcrumbs,
|
||||
Some(&index_context),
|
||||
Some(&injected_context),
|
||||
&container.explicit_context,
|
||||
Some(array_elem),
|
||||
);
|
||||
self.render_body(
|
||||
&body,
|
||||
new_breadcrumbs
|
||||
.as_ref()
|
||||
.unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let rendered_slice: &[String] = &rendered_results?;
|
||||
return Ok(rendered_slice.join(""));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Oddly enough if the value is falsey (like
|
||||
// an empty array or null), Dust uses the
|
||||
// original context before walking the path as
|
||||
// the context for rendering the else block
|
||||
let new_breadcrumbs = self.new_breadcrumbs_section(
|
||||
breadcrumbs,
|
||||
None,
|
||||
Some(&injected_context),
|
||||
&container.explicit_context,
|
||||
None,
|
||||
);
|
||||
self.render_maybe_body(
|
||||
&container.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
DustTag::DTExists(container) => {
|
||||
let new_breadcrumbs = self.new_breadcrumbs_partial(
|
||||
breadcrumbs,
|
||||
breadcrumbs,
|
||||
None,
|
||||
&container.explicit_context,
|
||||
);
|
||||
let val = walk_path(breadcrumbs, &container.path.keys)
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
return match val {
|
||||
Ok(Some(v)) if v.get_context_element_reference().is_truthy() => self
|
||||
.render_maybe_body(
|
||||
&container.contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
),
|
||||
_ => self.render_maybe_body(
|
||||
&container.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
),
|
||||
};
|
||||
}
|
||||
DustTag::DTNotExists(container) => {
|
||||
let new_breadcrumbs = self.new_breadcrumbs_partial(
|
||||
breadcrumbs,
|
||||
breadcrumbs,
|
||||
None,
|
||||
&container.explicit_context,
|
||||
);
|
||||
let val = walk_path(breadcrumbs, &container.path.keys)
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
return match val {
|
||||
Ok(Some(v)) if v.get_context_element_reference().is_truthy() => self
|
||||
.render_maybe_body(
|
||||
&container.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
),
|
||||
_ => self.render_maybe_body(
|
||||
&container.contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
),
|
||||
};
|
||||
}
|
||||
DustTag::DTPartial(partial) => {
|
||||
let partial_name = self.render_partial_name(&partial.name, breadcrumbs)?;
|
||||
if partial.params.is_empty() {
|
||||
let new_breadcrumbs = self.new_breadcrumbs_partial(
|
||||
breadcrumbs,
|
||||
breadcrumbs,
|
||||
None,
|
||||
&partial.explicit_context,
|
||||
);
|
||||
let rendered_content = self.render_template(
|
||||
&partial_name,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
Some(blocks.blocks),
|
||||
)?;
|
||||
return Ok(rendered_content);
|
||||
} else {
|
||||
let injected_context =
|
||||
ParametersContext::new(self, breadcrumbs, &partial.params);
|
||||
let new_breadcrumbs = self.new_breadcrumbs_partial(
|
||||
breadcrumbs,
|
||||
breadcrumbs,
|
||||
Some(&injected_context),
|
||||
&partial.explicit_context,
|
||||
);
|
||||
let rendered_content = self.render_template(
|
||||
&partial_name,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
Some(blocks.blocks),
|
||||
)?;
|
||||
return Ok(rendered_content);
|
||||
}
|
||||
}
|
||||
DustTag::DTInlinePartial(_named_block) => {
|
||||
// Inline partials are blank during rendering (they get injected into blocks)
|
||||
return Ok("".to_owned());
|
||||
}
|
||||
DustTag::DTBlock(named_block) => {
|
||||
let new_breadcrumbs = self.new_breadcrumbs_partial(
|
||||
breadcrumbs,
|
||||
blocks.breadcrumbs,
|
||||
None,
|
||||
&named_block.explicit_context,
|
||||
);
|
||||
return match blocks.blocks.get_block(named_block.path.keys[0]) {
|
||||
None => self.render_maybe_body(
|
||||
&named_block.contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
),
|
||||
Some(inline_partial) => self.render_maybe_body(
|
||||
inline_partial,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
),
|
||||
};
|
||||
}
|
||||
DustTag::DTHelperEquals(parameterized_block) => {
|
||||
let new_breadcrumbs = self.new_breadcrumbs_partial(
|
||||
breadcrumbs,
|
||||
breadcrumbs,
|
||||
None,
|
||||
¶meterized_block.explicit_context,
|
||||
);
|
||||
|
||||
let param_map =
|
||||
ParametersContext::new(self, breadcrumbs, ¶meterized_block.params);
|
||||
|
||||
if !param_map.contains_key("key") {
|
||||
return Ok("".to_owned());
|
||||
}
|
||||
let left_side = param_map
|
||||
.walk("key")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
let right_side = param_map
|
||||
.walk("value")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
// Special case: when comparing two RVPaths, if the
|
||||
// path points to the same value then they are
|
||||
// equal. This is particularly important for objects
|
||||
// which compare memory locations rather than contents
|
||||
// (javascript object equality).
|
||||
if Self::new_are_paths_identical(&left_side, &right_side)
|
||||
|| left_side.as_ref().map(|maybe_ice| {
|
||||
maybe_ice
|
||||
.as_ref()
|
||||
.map(|ice| ice.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(
|
||||
¶meterized_block.contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
} else {
|
||||
return self.render_maybe_body(
|
||||
¶meterized_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,
|
||||
¶meterized_block.explicit_context,
|
||||
);
|
||||
|
||||
let param_map =
|
||||
ParametersContext::new(self, breadcrumbs, ¶meterized_block.params);
|
||||
|
||||
if !param_map.contains_key("key") {
|
||||
return Ok("".to_owned());
|
||||
}
|
||||
let left_side = param_map
|
||||
.walk("key")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
let right_side = param_map
|
||||
.walk("value")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
// Special case: when comparing two RVPaths, if the
|
||||
// path points to the same value then they are
|
||||
// equal. This is particularly important for objects
|
||||
// which compare memory locations rather than contents
|
||||
// (javascript object equality).
|
||||
if Self::new_are_paths_identical(&left_side, &right_side)
|
||||
|| left_side.as_ref().map(|maybe_ice| {
|
||||
maybe_ice
|
||||
.as_ref()
|
||||
.map(|ice| ice.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(
|
||||
¶meterized_block.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
} else {
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
}
|
||||
}
|
||||
DustTag::DTHelperGreaterThan(parameterized_block) => {
|
||||
let new_breadcrumbs = self.new_breadcrumbs_partial(
|
||||
breadcrumbs,
|
||||
breadcrumbs,
|
||||
None,
|
||||
¶meterized_block.explicit_context,
|
||||
);
|
||||
|
||||
let param_map =
|
||||
ParametersContext::new(self, breadcrumbs, ¶meterized_block.params);
|
||||
if !param_map.contains_key("key") {
|
||||
return Ok("".to_owned());
|
||||
}
|
||||
let left_side = param_map
|
||||
.walk("key")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
let right_side = param_map
|
||||
.walk("value")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
match (left_side, right_side) {
|
||||
(Ok(Some(left_side_unwrapped)), Ok(Some(right_side_unwrapped))) => {
|
||||
if left_side_unwrapped.get_context_element_reference()
|
||||
> right_side_unwrapped.get_context_element_reference()
|
||||
{
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
} else {
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
DustTag::DTHelperGreaterThanOrEquals(parameterized_block) => {
|
||||
let new_breadcrumbs = self.new_breadcrumbs_partial(
|
||||
breadcrumbs,
|
||||
breadcrumbs,
|
||||
None,
|
||||
¶meterized_block.explicit_context,
|
||||
);
|
||||
|
||||
let param_map =
|
||||
ParametersContext::new(self, breadcrumbs, ¶meterized_block.params);
|
||||
if !param_map.contains_key("key") {
|
||||
return Ok("".to_owned());
|
||||
}
|
||||
let left_side = param_map
|
||||
.walk("key")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
let right_side = param_map
|
||||
.walk("value")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
match (left_side, right_side) {
|
||||
(Ok(Some(left_side_unwrapped)), Ok(Some(right_side_unwrapped))) => {
|
||||
if left_side_unwrapped.get_context_element_reference()
|
||||
>= right_side_unwrapped.get_context_element_reference()
|
||||
{
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
} else {
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
DustTag::DTHelperLessThan(parameterized_block) => {
|
||||
let new_breadcrumbs = self.new_breadcrumbs_partial(
|
||||
breadcrumbs,
|
||||
breadcrumbs,
|
||||
None,
|
||||
¶meterized_block.explicit_context,
|
||||
);
|
||||
|
||||
let param_map =
|
||||
ParametersContext::new(self, breadcrumbs, ¶meterized_block.params);
|
||||
if !param_map.contains_key("key") {
|
||||
return Ok("".to_owned());
|
||||
}
|
||||
let left_side = param_map
|
||||
.walk("key")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
let right_side = param_map
|
||||
.walk("value")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
match (left_side, right_side) {
|
||||
(Ok(Some(left_side_unwrapped)), Ok(Some(right_side_unwrapped))) => {
|
||||
if left_side_unwrapped.get_context_element_reference()
|
||||
< right_side_unwrapped.get_context_element_reference()
|
||||
{
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
} else {
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
DustTag::DTHelperLessThanOrEquals(parameterized_block) => {
|
||||
let new_breadcrumbs = self.new_breadcrumbs_partial(
|
||||
breadcrumbs,
|
||||
breadcrumbs,
|
||||
None,
|
||||
¶meterized_block.explicit_context,
|
||||
);
|
||||
|
||||
let param_map =
|
||||
ParametersContext::new(self, breadcrumbs, ¶meterized_block.params);
|
||||
if !param_map.contains_key("key") {
|
||||
return Ok("".to_owned());
|
||||
}
|
||||
let left_side = param_map
|
||||
.walk("key")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
let right_side = param_map
|
||||
.walk("value")
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs));
|
||||
match (left_side, right_side) {
|
||||
(Ok(Some(left_side_unwrapped)), Ok(Some(right_side_unwrapped))) => {
|
||||
if left_side_unwrapped.get_context_element_reference()
|
||||
<= right_side_unwrapped.get_context_element_reference()
|
||||
{
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
} else {
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
return self.render_maybe_body(
|
||||
¶meterized_block.else_contents,
|
||||
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
|
||||
blocks,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => panic!("Unsupported tag"),
|
||||
}
|
||||
|
||||
Ok("".to_owned())
|
||||
}
|
||||
|
||||
/// Returns a option of a tuple of (parent, new_node_elements)
|
||||
/// which can then be formed into new BreadcrumbTreeNodes
|
||||
///
|
||||
/// If None is returned, then it is a signal to simply re-use the
|
||||
/// existing breadcrumbs.
|
||||
///
|
||||
/// Otherwise, the parent (which may be None, especially for
|
||||
/// explicit contexts) and the additional node elements (which may
|
||||
/// be empty) should be combined into a final BreadcrumbTreeNode
|
||||
fn new_breadcrumbs_section<'b>(
|
||||
&'b self,
|
||||
maybe_breadcrumbs: Option<&'b BreadcrumbTree>,
|
||||
breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
|
||||
index_context: Option<&'b dyn IntoContextElement>,
|
||||
injected_context: Option<&'b dyn IntoContextElement>,
|
||||
explicit_context: &Option<Path<'b>>,
|
||||
new_context_element: Option<&'b dyn ContextElement>,
|
||||
) -> Option<(Option<&'b BreadcrumbTree>, Vec<BreadcrumbTreeElement<'b>>)> {
|
||||
) -> Option<Vec<BreadcrumbTreeElement<'b>>> {
|
||||
// If none of the additional contexts are present, return None
|
||||
// to signal that the original breadcrumbs should be used
|
||||
// rather than incurring a copy here.
|
||||
@ -222,50 +677,40 @@ impl<'a> DustRenderer<'a> {
|
||||
|
||||
// If there is an explicit context, then drop all the current
|
||||
// context
|
||||
let parent = match explicit_context {
|
||||
Some(_) => None,
|
||||
None => maybe_breadcrumbs,
|
||||
let mut new_stack = match explicit_context {
|
||||
Some(_) => Vec::with_capacity(4),
|
||||
None => breadcrumbs.clone(),
|
||||
};
|
||||
let mut new_nodes: Vec<BreadcrumbTreeElement> = Vec::new();
|
||||
|
||||
explicit_context.as_ref().map(|path| {
|
||||
walk_path(maybe_breadcrumbs, &path.keys)
|
||||
.map(|ice| ice.into_context_element(self, maybe_breadcrumbs))
|
||||
walk_path(breadcrumbs, &path.keys)
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs))
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|val| {
|
||||
if val.get_context_element_reference().is_truthy() {
|
||||
new_nodes.push(std::convert::From::from(val))
|
||||
new_stack.push(std::convert::From::from(val))
|
||||
}
|
||||
});
|
||||
});
|
||||
injected_context.map(|ctx| new_nodes.push(BreadcrumbTreeElement::from_borrowed(ctx)));
|
||||
injected_context.map(|ctx| new_stack.push(BreadcrumbTreeElement::from_borrowed(ctx)));
|
||||
new_context_element.map(|ctx| {
|
||||
new_nodes.push(BreadcrumbTreeElement::from_borrowed(
|
||||
new_stack.push(BreadcrumbTreeElement::from_borrowed(
|
||||
ctx.from_context_element(),
|
||||
))
|
||||
});
|
||||
index_context.map(|ctx| new_nodes.push(BreadcrumbTreeElement::from_borrowed(ctx)));
|
||||
index_context.map(|ctx| new_stack.push(BreadcrumbTreeElement::from_borrowed(ctx)));
|
||||
|
||||
Some((parent, new_nodes))
|
||||
Some(new_stack)
|
||||
}
|
||||
|
||||
/// Returns a option of a tuple of (parent, new_node_elements)
|
||||
/// which can then be formed into new BreadcrumbTreeNodes
|
||||
///
|
||||
/// If None is returned, then it is a signal to simply re-use the
|
||||
/// existing breadcrumbs.
|
||||
///
|
||||
/// Otherwise, the parent (which may be None, especially for
|
||||
/// explicit contexts) and the additional node elements (which may
|
||||
/// be empty) should be combined into a final BreadcrumbTreeNode
|
||||
fn new_breadcrumbs_partial<'b>(
|
||||
&'b self,
|
||||
maybe_breadcrumbs: Option<&'b BreadcrumbTree>,
|
||||
explicit_context_maybe_breadcrumbs: Option<&'b BreadcrumbTree>,
|
||||
breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
|
||||
explicit_context_breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
injected_context: Option<&'b dyn IntoContextElement>,
|
||||
explicit_context: &Option<Path<'b>>,
|
||||
) -> Option<(Option<&'b BreadcrumbTree>, Vec<BreadcrumbTreeElement<'b>>)> {
|
||||
) -> Option<Vec<BreadcrumbTreeElement<'b>>> {
|
||||
// If none of the additional contexts are present, return None
|
||||
// to signal that the original breadcrumbs should be used
|
||||
// rather than incurring a copy here.
|
||||
@ -276,11 +721,10 @@ impl<'a> DustRenderer<'a> {
|
||||
|
||||
// If there is an explicit context, then drop all the current
|
||||
// context
|
||||
let mut parent = match explicit_context {
|
||||
Some(_) => None,
|
||||
None => maybe_breadcrumbs,
|
||||
let mut new_stack = match explicit_context {
|
||||
Some(_) => Vec::with_capacity(3),
|
||||
None => breadcrumbs.clone(),
|
||||
};
|
||||
let mut new_nodes: Vec<BreadcrumbTreeElement> = Vec::new();
|
||||
|
||||
injected_context.map(|ctx| {
|
||||
// Special case: when there is no explicit context, the
|
||||
@ -289,56 +733,69 @@ impl<'a> DustRenderer<'a> {
|
||||
// added after the current context but before the explicit
|
||||
// context.
|
||||
match explicit_context {
|
||||
None => {
|
||||
let (new_parent, passed_nodes) =
|
||||
Self::split_tree_at_predicate(parent, |b| b.get_ice().is_pseudo_element());
|
||||
parent = new_parent;
|
||||
new_nodes.extend(passed_nodes.iter().map(|b| b.get_element().clone()));
|
||||
}
|
||||
_ => new_nodes.push(BreadcrumbTreeElement::from_borrowed(ctx)),
|
||||
None => new_stack.insert(
|
||||
Self::get_index_of_first_non_pseudo_element(&new_stack).unwrap_or(0),
|
||||
BreadcrumbTreeElement::from_borrowed(ctx),
|
||||
),
|
||||
_ => new_stack.push(BreadcrumbTreeElement::from_borrowed(ctx)),
|
||||
}
|
||||
});
|
||||
|
||||
explicit_context.as_ref().map(|path| {
|
||||
// TODO: should resolving the value here use
|
||||
// explicit_context_maybe_breadcrumbs or
|
||||
// maybe_breadcrumbs?
|
||||
walk_path(explicit_context_maybe_breadcrumbs, &path.keys)
|
||||
.map(|ice| ice.into_context_element(self, maybe_breadcrumbs))
|
||||
walk_path(explicit_context_breadcrumbs, &path.keys)
|
||||
.map(|ice| ice.into_context_element(self, breadcrumbs))
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|val| {
|
||||
if val.get_context_element_reference().is_truthy() {
|
||||
new_nodes.push(std::convert::From::from(val));
|
||||
new_stack.push(std::convert::From::from(val));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Some((parent, new_nodes))
|
||||
Some(new_stack)
|
||||
}
|
||||
|
||||
/// Returns a Breadcrumb tree where all the bottom nodes that do
|
||||
/// not match the predicate and the first node that match the
|
||||
/// predicate are shaved off, and a list of those nodes that are
|
||||
/// shaved off.
|
||||
fn split_tree_at_predicate<'b, F>(
|
||||
maybe_breadcrumbs: Option<&'b BreadcrumbTree>,
|
||||
f: F,
|
||||
) -> (Option<&'b BreadcrumbTree<'b>>, Vec<&'b BreadcrumbTree<'b>>)
|
||||
where
|
||||
F: Fn(&'b BreadcrumbTree) -> bool,
|
||||
{
|
||||
match maybe_breadcrumbs {
|
||||
None => return (None, Vec::new()),
|
||||
Some(breadcrumbs) => {
|
||||
let mut passed_nodes: Vec<&'b BreadcrumbTree<'b>> = Vec::new();
|
||||
for tree_node in breadcrumbs {
|
||||
passed_nodes.push(tree_node);
|
||||
if f(tree_node) {
|
||||
return (tree_node.get_parent(), passed_nodes);
|
||||
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,
|
||||
},
|
||||
}
|
||||
}
|
||||
return (None, passed_nodes);
|
||||
}
|
||||
|
||||
fn new_are_paths_identical<'b>(
|
||||
left_side: &Result<Option<IceResult<'b>>, WalkError>,
|
||||
right_side: &Result<Option<IceResult<'b>>, WalkError>,
|
||||
) -> bool {
|
||||
let left_resolved = left_side.as_ref().map(|maybe_ice| {
|
||||
maybe_ice
|
||||
.as_ref()
|
||||
.map(|ice| ice.get_context_element_reference())
|
||||
});
|
||||
let right_resolved = right_side.as_ref().map(|maybe_ice| {
|
||||
maybe_ice
|
||||
.as_ref()
|
||||
.map(|ice| ice.get_context_element_reference())
|
||||
});
|
||||
match (left_resolved, right_resolved) {
|
||||
(Ok(Some(lce)), Ok(Some(rce))) => lce as *const _ == rce as *const _,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,10 +813,18 @@ impl<'a> DustRenderer<'a> {
|
||||
}
|
||||
final_filters
|
||||
}
|
||||
|
||||
fn get_index_of_first_non_pseudo_element<'b>(
|
||||
breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
|
||||
) -> Option<usize> {
|
||||
breadcrumbs.iter().rposition(|b| {
|
||||
!std::borrow::Borrow::<dyn IntoContextElement + 'b>::borrow(b).is_pseudo_element()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct BlockContext<'a> {
|
||||
/// The breadcrumbs at the time of entering the current partial
|
||||
breadcrumbs: Option<&'a BreadcrumbTree<'a>>,
|
||||
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
blocks: &'a InlinePartialTreeElement<'a>,
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::renderer::breadcrumb_tree::BreadcrumbTree;
|
||||
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
|
||||
use crate::renderer::context_element::IntoContextElement;
|
||||
use crate::renderer::WalkError;
|
||||
use std::borrow::Borrow;
|
||||
@ -38,30 +38,33 @@ where
|
||||
}
|
||||
|
||||
fn get_first_non_pseudo_element<'a>(
|
||||
breadcrumbs: &'a BreadcrumbTree,
|
||||
) -> Option<&'a BreadcrumbTree<'a>> {
|
||||
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
) -> Option<&'a BreadcrumbTreeElement<'a>> {
|
||||
breadcrumbs
|
||||
.breadcrumb_iter()
|
||||
.filter(|b| b.get_ice().is_pseudo_element())
|
||||
.iter()
|
||||
.rev()
|
||||
.filter(|b| {
|
||||
!std::borrow::Borrow::<dyn IntoContextElement + 'a>::borrow(*b).is_pseudo_element()
|
||||
})
|
||||
.next()
|
||||
}
|
||||
|
||||
pub fn walk_path<'a, P>(
|
||||
maybe_breadcrumbs: Option<&'a BreadcrumbTree>,
|
||||
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||
path: &Vec<P>,
|
||||
) -> Result<&'a dyn IntoContextElement, WalkError>
|
||||
where
|
||||
P: Borrow<str>,
|
||||
{
|
||||
match (maybe_breadcrumbs, path.first()) {
|
||||
match (breadcrumbs.last(), path.first()) {
|
||||
(None, _) => return Err(WalkError::CantWalk),
|
||||
(Some(breadcrumbs), None) => return Ok(breadcrumbs.get_ice()),
|
||||
(Some(breadcrumbs), Some(path_first)) if path_first.borrow() == "." => {
|
||||
(Some(last_elem), None) => return Ok(last_elem.borrow()),
|
||||
(Some(_), Some(path_first)) if path_first.borrow() == "." => {
|
||||
let first_non_pseudo_element = get_first_non_pseudo_element(breadcrumbs);
|
||||
return match first_non_pseudo_element {
|
||||
None => Err(WalkError::CantWalk),
|
||||
Some(current_context) => {
|
||||
match walk_path_from_single_level(current_context.get_ice(), &path[1..]) {
|
||||
match walk_path_from_single_level(current_context.borrow(), &path[1..]) {
|
||||
// If no walking was done at all or we partially walked
|
||||
// then stop trying to find anything because '.' restricts
|
||||
// us to the current scope
|
||||
@ -71,9 +74,9 @@ where
|
||||
}
|
||||
};
|
||||
}
|
||||
(Some(breadcrumbs), Some(path_first)) => {
|
||||
for context in breadcrumbs.ice_iter() {
|
||||
match walk_path_from_single_level(context, path) {
|
||||
(Some(_), Some(path_first)) => {
|
||||
for context in breadcrumbs.iter().rev() {
|
||||
match walk_path_from_single_level(context.borrow(), path) {
|
||||
// If no walking was done at all, keep looping
|
||||
WalkResult::NoWalk => {}
|
||||
// If we partially walked then stop trying to find
|
||||
|
Loading…
x
Reference in New Issue
Block a user