diff --git a/src/renderer/iteration_context.rs b/src/renderer/iteration_context.rs index 9830137..687fb71 100644 --- a/src/renderer/iteration_context.rs +++ b/src/renderer/iteration_context.rs @@ -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) -> 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 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>, + ) -> Option> { + 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 { - // TODO: Does this ever happen? perhaps I should have a panic here. - None - } -} diff --git a/src/renderer/mod.rs b/src/renderer/mod.rs index 6baa196..11f75f8 100644 --- a/src/renderer/mod.rs +++ b/src/renderer/mod.rs @@ -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; diff --git a/src/renderer/renderer.rs b/src/renderer/renderer.rs index adb17c5..0506c0b 100644 --- a/src/renderer/renderer.rs +++ b/src/renderer/renderer.rs @@ -15,6 +15,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::iteration_context::IterationContext; use crate::renderer::parameters_context::ParametersContext; use crate::renderer::tree_walking::walk_path; use std::borrow::Borrow; @@ -170,8 +171,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,9 +179,84 @@ 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, 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>, explicit_context: &Option>, ) -> Option>> { - // 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. @@ -270,8 +344,11 @@ impl<'a> DustRenderer<'a> { // added after the current context but before the 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)), - _ => new_stack.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)), } }); @@ -308,11 +385,12 @@ impl<'a> DustRenderer<'a> { final_filters } - fn get_index_of_first_non_pseudo_element<'b>(breadcrumbs: &'b Vec>) -> Option - { - breadcrumbs - .iter() - .rposition(|b| std::borrow::Borrow::::borrow(b).is_pseudo_element()) + fn get_index_of_first_non_pseudo_element<'b>( + breadcrumbs: &'b Vec>, + ) -> Option { + breadcrumbs.iter().rposition(|b| { + std::borrow::Borrow::::borrow(b).is_pseudo_element() + }) } }