Update IterationContext to be an IntoContextElement and finish implementing section.

This commit is contained in:
Tom Alexander 2020-06-06 23:08:21 -04:00
parent 00699b84ba
commit e28ebaf26a
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
3 changed files with 102 additions and 52 deletions

View File

@ -1,6 +1,9 @@
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
use crate::renderer::context_element::CompareContextElement; use crate::renderer::context_element::CompareContextElement;
use crate::renderer::context_element::ContextElement; use crate::renderer::context_element::ContextElement;
use crate::renderer::context_element::IceResult;
use crate::renderer::context_element::IntoContextElement; use crate::renderer::context_element::IntoContextElement;
use crate::renderer::DustRenderer;
use crate::renderer::Loopable; use crate::renderer::Loopable;
use crate::renderer::RenderError; use crate::renderer::RenderError;
use crate::renderer::Renderable; use crate::renderer::Renderable;
@ -16,7 +19,7 @@ use std::cmp::Ordering;
/// Functions the same as the injected parameters contexts for /// Functions the same as the injected parameters contexts for
/// helpers/partials with parameters but this has no need for storing /// helpers/partials with parameters but this has no need for storing
/// breadcrumbs since its simply storing two integers. /// breadcrumbs since its simply storing two integers.
#[derive(Debug, Clone)] #[derive(Debug)]
pub struct IterationContext { pub struct IterationContext {
idx: OwnedLiteral, idx: OwnedLiteral,
len: OwnedLiteral, len: OwnedLiteral,
@ -32,32 +35,13 @@ impl IterationContext {
} }
} }
impl ContextElement for IterationContext {} impl IntoContextElement for IterationContext {
fn into_context_element<'b>(
impl Truthiness for IterationContext { &'b self,
fn is_truthy(&self) -> bool { renderer: &DustRenderer,
// TODO: Would this even ever be called? Won't matter, but I'd breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
// like to know. Since it is injected 1 above the current ) -> Option<IceResult<'b>> {
// context, we wouldn't be able to access it with `{.}`. panic!("into_context_element cannot be called on pseudo elements");
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()
} }
} }
@ -74,15 +58,3 @@ impl Walkable for IterationContext {
true 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
}
}

View File

@ -4,7 +4,7 @@ mod breadcrumb_tree;
mod context_element; mod context_element;
mod errors; mod errors;
mod inline_partial_tree; mod inline_partial_tree;
// mod iteration_context; mod iteration_context;
mod parameters_context; mod parameters_context;
mod renderer; mod renderer;
mod tree_walking; mod tree_walking;

View File

@ -15,6 +15,7 @@ use crate::renderer::errors::RenderError;
use crate::renderer::errors::WalkError; use crate::renderer::errors::WalkError;
use crate::renderer::inline_partial_tree::extract_inline_partials; use crate::renderer::inline_partial_tree::extract_inline_partials;
use crate::renderer::inline_partial_tree::InlinePartialTreeElement; use crate::renderer::inline_partial_tree::InlinePartialTreeElement;
use crate::renderer::iteration_context::IterationContext;
use crate::renderer::parameters_context::ParametersContext; use crate::renderer::parameters_context::ParametersContext;
use crate::renderer::tree_walking::walk_path; use crate::renderer::tree_walking::walk_path;
use std::borrow::Borrow; use std::borrow::Borrow;
@ -170,8 +171,7 @@ impl<'a> DustRenderer<'a> {
let val = walk_path(breadcrumbs, &container.path.keys) let val = walk_path(breadcrumbs, &container.path.keys)
.map(|ice| ice.into_context_element(self, breadcrumbs)); .map(|ice| ice.into_context_element(self, breadcrumbs));
match val { match val {
Err(WalkError::CantWalk) => { Err(WalkError::CantWalk) | Ok(None) => {
// TODO
let new_breadcrumbs = self.new_breadcrumbs_section( let new_breadcrumbs = self.new_breadcrumbs_section(
breadcrumbs, breadcrumbs,
None, None,
@ -179,9 +179,84 @@ impl<'a> DustRenderer<'a> {
&container.explicit_context, &container.explicit_context,
None, None,
); );
return self.render_maybe_body(
&container.else_contents,
new_breadcrumbs.as_ref().unwrap_or(breadcrumbs),
blocks,
);
} }
Ok(final_val) => { Ok(Some(final_val)) => {
// TODO 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,
)
};
} }
} }
} }
@ -247,7 +322,6 @@ impl<'a> DustRenderer<'a> {
injected_context: Option<&'b dyn IntoContextElement>, injected_context: Option<&'b dyn IntoContextElement>,
explicit_context: &Option<Path<'b>>, explicit_context: &Option<Path<'b>>,
) -> Option<Vec<BreadcrumbTreeElement<'b>>> { ) -> Option<Vec<BreadcrumbTreeElement<'b>>> {
// If none of the additional contexts are present, return None // If none of the additional contexts are present, return None
// to signal that the original breadcrumbs should be used // to signal that the original breadcrumbs should be used
// rather than incurring a copy here. // rather than incurring a copy here.
@ -270,8 +344,11 @@ impl<'a> DustRenderer<'a> {
// added after the current context but before the explicit // added after the current context but before the explicit
// context. // context.
match explicit_context { match explicit_context {
None => new_stack.insert(Self::get_index_of_first_non_pseudo_element(&new_stack).unwrap_or(0), BreadcrumbTreeElement::from_borrowed(ctx)), None => new_stack.insert(
_ => new_stack.push(BreadcrumbTreeElement::from_borrowed(ctx)) Self::get_index_of_first_non_pseudo_element(&new_stack).unwrap_or(0),
BreadcrumbTreeElement::from_borrowed(ctx),
),
_ => new_stack.push(BreadcrumbTreeElement::from_borrowed(ctx)),
} }
}); });
@ -308,11 +385,12 @@ impl<'a> DustRenderer<'a> {
final_filters final_filters
} }
fn get_index_of_first_non_pseudo_element<'b>(breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>) -> Option<usize> fn get_index_of_first_non_pseudo_element<'b>(
{ breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
breadcrumbs ) -> Option<usize> {
.iter() breadcrumbs.iter().rposition(|b| {
.rposition(|b| std::borrow::Borrow::<dyn IntoContextElement + 'b>::borrow(b).is_pseudo_element()) std::borrow::Borrow::<dyn IntoContextElement + 'b>::borrow(b).is_pseudo_element()
})
} }
} }