Initial implementation combining owned_walk_path and walk_path. Works everywhere except one spot.

This commit is contained in:
Tom Alexander 2020-05-24 14:56:09 -04:00
parent a58b605e59
commit 4790ac77d6
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
3 changed files with 85 additions and 9 deletions

View File

@ -2,7 +2,7 @@ use crate::parser::KVPair;
use crate::parser::{Filter, OwnedLiteral, RValue}; use crate::parser::{Filter, OwnedLiteral, RValue};
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::walking::owned_walk_path; use crate::renderer::walking::walk_path_combined;
use crate::renderer::Loopable; use crate::renderer::Loopable;
use crate::renderer::RenderError; use crate::renderer::RenderError;
use crate::renderer::Renderable; use crate::renderer::Renderable;
@ -89,7 +89,7 @@ impl Walkable for ParametersContext {
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> { fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> {
let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?; let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?;
match rval { match rval {
OwnedRValue::RVPath(path) => owned_walk_path(&self.breadcrumbs, &path.keys), OwnedRValue::RVPath(path) => walk_path_combined(&self.breadcrumbs, &path.keys),
OwnedRValue::RVLiteral(literal) => Ok(literal), OwnedRValue::RVLiteral(literal) => Ok(literal),
} }
} }

View File

@ -15,6 +15,7 @@ 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::parameters_context::ParametersContext; use crate::renderer::parameters_context::ParametersContext;
use crate::renderer::walking::walk_path; use crate::renderer::walking::walk_path;
use crate::renderer::walking::walk_path_combined;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -146,7 +147,7 @@ impl<'a> DustRenderer<'a> {
} }
DustTag::DTLiteralStringBlock(literal) => return Ok((*literal).to_owned()), DustTag::DTLiteralStringBlock(literal) => return Ok((*literal).to_owned()),
DustTag::DTReference(reference) => { DustTag::DTReference(reference) => {
let val = walk_path(breadcrumbs, &reference.path.keys); let val = walk_path_combined(breadcrumbs, &reference.path.keys);
match val { match val {
Err(WalkError::CantWalk) => return Ok("".to_owned()), Err(WalkError::CantWalk) => return Ok("".to_owned()),
Ok(final_val) => { Ok(final_val) => {
@ -160,7 +161,7 @@ impl<'a> DustRenderer<'a> {
} }
} }
DustTag::DTSection(container) => { DustTag::DTSection(container) => {
let val = walk_path(breadcrumbs, &container.path.keys); let val = walk_path_combined(breadcrumbs, &container.path.keys);
let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val); let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
if loop_elements.is_empty() { if loop_elements.is_empty() {
// Oddly enough if the value is falsey (like // Oddly enough if the value is falsey (like
@ -187,7 +188,7 @@ impl<'a> DustRenderer<'a> {
} }
} }
DustTag::DTExists(container) => { DustTag::DTExists(container) => {
let val = walk_path(breadcrumbs, &container.path.keys); let val = walk_path_combined(breadcrumbs, &container.path.keys);
let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val); let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
return if loop_elements.is_empty() { return if loop_elements.is_empty() {
self.render_maybe_body(&container.else_contents, breadcrumbs, blocks) self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
@ -196,7 +197,7 @@ impl<'a> DustRenderer<'a> {
}; };
} }
DustTag::DTNotExists(container) => { DustTag::DTNotExists(container) => {
let val = walk_path(breadcrumbs, &container.path.keys); let val = walk_path_combined(breadcrumbs, &container.path.keys);
let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val); let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
return if !loop_elements.is_empty() { return if !loop_elements.is_empty() {
self.render_maybe_body(&container.else_contents, breadcrumbs, blocks) self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
@ -682,14 +683,14 @@ mod tests {
.collect(); .collect();
assert_eq!( assert_eq!(
walk_path(&vec![&context as &dyn ContextElement], &vec!["cat"]) walk_path_combined(&vec![&context as &dyn ContextElement], &vec!["cat"])
.unwrap() .unwrap()
.render(&Vec::new()) .render(&Vec::new())
.unwrap(), .unwrap(),
"kitty".to_owned() "kitty".to_owned()
); );
assert_eq!( assert_eq!(
walk_path( walk_path_combined(
&vec![&number_context as &dyn ContextElement], &vec![&number_context as &dyn ContextElement],
&vec!["tiger"] &vec!["tiger"]
) )
@ -699,7 +700,7 @@ mod tests {
"3".to_owned() "3".to_owned()
); );
assert_eq!( assert_eq!(
walk_path( walk_path_combined(
&vec![&deep_context as &dyn ContextElement], &vec![&deep_context as &dyn ContextElement],
&vec!["tiger", "food"] &vec!["tiger", "food"]
) )

View File

@ -1,5 +1,6 @@
use crate::renderer::context_element::ContextElement; use crate::renderer::context_element::ContextElement;
use crate::renderer::WalkError; use crate::renderer::WalkError;
use std::borrow::Borrow;
enum WalkResult<'a> { enum WalkResult<'a> {
NoWalk, NoWalk,
@ -32,6 +33,80 @@ fn walk_path_from_single_level<'a>(
WalkResult::FullyWalked(output) WalkResult::FullyWalked(output)
} }
fn walk_path_from_single_level_borrow<'a, P, C>(context: &'a C, path: &[P]) -> WalkResult<'a>
where
P: Borrow<str>,
C: Borrow<dyn ContextElement + 'a>,
{
if path.is_empty() {
return WalkResult::FullyWalked(context.borrow());
}
let mut walk_failure = WalkResult::NoWalk;
let mut output = context.borrow();
for elem in path.iter() {
match output.borrow().walk(elem.borrow()) {
Err(WalkError::CantWalk { .. }) => {
return walk_failure;
}
Ok(new_val) => {
walk_failure = WalkResult::PartialWalk;
output = new_val;
}
}
}
WalkResult::FullyWalked(output)
}
pub fn walk_path_combined<'a, B, P>(
breadcrumbs: &'a Vec<B>,
path: &Vec<P>,
) -> Result<&'a dyn ContextElement, WalkError>
where
B: Borrow<dyn ContextElement + 'a>,
P: Borrow<str>,
{
if path.is_empty() {
return Ok(breadcrumbs
.last()
.expect("Breadcrumbs should never be empty.")
.borrow());
}
if path
.first()
.expect("Already proved path is not empty")
.borrow()
== "."
{
return match walk_path_from_single_level_borrow(
breadcrumbs
.last()
.expect("Breadcrumbs should never be empty"),
&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
WalkResult::NoWalk | WalkResult::PartialWalk => Err(WalkError::CantWalk),
WalkResult::FullyWalked(new_context) => Ok(new_context),
};
}
for context in breadcrumbs.iter().rev() {
match walk_path_from_single_level_borrow(context, path) {
// 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)
}
pub fn walk_path<'a>( pub fn walk_path<'a>(
breadcrumbs: &Vec<&'a dyn ContextElement>, breadcrumbs: &Vec<&'a dyn ContextElement>,
path: &'a Vec<&str>, path: &'a Vec<&str>,