Merge branch 'into_context_element_breadcrumb_tree' into into_context_element
This commit is contained in:
commit
9b69ba7b09
@ -21,3 +21,9 @@
|
|||||||
{@eq key=array_of_some_obj value=array_of_some_obj}array_of_some_obj is equal to array_of_some_obj{:else}array_of_some_obj does not equal array_of_some_obj{/eq}{~n}
|
{@eq key=array_of_some_obj value=array_of_some_obj}array_of_some_obj is equal to array_of_some_obj{:else}array_of_some_obj does not equal array_of_some_obj{/eq}{~n}
|
||||||
{@eq key=array_of_some_obj value=copy_array_of_some_obj}array_of_some_obj is equal to copy_array_of_some_obj{:else}array_of_some_obj does not equal copy_array_of_some_obj{/eq}{~n}
|
{@eq key=array_of_some_obj value=copy_array_of_some_obj}array_of_some_obj is equal to copy_array_of_some_obj{:else}array_of_some_obj does not equal copy_array_of_some_obj{/eq}{~n}
|
||||||
{@eq key=array_of_some_obj value=array_of_other_obj}array_of_some_obj is equal to array_of_other_obj{:else}array_of_some_obj does not equal array_of_other_obj{/eq}{~n}
|
{@eq key=array_of_some_obj value=array_of_other_obj}array_of_some_obj is equal to array_of_other_obj{:else}array_of_some_obj does not equal array_of_other_obj{/eq}{~n}
|
||||||
|
|
||||||
|
Do objects with different paths referencing the same variable match?{~n}
|
||||||
|
===================================================================={~n}
|
||||||
|
{#int renamed=some_obj}
|
||||||
|
{@eq key=some_obj value=renamed}some_obj equals renamed{:else}some_obj does not equal renamed{/eq}{~n}
|
||||||
|
{/int}
|
||||||
|
@ -19,5 +19,14 @@
|
|||||||
"bar"
|
"bar"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"some_object": {
|
||||||
|
"foo": "bar"
|
||||||
|
},
|
||||||
|
"some_same_object": {
|
||||||
|
"foo": "bar"
|
||||||
|
},
|
||||||
|
"some_different_object": {
|
||||||
|
"foo": "baz"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,3 +53,12 @@ Reference Parameters{~n}
|
|||||||
{#truthy name="chris" pet="{petname}" petname="{deeperpetname}" deeperpetname="fluffy"}
|
{#truthy name="chris" pet="{petname}" petname="{deeperpetname}" deeperpetname="fluffy"}
|
||||||
Hello {name}, nice {pet}{~n}
|
Hello {name}, nice {pet}{~n}
|
||||||
{/truthy}
|
{/truthy}
|
||||||
|
|
||||||
|
Equality{~n}
|
||||||
|
========{~n}
|
||||||
|
{@eq key=some_object value=some_object}some_object equals some_object{:else}some_object does not equal some_object{/eq}{~n}
|
||||||
|
{@eq key=some_object value=some_same_object}some_object equals some_same_object{:else}some_object does not equal some_same_object{/eq}{~n}
|
||||||
|
{@eq key=some_object value="{some_object}"}some_object equals reference(some_object){:else}some_object does not equal reference(some_object){/eq}{~n}
|
||||||
|
{@eq key="{some_object}" value="{some_object}"}reference(some_object) equals reference(some_object){:else}reference(some_object) does not equal reference(some_object){/eq}{~n}
|
||||||
|
{@eq key="{some_object}" value="{some_same_object}"}reference(some_object) equals reference(some_same_object){:else}reference(some_object) does not equal reference(some_same_object){/eq}{~n}
|
||||||
|
{@eq key="{some_object}" value="{some_different_object}"}reference(some_object) equals reference(some_different_object){:else}reference(some_object) does not equal reference(some_different_object){/eq}{~n}
|
||||||
|
35
src/bin.rs
35
src/bin.rs
@ -3,8 +3,9 @@ extern crate nom;
|
|||||||
use crate::renderer::CompareContextElement;
|
use crate::renderer::CompareContextElement;
|
||||||
use parser::Filter;
|
use parser::Filter;
|
||||||
use parser::OwnedLiteral;
|
use parser::OwnedLiteral;
|
||||||
|
use parser::Template;
|
||||||
use renderer::compile_template;
|
use renderer::compile_template;
|
||||||
use renderer::CompiledTemplate;
|
use renderer::CompileError;
|
||||||
use renderer::ContextElement;
|
use renderer::ContextElement;
|
||||||
use renderer::DustRenderer;
|
use renderer::DustRenderer;
|
||||||
use renderer::IntoContextElement;
|
use renderer::IntoContextElement;
|
||||||
@ -38,32 +39,40 @@ fn main() {
|
|||||||
(p.to_string(), template_content)
|
(p.to_string(), template_content)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let compiled_templates: Vec<CompiledTemplate> = template_contents
|
let compiled_templates_result: Result<Vec<(String, Template)>, CompileError> =
|
||||||
|
template_contents
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(p, contents)| template_from_file(p, contents))
|
.map(|(p, contents)| template_from_file(p, contents))
|
||||||
.collect();
|
.collect();
|
||||||
let mut dust_renderer = DustRenderer::new();
|
let compiled_templates = compiled_templates_result.unwrap();
|
||||||
compiled_templates.iter().for_each(|template| {
|
|
||||||
dust_renderer.load_source(template);
|
|
||||||
});
|
|
||||||
let main_template_name = &compiled_templates
|
let main_template_name = &compiled_templates
|
||||||
.first()
|
.first()
|
||||||
.expect("There should be more than 1 template")
|
.expect("There should be more than 1 template")
|
||||||
.name;
|
.0;
|
||||||
let breadcrumbs = vec![&context as &dyn IntoContextElement];
|
let mut dust_renderer = DustRenderer::new();
|
||||||
|
compiled_templates.iter().for_each(|(name, template)| {
|
||||||
|
dust_renderer.load_source(template, name.to_owned());
|
||||||
|
});
|
||||||
println!(
|
println!(
|
||||||
"{}",
|
"{}",
|
||||||
dust_renderer
|
dust_renderer
|
||||||
.render(main_template_name, &breadcrumbs)
|
.render(main_template_name, Some(&context))
|
||||||
.expect("Failed to render")
|
.expect("Failed to render")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn template_from_file<'a>(file_path: &str, file_contents: &'a str) -> CompiledTemplate<'a> {
|
fn template_from_file<'a>(
|
||||||
|
file_path: &str,
|
||||||
|
file_contents: &'a str,
|
||||||
|
) -> Result<(String, Template<'a>), CompileError> {
|
||||||
let path: &Path = Path::new(file_path);
|
let path: &Path = Path::new(file_path);
|
||||||
let name = path.file_stem().unwrap();
|
let name = path.file_stem().ok_or(CompileError {
|
||||||
compile_template(file_contents, name.to_string_lossy().to_string())
|
message: format!("Failed to get file stem on {}", file_path),
|
||||||
.expect("Failed to compile template")
|
})?;
|
||||||
|
Ok((
|
||||||
|
name.to_string_lossy().to_string(),
|
||||||
|
compile_template(file_contents)?,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_context_from_stdin() -> serde_json::Value {
|
fn read_context_from_stdin() -> serde_json::Value {
|
||||||
|
@ -23,7 +23,7 @@ use nom::sequence::terminated;
|
|||||||
use nom::sequence::tuple;
|
use nom::sequence::tuple;
|
||||||
use nom::IResult;
|
use nom::IResult;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum DustTag<'a> {
|
pub enum DustTag<'a> {
|
||||||
DTSpecial(Special),
|
DTSpecial(Special),
|
||||||
DTComment(Comment<'a>),
|
DTComment(Comment<'a>),
|
||||||
@ -52,12 +52,12 @@ pub enum Special {
|
|||||||
RightCurlyBrace,
|
RightCurlyBrace,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum IgnoredWhitespace<'a> {
|
pub enum IgnoredWhitespace<'a> {
|
||||||
StartOfLine(&'a str),
|
StartOfLine(&'a str),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Comment<'a> {
|
pub struct Comment<'a> {
|
||||||
value: &'a str,
|
value: &'a str,
|
||||||
}
|
}
|
||||||
@ -65,12 +65,12 @@ pub struct Comment<'a> {
|
|||||||
/// A series of keys separated by '.' to reference a variable in the context
|
/// A series of keys separated by '.' to reference a variable in the context
|
||||||
///
|
///
|
||||||
/// Special case: If the path is just "." then keys will be an empty vec
|
/// Special case: If the path is just "." then keys will be an empty vec
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Path<'a> {
|
pub struct Path<'a> {
|
||||||
pub keys: Vec<&'a str>,
|
pub keys: Vec<&'a str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Reference<'a> {
|
pub struct Reference<'a> {
|
||||||
pub path: Path<'a>,
|
pub path: Path<'a>,
|
||||||
pub filters: Vec<Filter>,
|
pub filters: Vec<Filter>,
|
||||||
@ -87,12 +87,12 @@ pub enum Filter {
|
|||||||
JsonParse,
|
JsonParse,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Span<'a> {
|
pub struct Span<'a> {
|
||||||
pub contents: &'a str,
|
pub contents: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct ParameterizedBlock<'a> {
|
pub struct ParameterizedBlock<'a> {
|
||||||
pub path: Path<'a>,
|
pub path: Path<'a>,
|
||||||
pub explicit_context: Option<Path<'a>>,
|
pub explicit_context: Option<Path<'a>>,
|
||||||
@ -101,33 +101,33 @@ pub struct ParameterizedBlock<'a> {
|
|||||||
pub else_contents: Option<Body<'a>>,
|
pub else_contents: Option<Body<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Partial<'a> {
|
pub struct Partial<'a> {
|
||||||
pub name: Vec<PartialNameElement>,
|
pub name: Vec<PartialNameElement>,
|
||||||
pub explicit_context: Option<Path<'a>>,
|
pub explicit_context: Option<Path<'a>>,
|
||||||
pub params: Vec<KVPair<'a>>,
|
pub params: Vec<KVPair<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum OwnedLiteral {
|
pub enum OwnedLiteral {
|
||||||
LString(String),
|
LString(String),
|
||||||
LPositiveInteger(u64),
|
LPositiveInteger(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum RValue<'a> {
|
pub enum RValue<'a> {
|
||||||
RVPath(Path<'a>),
|
RVPath(Path<'a>),
|
||||||
RVTemplate(Vec<PartialNameElement>),
|
RVTemplate(Vec<PartialNameElement>),
|
||||||
RVLiteral(OwnedLiteral),
|
RVLiteral(OwnedLiteral),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct KVPair<'a> {
|
pub struct KVPair<'a> {
|
||||||
pub key: &'a str,
|
pub key: &'a str,
|
||||||
pub value: RValue<'a>,
|
pub value: RValue<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum PartialNameElement {
|
pub enum PartialNameElement {
|
||||||
PNSpan {
|
PNSpan {
|
||||||
contents: String,
|
contents: String,
|
||||||
@ -138,17 +138,17 @@ pub enum PartialNameElement {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Body<'a> {
|
pub struct Body<'a> {
|
||||||
pub elements: Vec<TemplateElement<'a>>,
|
pub elements: Vec<TemplateElement<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Template<'a> {
|
pub struct Template<'a> {
|
||||||
pub contents: Body<'a>,
|
pub contents: Body<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum TemplateElement<'a> {
|
pub enum TemplateElement<'a> {
|
||||||
TESpan(Span<'a>),
|
TESpan(Span<'a>),
|
||||||
TETag(DustTag<'a>),
|
TETag(DustTag<'a>),
|
||||||
|
59
src/renderer/breadcrumb_tree.rs
Normal file
59
src/renderer/breadcrumb_tree.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
use crate::renderer::context_element::ContextElement;
|
||||||
|
use crate::renderer::context_element::IceResult;
|
||||||
|
use crate::renderer::context_element::IntoContextElement;
|
||||||
|
use crate::renderer::context_element::IntoRcIce;
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum BreadcrumbTreeElement<'a> {
|
||||||
|
// Using Rc so that when we need to create BreadcrumbTrees with
|
||||||
|
// the same BreadcrumbTreeElement but a different parent (for
|
||||||
|
// example, when inserting behind the tail), we don't need to the
|
||||||
|
// copy the already owned/malloc'd data.
|
||||||
|
Owned(Rc<dyn IntoContextElement + 'a>),
|
||||||
|
Borrowed(&'a dyn IntoContextElement),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> BreadcrumbTreeElement<'a> {
|
||||||
|
pub fn from_owned<I: 'a + IntoContextElement>(val: I) -> BreadcrumbTreeElement<'a> {
|
||||||
|
BreadcrumbTreeElement::Owned(Rc::new(val))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_borrowed(val: &'a dyn IntoContextElement) -> BreadcrumbTreeElement<'a> {
|
||||||
|
BreadcrumbTreeElement::Borrowed(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a IceResult<'a>> for BreadcrumbTreeElement<'a> {
|
||||||
|
fn from(inp: &'a IceResult<'a>) -> Self {
|
||||||
|
match inp {
|
||||||
|
IceResult::Owned(rc_ce) => {
|
||||||
|
BreadcrumbTreeElement::from_borrowed(rc_ce.from_context_element())
|
||||||
|
}
|
||||||
|
IceResult::Borrowed(ce) => {
|
||||||
|
BreadcrumbTreeElement::from_borrowed(ce.from_context_element())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<IceResult<'a>> for BreadcrumbTreeElement<'a> {
|
||||||
|
fn from(inp: IceResult<'a>) -> Self {
|
||||||
|
match inp {
|
||||||
|
IceResult::Owned(rc_ce) => BreadcrumbTreeElement::Owned(rc_ce.into_rc_ice()),
|
||||||
|
IceResult::Borrowed(ce) => {
|
||||||
|
BreadcrumbTreeElement::from_borrowed(ce.from_context_element())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Borrow<dyn IntoContextElement + 'a> for BreadcrumbTreeElement<'a> {
|
||||||
|
fn borrow(&self) -> &(dyn IntoContextElement + 'a) {
|
||||||
|
match self {
|
||||||
|
BreadcrumbTreeElement::Owned(ice) => ice.as_ref(),
|
||||||
|
BreadcrumbTreeElement::Borrowed(ice) => *ice,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,10 @@
|
|||||||
use crate::parser::Filter;
|
use crate::parser::Filter;
|
||||||
|
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;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::{cmp::Ordering, fmt::Debug};
|
use std::{cmp::Ordering, fmt::Debug};
|
||||||
|
|
||||||
pub trait ContextElement:
|
pub trait ContextElement:
|
||||||
@ -11,9 +13,10 @@ pub trait ContextElement:
|
|||||||
+ Walkable
|
+ Walkable
|
||||||
+ Renderable
|
+ Renderable
|
||||||
+ Loopable
|
+ Loopable
|
||||||
+ CloneIntoBoxedContextElement
|
// + CloneIntoBoxedContextElement
|
||||||
+ CompareContextElement
|
+ CompareContextElement
|
||||||
+ FromContextElement
|
+ FromContextElement
|
||||||
|
+ IntoRcIce
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,15 +64,15 @@ pub trait CompareContextElement: CastToAny {
|
|||||||
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering>;
|
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CloneIntoBoxedContextElement {
|
// pub trait CloneIntoBoxedContextElement {
|
||||||
fn clone_to_box(&self) -> Box<dyn IntoContextElement>;
|
// fn clone_to_box(&self) -> Box<dyn IntoContextElement>;
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl<C: 'static + IntoContextElement + Clone> CloneIntoBoxedContextElement for C {
|
// impl<C: 'static + IntoContextElement + Clone> CloneIntoBoxedContextElement for C {
|
||||||
fn clone_to_box(&self) -> Box<dyn IntoContextElement> {
|
// fn clone_to_box(&self) -> Box<dyn IntoContextElement> {
|
||||||
Box::new(self.clone())
|
// Box::new(self.clone())
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
impl<C: 'static + ContextElement> CastToAny for C {
|
impl<C: 'static + ContextElement> CastToAny for C {
|
||||||
fn to_any(&self) -> &dyn Any {
|
fn to_any(&self) -> &dyn Any {
|
||||||
@ -99,20 +102,76 @@ impl<C: ContextElement> FromContextElement for C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait IntoContextElement: Debug + Walkable + CloneIntoBoxedContextElement {
|
pub trait IntoContextElement: Debug + Walkable /* + CloneIntoBoxedContextElement*/ {
|
||||||
fn into_context_element(
|
fn into_context_element<'a>(
|
||||||
&self,
|
&'a self,
|
||||||
renderer: &DustRenderer,
|
renderer: &DustRenderer,
|
||||||
breadcrumbs: &Vec<&dyn IntoContextElement>,
|
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||||
) -> &dyn ContextElement;
|
) -> Option<IceResult<'a>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: ContextElement> IntoContextElement for C {
|
impl<C: ContextElement> IntoContextElement for C {
|
||||||
fn into_context_element(
|
fn into_context_element<'a>(
|
||||||
&self,
|
&'a self,
|
||||||
renderer: &DustRenderer,
|
renderer: &DustRenderer,
|
||||||
breadcrumbs: &Vec<&dyn IntoContextElement>,
|
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||||
) -> &dyn ContextElement {
|
) -> Option<IceResult<'a>> {
|
||||||
self
|
Some(IceResult::from_borrowed(self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait IntoRcIce {
|
||||||
|
fn into_rc_ice(self: Rc<Self>) -> Rc<dyn IntoContextElement>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: 'static + ContextElement> IntoRcIce for C {
|
||||||
|
fn into_rc_ice(self: Rc<C>) -> Rc<dyn IntoContextElement> {
|
||||||
|
Rc::clone(&self) as Rc<dyn IntoContextElement>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum IceResult<'a> {
|
||||||
|
// Using Rc so that when we need to create BreadcrumbTrees with
|
||||||
|
// the same BreadcrumbTreeElement but a different parent (for
|
||||||
|
// example, when inserting behind the tail), we don't need to the
|
||||||
|
// copy the already owned/malloc'd data.
|
||||||
|
Owned(Rc<dyn ContextElement>),
|
||||||
|
Borrowed(&'a dyn ContextElement),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IceResult<'a> {
|
||||||
|
pub fn from_owned<C: 'static + ContextElement>(val: C) -> IceResult<'a> {
|
||||||
|
IceResult::Owned(Rc::new(val))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_borrowed(val: &'a dyn ContextElement) -> IceResult<'a> {
|
||||||
|
IceResult::Borrowed(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_context_element_reference(&self) -> &dyn ContextElement {
|
||||||
|
match self {
|
||||||
|
IceResult::Owned(rc_ce) => rc_ce.as_ref(),
|
||||||
|
IceResult::Borrowed(ce) => *ce,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> IntoContextElement for IceResult<'a> {
|
||||||
|
fn into_context_element<'b>(
|
||||||
|
&'b self,
|
||||||
|
renderer: &DustRenderer,
|
||||||
|
breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
|
||||||
|
) -> Option<IceResult<'b>> {
|
||||||
|
match self {
|
||||||
|
IceResult::Owned(rc_ce) => Some(IceResult::from_borrowed(rc_ce.as_ref())),
|
||||||
|
IceResult::Borrowed(ce) => Some(IceResult::from_borrowed(*ce)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Walkable for IceResult<'a> {
|
||||||
|
fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
|
||||||
|
self.get_context_element_reference().walk(segment)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
//! This module contains a renderer for a rust implementation of LinkedIn Dust
|
//! This module contains a renderer for a rust implementation of LinkedIn Dust
|
||||||
|
|
||||||
|
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 walking;
|
mod walking;
|
||||||
|
|
||||||
pub use context_element::CloneIntoBoxedContextElement;
|
// pub use context_element::CloneIntoBoxedContextElement;
|
||||||
pub use context_element::CompareContextElement;
|
pub use context_element::CompareContextElement;
|
||||||
pub use context_element::ContextElement;
|
pub use context_element::ContextElement;
|
||||||
pub use context_element::IntoContextElement;
|
pub use context_element::IntoContextElement;
|
||||||
@ -20,5 +22,5 @@ pub use errors::CompileError;
|
|||||||
pub use errors::RenderError;
|
pub use errors::RenderError;
|
||||||
pub use errors::WalkError;
|
pub use errors::WalkError;
|
||||||
pub use renderer::compile_template;
|
pub use renderer::compile_template;
|
||||||
pub use renderer::CompiledTemplate;
|
// pub use renderer::CompiledTemplate;
|
||||||
pub use renderer::DustRenderer;
|
pub use renderer::DustRenderer;
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
|
use crate::parser::Filter;
|
||||||
use crate::parser::KVPair;
|
use crate::parser::KVPair;
|
||||||
use crate::parser::{Filter, OwnedLiteral, PartialNameElement, RValue};
|
use crate::parser::OwnedLiteral;
|
||||||
|
use crate::parser::RValue;
|
||||||
|
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::walking::walk_path;
|
use crate::renderer::tree_walking::walk_path;
|
||||||
use crate::renderer::DustRenderer;
|
use crate::renderer::DustRenderer;
|
||||||
use crate::renderer::Loopable;
|
use crate::renderer::Loopable;
|
||||||
use crate::renderer::RenderError;
|
use crate::renderer::RenderError;
|
||||||
@ -11,104 +15,80 @@ use crate::renderer::Renderable;
|
|||||||
use crate::renderer::Truthiness;
|
use crate::renderer::Truthiness;
|
||||||
use crate::renderer::WalkError;
|
use crate::renderer::WalkError;
|
||||||
use crate::renderer::Walkable;
|
use crate::renderer::Walkable;
|
||||||
use std::{cmp::Ordering, collections::HashMap};
|
use std::borrow::Borrow;
|
||||||
|
use std::cmp::Ordering;
|
||||||
/// Copy the data from an RValue to an Owned struct
|
use std::collections::HashMap;
|
||||||
///
|
use std::rc::Rc;
|
||||||
/// In order to get comparisons to work for our `ContextElement` trait
|
|
||||||
/// objects, we need to be able to use `std::any::Any`. Unfortunately,
|
|
||||||
/// `Any` requires that the structs do not have a lifetime (so they
|
|
||||||
/// will have a `'static` lifetime. This means that we cannot have a
|
|
||||||
/// `<'a>` appended to the struct type, so the struct cannot contain
|
|
||||||
/// any borrows. Rather than impose the copy cost in the parser, we
|
|
||||||
/// are imposing the cost of copying the data in the renderer because
|
|
||||||
/// the parser has no reason to not be able to reference data from the
|
|
||||||
/// input string.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum OwnedRValue {
|
|
||||||
RVPath(OwnedPath),
|
|
||||||
RVTemplate(Vec<PartialNameElement>),
|
|
||||||
RVLiteral(OwnedLiteral),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub struct OwnedPath {
|
|
||||||
pub keys: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&RValue<'_>> for OwnedRValue {
|
|
||||||
fn from(original: &RValue<'_>) -> Self {
|
|
||||||
match original {
|
|
||||||
RValue::RVLiteral(literal) => OwnedRValue::RVLiteral(literal.clone()),
|
|
||||||
RValue::RVTemplate(template) => OwnedRValue::RVTemplate(template.clone()),
|
|
||||||
RValue::RVPath(path) => OwnedRValue::RVPath(OwnedPath {
|
|
||||||
keys: path.keys.iter().map(|k| k.to_string()).collect(),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParametersContext {
|
pub struct ParametersContext<'a> {
|
||||||
params: HashMap<String, OwnedRValue>,
|
params: HashMap<&'a str, (&'a RValue<'a>, Option<BreadcrumbTreeElement<'a>>)>,
|
||||||
breadcrumbs: Vec<Box<dyn IntoContextElement>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParametersContext {
|
impl<'a> ParametersContext<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
breadcrumbs: &Vec<&dyn IntoContextElement>,
|
renderer: &DustRenderer,
|
||||||
params: &Vec<KVPair>,
|
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||||
) -> ParametersContext {
|
params: &'a Vec<KVPair>,
|
||||||
let owned_params: HashMap<String, OwnedRValue> = params
|
) -> Self {
|
||||||
|
// If the parameter is a Path, then we resolve it immediately
|
||||||
|
// to a context element because those are resolved using the
|
||||||
|
// breadcrumbs at the time of assignment.
|
||||||
|
//
|
||||||
|
// If the parameter is a template (for example `foo="{bar}"`)
|
||||||
|
// then those are resolved at the time of access rather than
|
||||||
|
// the time of assignment, so we leave them into their
|
||||||
|
// original IntoContextElement state.
|
||||||
|
let rendered_params: HashMap<&'a str, (&'a RValue<'a>, Option<BreadcrumbTreeElement<'a>>)> =
|
||||||
|
params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|kvpair| (kvpair.key.to_string(), OwnedRValue::from(&kvpair.value)))
|
.map(|kvpair| {
|
||||||
|
let k = kvpair.key;
|
||||||
|
let v: Option<BreadcrumbTreeElement<'a>> = match &kvpair.value {
|
||||||
|
RValue::RVLiteral(owned_literal) => {
|
||||||
|
Some(BreadcrumbTreeElement::from_borrowed(&kvpair.value))
|
||||||
|
}
|
||||||
|
RValue::RVPath(path) => kvpair
|
||||||
|
.value
|
||||||
|
.into_context_element(renderer, breadcrumbs)
|
||||||
|
.map(std::convert::From::from),
|
||||||
|
RValue::RVTemplate(template) => {
|
||||||
|
Some(BreadcrumbTreeElement::from_borrowed(&kvpair.value))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(k, (&kvpair.value, v))
|
||||||
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let owned_breadcrumbs: Vec<Box<dyn IntoContextElement>> =
|
|
||||||
breadcrumbs.iter().map(|ce| ce.clone_to_box()).collect();
|
|
||||||
|
|
||||||
ParametersContext {
|
ParametersContext {
|
||||||
params: owned_params,
|
params: rendered_params,
|
||||||
breadcrumbs: owned_breadcrumbs,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_original_rvalue(&self, segment: &str) -> Option<&'a RValue<'a>> {
|
||||||
|
self.params.get(segment).map(|(rvalue, _bte)| *rvalue)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains_key(&self, segment: &str) -> bool {
|
||||||
|
self.params.contains_key(segment)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextElement for ParametersContext {}
|
impl<'a> IntoContextElement for ParametersContext<'a> {
|
||||||
|
fn into_context_element<'b>(
|
||||||
impl Truthiness for ParametersContext {
|
&'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 ParametersContext {
|
impl<'a> Walkable for ParametersContext<'a> {
|
||||||
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 ParametersContext {
|
|
||||||
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 Walkable for ParametersContext {
|
|
||||||
fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
|
fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
|
||||||
let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?;
|
match self.params.get(segment).map(|(_rvalue, bte)| bte) {
|
||||||
match rval {
|
Some(Some(bte)) => Ok(bte.borrow()),
|
||||||
OwnedRValue::RVPath(path) => walk_path(&self.breadcrumbs, &path.keys),
|
_ => Err(WalkError::CantWalk),
|
||||||
OwnedRValue::RVTemplate(template) => Ok(template),
|
|
||||||
OwnedRValue::RVLiteral(literal) => Ok(literal),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,34 +97,30 @@ impl Walkable for ParametersContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for ParametersContext {
|
impl<'a> IntoContextElement for RValue<'a> {
|
||||||
fn clone(&self) -> Self {
|
fn into_context_element<'b>(
|
||||||
let new_params: HashMap<String, OwnedRValue> = self
|
&'b self,
|
||||||
.params
|
renderer: &DustRenderer,
|
||||||
.iter()
|
breadcrumbs: &'b Vec<BreadcrumbTreeElement<'b>>,
|
||||||
.map(|(k, v)| (k.clone(), v.clone()))
|
) -> Option<IceResult<'b>> {
|
||||||
.collect();
|
match self {
|
||||||
let new_breadcrumbs: Vec<Box<dyn IntoContextElement>> = self
|
RValue::RVLiteral(owned_literal) => Some(IceResult::from_borrowed(owned_literal)),
|
||||||
.breadcrumbs
|
RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys)
|
||||||
.iter()
|
.map(|ice| ice.into_context_element(renderer, breadcrumbs))
|
||||||
.map(|bread| bread.clone_to_box())
|
.ok()
|
||||||
.collect();
|
.flatten(),
|
||||||
ParametersContext {
|
RValue::RVTemplate(template) => renderer
|
||||||
params: new_params,
|
.render_partial_name(template, breadcrumbs)
|
||||||
breadcrumbs: new_breadcrumbs,
|
.map(|rendered| OwnedLiteral::LString(rendered))
|
||||||
|
.ok()
|
||||||
|
.map(|owned_literal| IceResult::from_owned(owned_literal)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompareContextElement for ParametersContext {
|
impl<'a> Walkable for RValue<'a> {
|
||||||
fn equals(&self, other: &dyn ContextElement) -> bool {
|
fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
|
||||||
// TODO: Does this ever happen? perhaps I should have a panic here.
|
Err(WalkError::CantWalk)
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
|
||||||
// TODO: Does this ever happen? perhaps I should have a panic here.
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,24 +216,3 @@ impl CompareContextElement for OwnedLiteral {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoContextElement for Vec<PartialNameElement> {
|
|
||||||
fn into_context_element(
|
|
||||||
&self,
|
|
||||||
renderer: &DustRenderer,
|
|
||||||
breadcrumbs: &Vec<&dyn IntoContextElement>,
|
|
||||||
) -> &dyn ContextElement {
|
|
||||||
OwnedLiteral::LString(
|
|
||||||
renderer
|
|
||||||
.render_partial_name(self, breadcrumbs)
|
|
||||||
.expect("TODO: Make into_context_element return a RenderError"),
|
|
||||||
)
|
|
||||||
// &OwnedLiteral::LPositiveInteger(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Walkable for Vec<PartialNameElement> {
|
|
||||||
fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
|
|
||||||
Err(WalkError::CantWalk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
264
src/renderer/parameters_context_old.rs
Normal file
264
src/renderer/parameters_context_old.rs
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
use crate::parser::KVPair;
|
||||||
|
use crate::parser::{Filter, OwnedLiteral, PartialNameElement, RValue};
|
||||||
|
use crate::renderer::context_element::CompareContextElement;
|
||||||
|
use crate::renderer::context_element::ContextElement;
|
||||||
|
use crate::renderer::context_element::IntoContextElement;
|
||||||
|
use crate::renderer::walking::walk_path;
|
||||||
|
use crate::renderer::DustRenderer;
|
||||||
|
use crate::renderer::Loopable;
|
||||||
|
use crate::renderer::RenderError;
|
||||||
|
use crate::renderer::Renderable;
|
||||||
|
use crate::renderer::Truthiness;
|
||||||
|
use crate::renderer::WalkError;
|
||||||
|
use crate::renderer::Walkable;
|
||||||
|
use std::{cmp::Ordering, collections::HashMap};
|
||||||
|
|
||||||
|
/// Copy the data from an RValue to an Owned struct
|
||||||
|
///
|
||||||
|
/// In order to get comparisons to work for our `ContextElement` trait
|
||||||
|
/// objects, we need to be able to use `std::any::Any`. Unfortunately,
|
||||||
|
/// `Any` requires that the structs do not have a lifetime (so they
|
||||||
|
/// will have a `'static` lifetime. This means that we cannot have a
|
||||||
|
/// `<'a>` appended to the struct type, so the struct cannot contain
|
||||||
|
/// any borrows. Rather than impose the copy cost in the parser, we
|
||||||
|
/// are imposing the cost of copying the data in the renderer because
|
||||||
|
/// the parser has no reason to not be able to reference data from the
|
||||||
|
/// input string.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub enum OwnedRValue {
|
||||||
|
RVPath(OwnedPath),
|
||||||
|
RVTemplate(Vec<PartialNameElement>),
|
||||||
|
RVLiteral(OwnedLiteral),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct OwnedPath {
|
||||||
|
pub keys: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&RValue<'_>> for OwnedRValue {
|
||||||
|
fn from(original: &RValue<'_>) -> Self {
|
||||||
|
match original {
|
||||||
|
RValue::RVLiteral(literal) => OwnedRValue::RVLiteral(literal.clone()),
|
||||||
|
RValue::RVTemplate(template) => OwnedRValue::RVTemplate(template.clone()),
|
||||||
|
RValue::RVPath(path) => OwnedRValue::RVPath(OwnedPath {
|
||||||
|
keys: path.keys.iter().map(|k| k.to_string()).collect(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ParametersContext {
|
||||||
|
params: HashMap<String, OwnedRValue>,
|
||||||
|
breadcrumbs: Vec<Box<dyn IntoContextElement>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParametersContext {
|
||||||
|
pub fn new(
|
||||||
|
breadcrumbs: &Vec<&dyn IntoContextElement>,
|
||||||
|
params: &Vec<KVPair>,
|
||||||
|
) -> ParametersContext {
|
||||||
|
let owned_params: HashMap<String, OwnedRValue> = params
|
||||||
|
.iter()
|
||||||
|
.map(|kvpair| (kvpair.key.to_string(), OwnedRValue::from(&kvpair.value)))
|
||||||
|
.collect();
|
||||||
|
let owned_breadcrumbs: Vec<Box<dyn IntoContextElement>> =
|
||||||
|
breadcrumbs.iter().map(|ce| ce.clone_to_box()).collect();
|
||||||
|
|
||||||
|
ParametersContext {
|
||||||
|
params: owned_params,
|
||||||
|
breadcrumbs: owned_breadcrumbs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextElement for ParametersContext {}
|
||||||
|
|
||||||
|
impl Truthiness for ParametersContext {
|
||||||
|
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 ParametersContext {
|
||||||
|
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 ParametersContext {
|
||||||
|
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 Walkable for ParametersContext {
|
||||||
|
fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
|
||||||
|
let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?;
|
||||||
|
match rval {
|
||||||
|
OwnedRValue::RVPath(path) => walk_path(&self.breadcrumbs, &path.keys),
|
||||||
|
OwnedRValue::RVTemplate(template) => Ok(template),
|
||||||
|
OwnedRValue::RVLiteral(literal) => Ok(literal),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_pseudo_element(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for ParametersContext {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
let new_params: HashMap<String, OwnedRValue> = self
|
||||||
|
.params
|
||||||
|
.iter()
|
||||||
|
.map(|(k, v)| (k.clone(), v.clone()))
|
||||||
|
.collect();
|
||||||
|
let new_breadcrumbs: Vec<Box<dyn IntoContextElement>> = self
|
||||||
|
.breadcrumbs
|
||||||
|
.iter()
|
||||||
|
.map(|bread| bread.clone_to_box())
|
||||||
|
.collect();
|
||||||
|
ParametersContext {
|
||||||
|
params: new_params,
|
||||||
|
breadcrumbs: new_breadcrumbs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompareContextElement for ParametersContext {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextElement for OwnedLiteral {}
|
||||||
|
|
||||||
|
impl Truthiness for OwnedLiteral {
|
||||||
|
fn is_truthy(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
OwnedLiteral::LString(text) => !text.is_empty(),
|
||||||
|
OwnedLiteral::LPositiveInteger(num) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Renderable for OwnedLiteral {
|
||||||
|
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
|
||||||
|
match self {
|
||||||
|
OwnedLiteral::LString(text) => Ok(text.clone()),
|
||||||
|
OwnedLiteral::LPositiveInteger(num) => Ok(num.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Loopable for OwnedLiteral {
|
||||||
|
fn get_loop_elements(&self) -> Vec<&dyn ContextElement> {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Walkable for OwnedLiteral {
|
||||||
|
fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
|
||||||
|
Err(WalkError::CantWalk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompareContextElement for OwnedLiteral {
|
||||||
|
fn equals(&self, other: &dyn ContextElement) -> bool {
|
||||||
|
// println!("equals literal {:?} | {:?}", self, other);
|
||||||
|
// If its an OwnedLiteral then compare them directly,
|
||||||
|
// otherwise defer to the other type's implementation of
|
||||||
|
// CompareContextElement since the end user could add any
|
||||||
|
// type.
|
||||||
|
match other.to_any().downcast_ref::<Self>() {
|
||||||
|
None => other.equals(self),
|
||||||
|
Some(other_literal) => match (self, other_literal) {
|
||||||
|
(OwnedLiteral::LString(self_text), OwnedLiteral::LString(other_text)) => {
|
||||||
|
self_text == other_text
|
||||||
|
}
|
||||||
|
(OwnedLiteral::LPositiveInteger(self_num), OwnedLiteral::LString(other_text)) => {
|
||||||
|
&self_num.to_string() == other_text
|
||||||
|
}
|
||||||
|
(OwnedLiteral::LString(self_text), OwnedLiteral::LPositiveInteger(other_num)) => {
|
||||||
|
self_text == &other_num.to_string()
|
||||||
|
}
|
||||||
|
(
|
||||||
|
OwnedLiteral::LPositiveInteger(self_num),
|
||||||
|
OwnedLiteral::LPositiveInteger(other_num),
|
||||||
|
) => self_num == other_num,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
||||||
|
// println!("partial_compare literal {:?} | {:?}", self, other);
|
||||||
|
// If its an OwnedLiteral then compare them directly,
|
||||||
|
// otherwise defer to the other type's implementation of
|
||||||
|
// CompareContextElement since the end user could add any
|
||||||
|
// type.
|
||||||
|
match other.to_any().downcast_ref::<Self>() {
|
||||||
|
None => match other.partial_compare(self) {
|
||||||
|
None => None,
|
||||||
|
Some(ord) => match ord {
|
||||||
|
Ordering::Equal => Some(Ordering::Equal),
|
||||||
|
Ordering::Greater => Some(Ordering::Less),
|
||||||
|
Ordering::Less => Some(Ordering::Greater),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Some(other_literal) => match (self, other_literal) {
|
||||||
|
(OwnedLiteral::LString(self_text), OwnedLiteral::LString(other_text)) => {
|
||||||
|
self_text.partial_cmp(other_text)
|
||||||
|
}
|
||||||
|
(OwnedLiteral::LPositiveInteger(self_num), OwnedLiteral::LString(other_text)) => {
|
||||||
|
self_num.to_string().partial_cmp(other_text)
|
||||||
|
}
|
||||||
|
(OwnedLiteral::LString(self_text), OwnedLiteral::LPositiveInteger(other_num)) => {
|
||||||
|
self_text.partial_cmp(&other_num.to_string())
|
||||||
|
}
|
||||||
|
(
|
||||||
|
OwnedLiteral::LPositiveInteger(self_num),
|
||||||
|
OwnedLiteral::LPositiveInteger(other_num),
|
||||||
|
) => self_num.partial_cmp(other_num),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoContextElement for Vec<PartialNameElement> {
|
||||||
|
fn into_context_element(
|
||||||
|
&self,
|
||||||
|
renderer: &DustRenderer,
|
||||||
|
breadcrumbs: &Vec<&dyn IntoContextElement>,
|
||||||
|
) -> &dyn ContextElement {
|
||||||
|
// OwnedLiteral::LString(
|
||||||
|
// renderer
|
||||||
|
// .render_partial_name(self, breadcrumbs)
|
||||||
|
// .expect("TODO: Make into_context_element return a RenderError"),
|
||||||
|
// )
|
||||||
|
// TODO
|
||||||
|
&OwnedLiteral::LPositiveInteger(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Walkable for Vec<PartialNameElement> {
|
||||||
|
fn walk(&self, segment: &str) -> Result<&dyn IntoContextElement, WalkError> {
|
||||||
|
Err(WalkError::CantWalk)
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
1021
src/renderer/renderer_old.rs
Normal file
1021
src/renderer/renderer_old.rs
Normal file
File diff suppressed because it is too large
Load Diff
94
src/renderer/tree_walking.rs
Normal file
94
src/renderer/tree_walking.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
|
||||||
|
use crate::renderer::context_element::IntoContextElement;
|
||||||
|
use crate::renderer::WalkError;
|
||||||
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
|
enum WalkResult<'a> {
|
||||||
|
NoWalk,
|
||||||
|
PartialWalk,
|
||||||
|
FullyWalked(&'a dyn IntoContextElement),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk_path_from_single_level<'a, P>(
|
||||||
|
context: &'a dyn IntoContextElement,
|
||||||
|
path: &[P],
|
||||||
|
) -> WalkResult<'a>
|
||||||
|
where
|
||||||
|
P: Borrow<str>,
|
||||||
|
{
|
||||||
|
if path.is_empty() {
|
||||||
|
return WalkResult::FullyWalked(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut walk_failure = WalkResult::NoWalk;
|
||||||
|
let mut output = context;
|
||||||
|
for elem in path.iter() {
|
||||||
|
match output.walk(elem.borrow()) {
|
||||||
|
Err(WalkError::CantWalk { .. }) => {
|
||||||
|
return walk_failure;
|
||||||
|
}
|
||||||
|
Ok(new_val) => {
|
||||||
|
walk_failure = WalkResult::PartialWalk;
|
||||||
|
output = new_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WalkResult::FullyWalked(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_first_non_pseudo_element<'a>(
|
||||||
|
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||||
|
) -> Option<&'a BreadcrumbTreeElement<'a>> {
|
||||||
|
breadcrumbs
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.filter(|b| {
|
||||||
|
!std::borrow::Borrow::<dyn IntoContextElement + 'a>::borrow(*b).is_pseudo_element()
|
||||||
|
})
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn walk_path<'a, P>(
|
||||||
|
breadcrumbs: &'a Vec<BreadcrumbTreeElement<'a>>,
|
||||||
|
path: &Vec<P>,
|
||||||
|
) -> Result<&'a dyn IntoContextElement, WalkError>
|
||||||
|
where
|
||||||
|
P: Borrow<str>,
|
||||||
|
{
|
||||||
|
match (breadcrumbs.last(), path.first()) {
|
||||||
|
(None, _) => return Err(WalkError::CantWalk),
|
||||||
|
(Some(last_elem), None) => return Ok(last_elem.borrow()),
|
||||||
|
(Some(_), Some(path_first)) if path_first.borrow() == "." => {
|
||||||
|
let first_non_pseudo_element = get_first_non_pseudo_element(breadcrumbs);
|
||||||
|
return match first_non_pseudo_element {
|
||||||
|
None => Err(WalkError::CantWalk),
|
||||||
|
Some(current_context) => {
|
||||||
|
match walk_path_from_single_level(current_context.borrow(), &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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(Some(_), Some(path_first)) => {
|
||||||
|
for context in breadcrumbs.iter().rev() {
|
||||||
|
match walk_path_from_single_level(context.borrow(), 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)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user