@ -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 ,
& parameterized_block . explicit_context ,
) ;
let param_map =
ParametersContext ::new ( self , breadcrumbs , & parameterized_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 (
& parameterized_block . contents ,
new_breadcrumbs . as_ref ( ) . unwrap_or ( breadcrumbs ) ,
blocks ,
) ;
} else {
return self . render_maybe_body (
& parameterized_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 ,
& parameterized_block . explicit_context ,
) ;
let param_map =
ParametersContext ::new ( self , breadcrumbs , & parameterized_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 (
& parameterized_block . else_contents ,
new_breadcrumbs . as_ref ( ) . unwrap_or ( breadcrumbs ) ,
blocks ,
) ;
} else {
return self . render_maybe_body (
& parameterized_block . contents ,
new_breadcrumbs . as_ref ( ) . unwrap_or ( breadcrumbs ) ,
blocks ,
) ;
}
}
DustTag ::DTHelperGreaterThan ( parameterized_block ) = > {
let new_breadcrumbs = self . new_breadcrumbs_partial (
breadcrumbs ,
breadcrumbs ,
None ,
& parameterized_block . explicit_context ,
) ;
let param_map =
ParametersContext ::new ( self , breadcrumbs , & parameterized_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 (
& parameterized_block . contents ,
new_breadcrumbs . as_ref ( ) . unwrap_or ( breadcrumbs ) ,
blocks ,
) ;
} else {
return self . render_maybe_body (
& parameterized_block . else_contents ,
new_breadcrumbs . as_ref ( ) . unwrap_or ( breadcrumbs ) ,
blocks ,
) ;
}
}
_ = > {
return self . render_maybe_body (
& parameterized_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 ,
& parameterized_block . explicit_context ,
) ;
let param_map =
ParametersContext ::new ( self , breadcrumbs , & parameterized_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 (
& parameterized_block . contents ,
new_breadcrumbs . as_ref ( ) . unwrap_or ( breadcrumbs ) ,
blocks ,
) ;
} else {
return self . render_maybe_body (
& parameterized_block . else_contents ,
new_breadcrumbs . as_ref ( ) . unwrap_or ( breadcrumbs ) ,
blocks ,
) ;
}
}
_ = > {
return self . render_maybe_body (
& parameterized_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 ,
& parameterized_block . explicit_context ,
) ;
let param_map =
ParametersContext ::new ( self , breadcrumbs , & parameterized_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 (
& parameterized_block . contents ,
new_breadcrumbs . as_ref ( ) . unwrap_or ( breadcrumbs ) ,
blocks ,
) ;
} else {
return self . render_maybe_body (
& parameterized_block . else_contents ,
new_breadcrumbs . as_ref ( ) . unwrap_or ( breadcrumbs ) ,
blocks ,
) ;
}
}
_ = > {
return self . render_maybe_body (
& parameterized_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 ,
& parameterized_block . explicit_context ,
) ;
let param_map =
ParametersContext ::new ( self , breadcrumbs , & parameterized_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 (
& parameterized_block . contents ,
new_breadcrumbs . as_ref ( ) . unwrap_or ( breadcrumbs ) ,
blocks ,
) ;
} else {
return self . render_maybe_body (
& parameterized_block . else_contents ,
new_breadcrumbs . as_ref ( ) . unwrap_or ( breadcrumbs ) ,
blocks ,
) ;
}
}
_ = > {
return self . render_maybe_body (
& parameterized_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_ node s. push ( std ::convert ::From ::from ( val ) )
new_ stack . push ( std ::convert ::From ::from ( val ) )
}
} ) ;
} ) ;
injected_context . map ( | ctx | new_ node s. push ( BreadcrumbTreeElement ::from_borrowed ( ctx ) ) ) ;
injected_context . map ( | ctx | new_ stack . push ( BreadcrumbTreeElement ::from_borrowed ( ctx ) ) ) ;
new_context_element . map ( | ctx | {
new_ node s. push ( BreadcrumbTreeElement ::from_borrowed (
new_ stack . push ( BreadcrumbTreeElement ::from_borrowed (
ctx . from_context_element ( ) ,
) )
} ) ;
index_context . map ( | ctx | new_ node s. 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_ node s. 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
}
return ( None , passed_nodes ) ;
}
_ = > false ,
} ,
}
}
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 > ,
}