Switching back to a Vec because inserting multiple elements into the linked list structure while maintaining ownership of each node proved to be difficult.

This commit is contained in:
Tom Alexander 2020-06-06 22:24:27 -04:00
parent 78bffb5f04
commit 71592a9a32
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
5 changed files with 50 additions and 142 deletions

View File

@ -5,11 +5,6 @@ use crate::renderer::context_element::IntoRcIce;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::rc::Rc; use std::rc::Rc;
pub struct BreadcrumbTree<'a> {
parent: Option<&'a BreadcrumbTree<'a>>,
element: BreadcrumbTreeElement<'a>,
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum BreadcrumbTreeElement<'a> { pub enum BreadcrumbTreeElement<'a> {
// Using Rc so that when we need to create BreadcrumbTrees with // 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> { impl<'a> Borrow<dyn IntoContextElement + 'a> for BreadcrumbTreeElement<'a> {
fn borrow(&self) -> &(dyn IntoContextElement + 'a) { fn borrow(&self) -> &(dyn IntoContextElement + 'a) {
match self { 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
}
}

View File

@ -1,5 +1,5 @@
use crate::parser::Filter; 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::RenderError;
use crate::renderer::errors::WalkError; use crate::renderer::errors::WalkError;
use crate::renderer::DustRenderer; use crate::renderer::DustRenderer;
@ -106,7 +106,7 @@ pub trait IntoContextElement: Debug + Walkable /* + CloneIntoBoxedContextElement
fn into_context_element<'a>( fn into_context_element<'a>(
&'a self, &'a self,
renderer: &DustRenderer, renderer: &DustRenderer,
breadcrumbs: Option<&'a BreadcrumbTree<'a>>, breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
) -> Option<IceResult<'a>>; ) -> Option<IceResult<'a>>;
} }
@ -114,7 +114,7 @@ impl<C: ContextElement> IntoContextElement for C {
fn into_context_element<'a>( fn into_context_element<'a>(
&'a self, &'a self,
renderer: &DustRenderer, renderer: &DustRenderer,
breadcrumbs: Option<&'a BreadcrumbTree<'a>>, breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
) -> Option<IceResult<'a>> { ) -> Option<IceResult<'a>> {
Some(IceResult::from_borrowed(self)) Some(IceResult::from_borrowed(self))
} }
@ -161,7 +161,7 @@ impl<'a> IntoContextElement for IceResult<'a> {
fn into_context_element<'b>( fn into_context_element<'b>(
&'b self, &'b self,
renderer: &DustRenderer, renderer: &DustRenderer,
breadcrumbs: Option<&'b BreadcrumbTree<'b>>, breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
) -> Option<IceResult<'b>> { ) -> Option<IceResult<'b>> {
match self { match self {
IceResult::Owned(rc_ce) => Some(IceResult::from_borrowed(rc_ce.as_ref())), IceResult::Owned(rc_ce) => Some(IceResult::from_borrowed(rc_ce.as_ref())),

View File

@ -2,7 +2,6 @@ use crate::parser::Filter;
use crate::parser::KVPair; use crate::parser::KVPair;
use crate::parser::OwnedLiteral; use crate::parser::OwnedLiteral;
use crate::parser::RValue; use crate::parser::RValue;
use crate::renderer::breadcrumb_tree::BreadcrumbTree;
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement; 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;
@ -29,7 +28,7 @@ pub struct ParametersContext<'a> {
impl<'a> ParametersContext<'a> { impl<'a> ParametersContext<'a> {
pub fn new( pub fn new(
renderer: &DustRenderer, renderer: &DustRenderer,
breadcrumbs: Option<&'a BreadcrumbTree>, breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
params: &'a Vec<KVPair>, params: &'a Vec<KVPair>,
) -> Self { ) -> Self {
// If the parameter is a Path, then we resolve it immediately // If the parameter is a Path, then we resolve it immediately
@ -72,7 +71,7 @@ impl<'a> IntoContextElement for ParametersContext<'a> {
fn into_context_element<'b>( fn into_context_element<'b>(
&'b self, &'b self,
renderer: &DustRenderer, renderer: &DustRenderer,
breadcrumbs: Option<&'b BreadcrumbTree<'b>>, breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
) -> Option<IceResult<'b>> { ) -> Option<IceResult<'b>> {
panic!("into_context_element cannot be called on pseudo elements"); panic!("into_context_element cannot be called on pseudo elements");
} }
@ -95,7 +94,7 @@ impl<'a> IntoContextElement for RValue<'a> {
fn into_context_element<'b>( fn into_context_element<'b>(
&'b self, &'b self,
renderer: &DustRenderer, renderer: &DustRenderer,
breadcrumbs: Option<&'b BreadcrumbTree<'b>>, breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
) -> Option<IceResult<'b>> { ) -> Option<IceResult<'b>> {
match self { match self {
RValue::RVLiteral(owned_literal) => Some(IceResult::from_borrowed(owned_literal)), RValue::RVLiteral(owned_literal) => Some(IceResult::from_borrowed(owned_literal)),

View File

@ -7,7 +7,6 @@ use crate::parser::Path;
use crate::parser::Special; use crate::parser::Special;
use crate::parser::Template; use crate::parser::Template;
use crate::parser::TemplateElement; use crate::parser::TemplateElement;
use crate::renderer::breadcrumb_tree::BreadcrumbTree;
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement; use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
use crate::renderer::context_element::ContextElement; use crate::renderer::context_element::ContextElement;
use crate::renderer::context_element::IntoContextElement; use crate::renderer::context_element::IntoContextElement;
@ -49,15 +48,16 @@ impl<'a> DustRenderer<'a> {
where where
C: IntoContextElement, C: IntoContextElement,
{ {
let breadcrumbs = let breadcrumbs = context
context.map(|ctx| BreadcrumbTree::new(None, BreadcrumbTreeElement::from_borrowed(ctx))); .map(|ctx| vec![BreadcrumbTreeElement::from_borrowed(ctx)])
.unwrap_or(Vec::new());
self.render_template(name, breadcrumbs.as_ref(), None) self.render_template(name, breadcrumbs.as_ref(), None)
} }
pub fn render_template( pub fn render_template(
&'a self, &'a self,
name: &str, name: &str,
breadcrumbs: Option<&'a BreadcrumbTree>, breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
blocks: Option<&'a InlinePartialTreeElement<'a>>, blocks: Option<&'a InlinePartialTreeElement<'a>>,
) -> Result<String, RenderError> { ) -> Result<String, RenderError> {
let main_template = match self.templates.get(name) { let main_template = match self.templates.get(name) {
@ -78,7 +78,7 @@ impl<'a> DustRenderer<'a> {
fn render_maybe_body( fn render_maybe_body(
&'a self, &'a self,
body: &'a Option<Body>, body: &'a Option<Body>,
breadcrumbs: Option<&'a BreadcrumbTree>, breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
blocks: &'a BlockContext<'a>, blocks: &'a BlockContext<'a>,
) -> Result<String, RenderError> { ) -> Result<String, RenderError> {
match body { match body {
@ -90,7 +90,7 @@ impl<'a> DustRenderer<'a> {
fn render_body( fn render_body(
&'a self, &'a self,
body: &'a Body, body: &'a Body,
breadcrumbs: Option<&'a BreadcrumbTree>, breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
blocks: &'a BlockContext<'a>, blocks: &'a BlockContext<'a>,
) -> Result<String, RenderError> { ) -> Result<String, RenderError> {
let mut output = String::new(); let mut output = String::new();
@ -110,7 +110,7 @@ impl<'a> DustRenderer<'a> {
pub fn render_partial_name( pub fn render_partial_name(
&'a self, &'a self,
body: &'a Vec<PartialNameElement>, body: &'a Vec<PartialNameElement>,
breadcrumbs: Option<&'a BreadcrumbTree>, breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
) -> Result<String, RenderError> { ) -> Result<String, RenderError> {
let converted_to_template_elements: Vec<TemplateElement<'a>> = let converted_to_template_elements: Vec<TemplateElement<'a>> =
body.into_iter().map(|e| e.into()).collect(); body.into_iter().map(|e| e.into()).collect();
@ -118,7 +118,7 @@ impl<'a> DustRenderer<'a> {
// cannot contain blocks or inline partials, so we use a blank // cannot contain blocks or inline partials, so we use a blank
// BlockContext. // BlockContext.
let empty_block_context = BlockContext { let empty_block_context = BlockContext {
breadcrumbs: None, breadcrumbs: &Vec::new(),
blocks: &InlinePartialTreeElement::new(None, HashMap::new()), blocks: &InlinePartialTreeElement::new(None, HashMap::new()),
}; };
self.render_body( self.render_body(
@ -133,7 +133,7 @@ impl<'a> DustRenderer<'a> {
fn render_tag( fn render_tag(
&'a self, &'a self,
tag: &'a DustTag, tag: &'a DustTag,
breadcrumbs: Option<&'a BreadcrumbTree>, breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
blocks: &'a BlockContext<'a>, blocks: &'a BlockContext<'a>,
) -> Result<String, RenderError> { ) -> Result<String, RenderError> {
match tag { match tag {
@ -190,23 +190,15 @@ impl<'a> DustRenderer<'a> {
Ok("".to_owned()) 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>( fn new_breadcrumbs_section<'b>(
&'b self, &'b self,
maybe_breadcrumbs: Option<&'b BreadcrumbTree>, maybe_breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
index_context: Option<&'b dyn IntoContextElement>, index_context: Option<&'b dyn IntoContextElement>,
injected_context: Option<&'b dyn IntoContextElement>, injected_context: Option<&'b dyn IntoContextElement>,
explicit_context: &Option<Path<'b>>, explicit_context: &Option<Path<'b>>,
new_context_element: Option<&'b dyn ContextElement>, new_context_element: Option<&'b dyn ContextElement>,
) -> Option<(Option<&'b BreadcrumbTree>, 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.
@ -248,24 +240,18 @@ impl<'a> DustRenderer<'a> {
index_context.map(|ctx| new_nodes.push(BreadcrumbTreeElement::from_borrowed(ctx))); index_context.map(|ctx| new_nodes.push(BreadcrumbTreeElement::from_borrowed(ctx)));
Some((parent, new_nodes)) Some((parent, new_nodes))
*/
todo!()
} }
/// 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>( fn new_breadcrumbs_partial<'b>(
&'b self, &'b self,
maybe_breadcrumbs: Option<&'b BreadcrumbTree>, maybe_breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
explicit_context_maybe_breadcrumbs: Option<&'b BreadcrumbTree>, explicit_context_maybe_breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
injected_context: Option<&'b dyn IntoContextElement>, injected_context: Option<&'b dyn IntoContextElement>,
explicit_context: &Option<Path<'b>>, explicit_context: &Option<Path<'b>>,
) -> Option<(Option<&'b BreadcrumbTree>, 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.
@ -313,33 +299,8 @@ impl<'a> DustRenderer<'a> {
}); });
}); });
Some((parent, new_nodes)) Some((parent, new_nodes))*/
} todo!()
/// 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);
}
}
return (None, passed_nodes);
}
}
} }
fn preprocess_filters(filters: &Vec<Filter>) -> Vec<Filter> { fn preprocess_filters(filters: &Vec<Filter>) -> Vec<Filter> {
@ -360,6 +321,6 @@ impl<'a> DustRenderer<'a> {
struct BlockContext<'a> { struct BlockContext<'a> {
/// The breadcrumbs at the time of entering the current partial /// The breadcrumbs at the time of entering the current partial
breadcrumbs: Option<&'a BreadcrumbTree<'a>>, breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
blocks: &'a InlinePartialTreeElement<'a>, blocks: &'a InlinePartialTreeElement<'a>,
} }

View File

@ -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::context_element::IntoContextElement;
use crate::renderer::WalkError; use crate::renderer::WalkError;
use std::borrow::Borrow; use std::borrow::Borrow;
@ -38,25 +38,34 @@ where
} }
fn get_first_non_pseudo_element<'a>( fn get_first_non_pseudo_element<'a>(
breadcrumbs: &'a BreadcrumbTree, breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
) -> Option<&'a BreadcrumbTree<'a>> { ) -> Option<&'a BreadcrumbTreeElement<'a>> {
breadcrumbs breadcrumbs
.breadcrumb_iter() .iter()
.filter(|b| b.get_ice().is_pseudo_element()) .rev()
.filter(|b| {
std::borrow::Borrow::<dyn IntoContextElement + 'a>::borrow(*b).is_pseudo_element()
})
.next() .next()
} }
pub fn walk_path<'a, P>( pub fn walk_path<'a, P>(
maybe_breadcrumbs: Option<&'a BreadcrumbTree>, breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
path: &Vec<P>, path: &Vec<P>,
) -> Result<&'a dyn IntoContextElement, WalkError> ) -> Result<&'a dyn IntoContextElement, WalkError>
where where
P: Borrow<str>, P: Borrow<str>,
{ {
match (maybe_breadcrumbs, path.first()) { /*
(None, _) => return Err(WalkError::CantWalk), match (breadcrumbs.is_empty(), path.first()) {
(Some(breadcrumbs), None) => return Ok(breadcrumbs.get_ice()), (true, _) => return Err(WalkError::CantWalk),
(Some(breadcrumbs), Some(path_first)) if path_first.borrow() == "." => { (false, None) => {
return breadcrumbs
.last()
.map(|bte| bte.borrow())
.ok_or(WalkError::CantWalk)
}
(false, Some(path_first)) if path_first.borrow() == "." => {
let first_non_pseudo_element = get_first_non_pseudo_element(breadcrumbs); let first_non_pseudo_element = get_first_non_pseudo_element(breadcrumbs);
return match first_non_pseudo_element { return match first_non_pseudo_element {
None => Err(WalkError::CantWalk), None => Err(WalkError::CantWalk),
@ -71,7 +80,7 @@ where
} }
}; };
} }
(Some(breadcrumbs), Some(path_first)) => { (false, Some(path_first)) => {
for context in breadcrumbs.ice_iter() { for context in breadcrumbs.ice_iter() {
match walk_path_from_single_level(context, path) { match walk_path_from_single_level(context, path) {
// If no walking was done at all, keep looping // If no walking was done at all, keep looping
@ -88,4 +97,6 @@ where
} }
Err(WalkError::CantWalk) Err(WalkError::CantWalk)
*/
todo!()
} }