Merge branch 'bug_comparison_type_coercion' into render
This commit is contained in:
commit
04d2f4b331
@ -21,9 +21,9 @@ beta is {beta}{~n}
|
|||||||
{@gt key="a" value="A"}"a" is greater than "A"{:else}"a" is less than or equal to "A"{/gt}{~n}
|
{@gt key="a" value="A"}"a" is greater than "A"{:else}"a" is less than or equal to "A"{/gt}{~n}
|
||||||
{@gt key="a" value="}"}"a" is greater than "}"{:else}"a" is less than or equal to "}"{/gt}{~n}
|
{@gt key="a" value="}"}"a" is greater than "}"{:else}"a" is less than or equal to "}"{/gt}{~n}
|
||||||
{!
|
{!
|
||||||
Commented out because unicode breaks nom
|
Commented out because unicode breaks nom
|
||||||
{@gt key="☃" value="☄"}"☃" is greater than "☄"{:else}"☃" is less than or equal to "☄"{/gt}{~n}
|
{@gt key="☃" value="☄"}"☃" is greater than "☄"{:else}"☃" is less than or equal to "☄"{/gt}{~n}
|
||||||
!}
|
!}
|
||||||
{@gt key=true_value value=false_value}true is greater than false{:else}true is less than or equal to false{/gt}{~n}
|
{@gt key=true_value value=false_value}true is greater than false{:else}true is less than or equal to false{/gt}{~n}
|
||||||
{@gt key=array_lower value=array_higher}[3,5,7] is greater than [8,9]{:else}[3,5,7] is less than or equal to [8,9]{/gt}{~n}
|
{@gt key=array_lower value=array_higher}[3,5,7] is greater than [8,9]{:else}[3,5,7] is less than or equal to [8,9]{/gt}{~n}
|
||||||
{@gt key=array_higher value=array_lower}[8,9] is greater than [3,5,7]{:else}[8,9] is less than or equal to [3,5,7]{/gt}{~n}
|
{@gt key=array_higher value=array_lower}[8,9] is greater than [3,5,7]{:else}[8,9] is less than or equal to [3,5,7]{/gt}{~n}
|
||||||
@ -40,3 +40,5 @@ Commented out because unicode breaks nom
|
|||||||
{@gt key=array_higher value=array_higher_longer}array_higher is greater than array_higher_longer{:else}array_higher is less than or equal to array_higher_longer{/gt}{~n}
|
{@gt key=array_higher value=array_higher_longer}array_higher is greater than array_higher_longer{:else}array_higher is less than or equal to array_higher_longer{/gt}{~n}
|
||||||
{@gt key=array_lower value=array_lower_with_array}array_lower is greater than array_lower_with_array{:else}array_lower is less than or equal to array_lower_with_array{/gt}{~n}
|
{@gt key=array_lower value=array_lower_with_array}array_lower is greater than array_lower_with_array{:else}array_lower is less than or equal to array_lower_with_array{/gt}{~n}
|
||||||
{@gt key=array_lower_with_array value=array_lower}array_lower_with_array is greater than array_lower{:else}array_lower_with_array is less than or equal to array_lower{/gt}{~n}
|
{@gt key=array_lower_with_array value=array_lower}array_lower_with_array is greater than array_lower{:else}array_lower_with_array is less than or equal to array_lower{/gt}{~n}
|
||||||
|
{@gt key=some_obj value=int}some_obj is greater than int{:else}some_obj is less than or equal to int{/gt}{~n}
|
||||||
|
{@gt key=some_obj value="[object Object]"}some_obj is greater than "[object Object]"{:else}some_obj is less than or equal to "[object Object]"{/gt}{~n}
|
||||||
|
@ -21,9 +21,9 @@ beta is {beta}{~n}
|
|||||||
{@gte key="a" value="A"}"a" is greater than or equal to "A"{:else}"a" is less than "A"{/gte}{~n}
|
{@gte key="a" value="A"}"a" is greater than or equal to "A"{:else}"a" is less than "A"{/gte}{~n}
|
||||||
{@gte key="a" value="}"}"a" is greater than or equal to "}"{:else}"a" is less than "}"{/gte}{~n}
|
{@gte key="a" value="}"}"a" is greater than or equal to "}"{:else}"a" is less than "}"{/gte}{~n}
|
||||||
{!
|
{!
|
||||||
Commented out because unicode breaks nom
|
Commented out because unicode breaks nom
|
||||||
{@gte key="☃" value="☄"}"☃" is greater than or equal to "☄"{:else}"☃" is less than "☄"{/gte}{~n}
|
{@gte key="☃" value="☄"}"☃" is greater than or equal to "☄"{:else}"☃" is less than "☄"{/gte}{~n}
|
||||||
!}
|
!}
|
||||||
{@gte key=true_value value=false_value}true is greater than or equal to false{:else}true is less than false{/gte}{~n}
|
{@gte key=true_value value=false_value}true is greater than or equal to false{:else}true is less than false{/gte}{~n}
|
||||||
{@gte key=array_lower value=array_higher}[3,5,7] is greater than or equal to [8,9]{:else}[3,5,7] is less than [8,9]{/gte}{~n}
|
{@gte key=array_lower value=array_higher}[3,5,7] is greater than or equal to [8,9]{:else}[3,5,7] is less than [8,9]{/gte}{~n}
|
||||||
{@gte key=array_higher value=array_lower}[8,9] is greater than or equal to [3,5,7]{:else}[8,9] is less than [3,5,7]{/gte}{~n}
|
{@gte key=array_higher value=array_lower}[8,9] is greater than or equal to [3,5,7]{:else}[8,9] is less than [3,5,7]{/gte}{~n}
|
||||||
@ -39,3 +39,5 @@ Commented out because unicode breaks nom
|
|||||||
{@gte key=array_higher value=array_higher_longer}array_higher is greater than or equal to array_higher_longer{:else}array_higher is less than array_higher_longer{/gte}{~n}
|
{@gte key=array_higher value=array_higher_longer}array_higher is greater than or equal to array_higher_longer{:else}array_higher is less than array_higher_longer{/gte}{~n}
|
||||||
{@gte key=array_lower value=array_lower_with_array}array_lower is greater than or equal to array_lower_with_array{:else}array_lower is less than array_lower_with_array{/gte}{~n}
|
{@gte key=array_lower value=array_lower_with_array}array_lower is greater than or equal to array_lower_with_array{:else}array_lower is less than array_lower_with_array{/gte}{~n}
|
||||||
{@gte key=array_lower_with_array value=array_lower}array_lower_with_array is greater than or equal to array_lower{:else}array_lower_with_array is less than array_lower{/gte}{~n}
|
{@gte key=array_lower_with_array value=array_lower}array_lower_with_array is greater than or equal to array_lower{:else}array_lower_with_array is less than array_lower{/gte}{~n}
|
||||||
|
{@gte key=some_obj value=int}some_obj is greater than or equal to int{:else}some_obj is less than int{/gte}{~n}
|
||||||
|
{@gte key=some_obj value="[object Object]"}some_obj is greater than or equal to "[object Object]"{:else}some_obj is less than "[object Object]"{/gte}{~n}
|
||||||
|
@ -21,9 +21,9 @@ beta is {beta}{~n}
|
|||||||
{@lt key="a" value="A"}"a" is less than "A"{:else}"a" is greater than or equal to "A"{/lt}{~n}
|
{@lt key="a" value="A"}"a" is less than "A"{:else}"a" is greater than or equal to "A"{/lt}{~n}
|
||||||
{@lt key="a" value="}"}"a" is less than "}"{:else}"a" is greater than or equal to "}"{/lt}{~n}
|
{@lt key="a" value="}"}"a" is less than "}"{:else}"a" is greater than or equal to "}"{/lt}{~n}
|
||||||
{!
|
{!
|
||||||
Commented out because unicode breaks nom
|
Commented out because unicode breaks nom
|
||||||
{@lt key="☃" value="☄"}"☃" is less than "☄"{:else}"☃" is greater than or equal to "☄"{/lt}{~n}
|
{@lt key="☃" value="☄"}"☃" is less than "☄"{:else}"☃" is greater than or equal to "☄"{/lt}{~n}
|
||||||
!}
|
!}
|
||||||
{@lt key=true_value value=false_value}true is less than false{:else}true is greater than or equal to false{/lt}{~n}
|
{@lt key=true_value value=false_value}true is less than false{:else}true is greater than or equal to false{/lt}{~n}
|
||||||
{@lt key=array_lower value=array_higher}[3,5,7] is less than [8,9]{:else}[3,5,7] is greater than or equal to [8,9]{/lt}{~n}
|
{@lt key=array_lower value=array_higher}[3,5,7] is less than [8,9]{:else}[3,5,7] is greater than or equal to [8,9]{/lt}{~n}
|
||||||
{@lt key=array_higher value=array_lower}[8,9] is less than [3,5,7]{:else}[8,9] is greater than or equal to [3,5,7]{/lt}{~n}
|
{@lt key=array_higher value=array_lower}[8,9] is less than [3,5,7]{:else}[8,9] is greater than or equal to [3,5,7]{/lt}{~n}
|
||||||
@ -39,3 +39,5 @@ Commented out because unicode breaks nom
|
|||||||
{@lt key=array_higher value=array_higher_longer}array_higher is less than array_higher_longer{:else}array_higher is greater than or equal to array_higher_longer{/lt}{~n}
|
{@lt key=array_higher value=array_higher_longer}array_higher is less than array_higher_longer{:else}array_higher is greater than or equal to array_higher_longer{/lt}{~n}
|
||||||
{@lt key=array_lower value=array_lower_with_array}array_lower is less than array_lower_with_array{:else}array_lower is greater than or equal to array_lower_with_array{/lt}{~n}
|
{@lt key=array_lower value=array_lower_with_array}array_lower is less than array_lower_with_array{:else}array_lower is greater than or equal to array_lower_with_array{/lt}{~n}
|
||||||
{@lt key=array_lower_with_array value=array_lower}array_lower_with_array is less than array_lower{:else}array_lower_with_array is greater than or equal to array_lower{/lt}{~n}
|
{@lt key=array_lower_with_array value=array_lower}array_lower_with_array is less than array_lower{:else}array_lower_with_array is greater than or equal to array_lower{/lt}{~n}
|
||||||
|
{@lt key=some_obj value=int}some_obj is less than int{:else}some_obj is greater than or equal to int{/lt}{~n}
|
||||||
|
{@lt key=some_obj value="[object Object]"}some_obj is less than "[object Object]"{:else}some_obj is greater than or equal to "[object Object]"{/lt}{~n}
|
||||||
|
@ -21,9 +21,9 @@ beta is {beta}{~n}
|
|||||||
{@lte key="a" value="A"}"a" is less than or equal to "A"{:else}"a" is greater than "A"{/lte}{~n}
|
{@lte key="a" value="A"}"a" is less than or equal to "A"{:else}"a" is greater than "A"{/lte}{~n}
|
||||||
{@lte key="a" value="}"}"a" is less than or equal to "}"{:else}"a" is greater than "}"{/lte}{~n}
|
{@lte key="a" value="}"}"a" is less than or equal to "}"{:else}"a" is greater than "}"{/lte}{~n}
|
||||||
{!
|
{!
|
||||||
Commented out because unicode breaks nom
|
Commented out because unicode breaks nom
|
||||||
{@lte key="☃" value="☄"}"☃" is less than or equal to "☄"{:else}"☃" is greater than "☄"{/lte}{~n}
|
{@lte key="☃" value="☄"}"☃" is less than or equal to "☄"{:else}"☃" is greater than "☄"{/lte}{~n}
|
||||||
!}
|
!}
|
||||||
{@lte key=true_value value=false_value}true is less than or equal to false{:else}true is greater than false{/lte}{~n}
|
{@lte key=true_value value=false_value}true is less than or equal to false{:else}true is greater than false{/lte}{~n}
|
||||||
{@lte key=array_lower value=array_higher}[3,5,7] is less than or equal to [8,9]{:else}[3,5,7] is greater than [8,9]{/lte}{~n}
|
{@lte key=array_lower value=array_higher}[3,5,7] is less than or equal to [8,9]{:else}[3,5,7] is greater than [8,9]{/lte}{~n}
|
||||||
{@lte key=array_higher value=array_lower}[8,9] is less than or equal to [3,5,7]{:else}[8,9] is greater than [3,5,7]{/lte}{~n}
|
{@lte key=array_higher value=array_lower}[8,9] is less than or equal to [3,5,7]{:else}[8,9] is greater than [3,5,7]{/lte}{~n}
|
||||||
@ -39,3 +39,5 @@ Commented out because unicode breaks nom
|
|||||||
{@lte key=array_higher value=array_higher_longer}array_higher is less than or equal to array_higher_longer{:else}array_higher is greater than array_higher_longer{/lte}{~n}
|
{@lte key=array_higher value=array_higher_longer}array_higher is less than or equal to array_higher_longer{:else}array_higher is greater than array_higher_longer{/lte}{~n}
|
||||||
{@lte key=array_lower value=array_lower_with_array}array_lower is less than or equal to array_lower_with_array{:else}array_lower is greater than array_lower_with_array{/lte}{~n}
|
{@lte key=array_lower value=array_lower_with_array}array_lower is less than or equal to array_lower_with_array{:else}array_lower is greater than array_lower_with_array{/lte}{~n}
|
||||||
{@lte key=array_lower_with_array value=array_lower}array_lower_with_array is less than or equal to array_lower{:else}array_lower_with_array is greater than array_lower{/lte}{~n}
|
{@lte key=array_lower_with_array value=array_lower}array_lower_with_array is less than or equal to array_lower{:else}array_lower_with_array is greater than array_lower{/lte}{~n}
|
||||||
|
{@lte key=some_obj value=int}some_obj is less than or equal to int{:else}some_obj is greater than int{/lte}{~n}
|
||||||
|
{@lte key=some_obj value="[object Object]"}some_obj is less than or equal to "[object Object]"{:else}some_obj is greater than "[object Object]"{/lte}{~n}
|
||||||
|
244
src/bin.rs
244
src/bin.rs
@ -2,6 +2,7 @@ extern crate nom;
|
|||||||
|
|
||||||
use crate::renderer::CompareContextElement;
|
use crate::renderer::CompareContextElement;
|
||||||
use parser::Filter;
|
use parser::Filter;
|
||||||
|
use parser::OwnedLiteral;
|
||||||
use renderer::compile_template;
|
use renderer::compile_template;
|
||||||
use renderer::CompiledTemplate;
|
use renderer::CompiledTemplate;
|
||||||
use renderer::ContextElement;
|
use renderer::ContextElement;
|
||||||
@ -142,6 +143,7 @@ impl Loopable for serde_json::Value {
|
|||||||
|
|
||||||
impl CompareContextElement for serde_json::Value {
|
impl CompareContextElement for serde_json::Value {
|
||||||
fn equals(&self, other: &dyn ContextElement) -> bool {
|
fn equals(&self, other: &dyn ContextElement) -> bool {
|
||||||
|
// println!("equals json {:?} | {:?}", self, other);
|
||||||
// Handle other serde_json::Value
|
// Handle other serde_json::Value
|
||||||
match other.to_any().downcast_ref::<Self>() {
|
match other.to_any().downcast_ref::<Self>() {
|
||||||
None => (),
|
None => (),
|
||||||
@ -155,20 +157,29 @@ impl CompareContextElement for serde_json::Value {
|
|||||||
_ => return self == other_json_value,
|
_ => return self == other_json_value,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// Handle string literals
|
// Handle literals
|
||||||
match other.to_any().downcast_ref::<String>() {
|
match other.to_any().downcast_ref::<OwnedLiteral>() {
|
||||||
None => (),
|
None => (),
|
||||||
Some(other_string) => return self.as_str().map_or(false, |s| s == other_string),
|
Some(OwnedLiteral::LString(other_string)) => {
|
||||||
}
|
return self.as_str().map_or(false, |s| s == other_string)
|
||||||
// Handle numeric literals
|
}
|
||||||
match other.to_any().downcast_ref::<u64>() {
|
Some(OwnedLiteral::LPositiveInteger(other_num)) => {
|
||||||
None => (),
|
return self.as_u64().map_or(false, |n| n == *other_num)
|
||||||
Some(other_num) => return self.as_u64().map_or(false, |n| n == *other_num),
|
}
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
||||||
|
// println!("partial_compare json {:?} | {:?}", self, other);
|
||||||
|
// Handle type coerced objects
|
||||||
|
|
||||||
|
// When doing a greater than or less than comparison,
|
||||||
|
// javascript coerces objects into "[object Object]".
|
||||||
|
if let serde_json::Value::Object(_) = self {
|
||||||
|
return OwnedLiteral::LString("[object Object]".to_owned()).partial_compare(other);
|
||||||
|
}
|
||||||
|
|
||||||
// Handle other serde_json::Value
|
// Handle other serde_json::Value
|
||||||
match other.to_any().downcast_ref::<Self>() {
|
match other.to_any().downcast_ref::<Self>() {
|
||||||
None => (),
|
None => (),
|
||||||
@ -181,63 +192,71 @@ impl CompareContextElement for serde_json::Value {
|
|||||||
(
|
(
|
||||||
serde_json::Value::Number(self_number),
|
serde_json::Value::Number(self_number),
|
||||||
serde_json::Value::Number(other_number),
|
serde_json::Value::Number(other_number),
|
||||||
) => match (
|
) => return compare_json_numbers(self_number, other_number),
|
||||||
self_number.as_f64(),
|
(
|
||||||
other_number.as_f64(),
|
serde_json::Value::String(self_string),
|
||||||
self_number.as_u64(),
|
serde_json::Value::Number(other_number),
|
||||||
other_number.as_u64(),
|
) => return compare_json_numbers(self_string, other_number),
|
||||||
self_number.as_i64(),
|
(
|
||||||
other_number.as_i64(),
|
serde_json::Value::Number(self_number),
|
||||||
) {
|
serde_json::Value::String(other_string),
|
||||||
(_, _, _, _, Some(self_int), Some(other_int)) => {
|
) => return compare_json_numbers(self_number, other_string),
|
||||||
self_int.partial_cmp(&other_int)
|
|
||||||
}
|
|
||||||
(_, _, Some(self_uint), Some(other_uint), _, _) => {
|
|
||||||
self_uint.partial_cmp(&other_uint)
|
|
||||||
}
|
|
||||||
(_, _, Some(_self_uint), _, _, Some(_other_int)) => {
|
|
||||||
// If the previous matches did not catch
|
|
||||||
// it, then other must be negative and
|
|
||||||
// self must be larger than can be
|
|
||||||
// represented with an i64, therefore self
|
|
||||||
// is greater than other.
|
|
||||||
Some(Ordering::Greater)
|
|
||||||
}
|
|
||||||
(_, _, _, Some(_other_uint), Some(_self_int), _) => {
|
|
||||||
// If the previous matches did not catch
|
|
||||||
// it, then self must be negative and
|
|
||||||
// other must be larger than can be
|
|
||||||
// represented with an i64, therefore
|
|
||||||
// other is greater than self.
|
|
||||||
Some(Ordering::Less)
|
|
||||||
}
|
|
||||||
(Some(self_float), Some(other_float), _, _, _, _) => {
|
|
||||||
self_float.partial_cmp(&other_float)
|
|
||||||
}
|
|
||||||
_ => panic!("This should be impossible since u64 and i64 can both be converted to floats"),
|
|
||||||
},
|
|
||||||
(
|
(
|
||||||
serde_json::Value::String(self_string),
|
serde_json::Value::String(self_string),
|
||||||
serde_json::Value::String(other_string),
|
serde_json::Value::String(other_string),
|
||||||
) => self_string.partial_cmp(other_string),
|
) => self_string.partial_cmp(other_string),
|
||||||
(serde_json::Value::Array(self_array), serde_json::Value::Array(other_array)) => convert_vec_to_context_element(self_array).partial_cmp(&convert_vec_to_context_element(other_array)),
|
(
|
||||||
|
serde_json::Value::Array(self_array),
|
||||||
|
serde_json::Value::Array(other_array),
|
||||||
|
) => {
|
||||||
|
return self
|
||||||
|
.render(&Vec::new())
|
||||||
|
.unwrap_or("".to_owned())
|
||||||
|
.partial_cmp(
|
||||||
|
&other_json_value
|
||||||
|
.render(&Vec::new())
|
||||||
|
.unwrap_or("".to_owned()),
|
||||||
|
)
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Handle string literals
|
// Handle literals
|
||||||
match other.to_any().downcast_ref::<String>() {
|
match other.to_any().downcast_ref::<OwnedLiteral>() {
|
||||||
None => (),
|
None => (),
|
||||||
Some(other_string) => {
|
Some(other_literal) => match (self, other_literal) {
|
||||||
return self
|
(serde_json::Value::String(self_string), OwnedLiteral::LString(other_string)) => {
|
||||||
.as_str()
|
return self_string.partial_cmp(other_string)
|
||||||
.map_or(None, |s| s.partial_cmp(other_string.as_str()))
|
}
|
||||||
}
|
(
|
||||||
}
|
serde_json::Value::String(self_string),
|
||||||
// Handle numeric literals
|
OwnedLiteral::LPositiveInteger(other_num),
|
||||||
match other.to_any().downcast_ref::<u64>() {
|
) => return compare_json_numbers(self_string, other_literal),
|
||||||
None => (),
|
(serde_json::Value::Number(self_num), OwnedLiteral::LString(other_string)) => {
|
||||||
Some(other_num) => return self.as_u64().map_or(None, |n| n.partial_cmp(other_num)),
|
return compare_json_numbers(self_num, other_string)
|
||||||
|
}
|
||||||
|
(
|
||||||
|
serde_json::Value::Number(self_num),
|
||||||
|
OwnedLiteral::LPositiveInteger(other_num),
|
||||||
|
) => return compare_json_numbers(self_num, other_literal),
|
||||||
|
(serde_json::Value::Array(_), _) => {
|
||||||
|
// TODO
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
(serde_json::Value::Object(_), _) => {
|
||||||
|
// TODO
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
(serde_json::Value::Bool(_), _) => {
|
||||||
|
// TODO
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
(serde_json::Value::Null, _) => {
|
||||||
|
// TODO
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -256,3 +275,116 @@ impl CompareContextElement for serde_json::Value {
|
|||||||
fn convert_vec_to_context_element(array: &Vec<serde_json::Value>) -> Vec<&dyn ContextElement> {
|
fn convert_vec_to_context_element(array: &Vec<serde_json::Value>) -> Vec<&dyn ContextElement> {
|
||||||
array.iter().map(|v| v as _).collect()
|
array.iter().map(|v| v as _).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum JsonNumber {
|
||||||
|
UnsignedInteger(u64),
|
||||||
|
SignedInteger(i64),
|
||||||
|
Decimal(f64),
|
||||||
|
Failure,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&String> for JsonNumber {
|
||||||
|
fn from(original: &String) -> Self {
|
||||||
|
match original.parse::<u64>() {
|
||||||
|
Ok(num) => return JsonNumber::UnsignedInteger(num),
|
||||||
|
Err(_) => (),
|
||||||
|
};
|
||||||
|
match original.parse::<i64>() {
|
||||||
|
Ok(num) => return JsonNumber::SignedInteger(num),
|
||||||
|
Err(_) => (),
|
||||||
|
};
|
||||||
|
match original.parse::<f64>() {
|
||||||
|
Ok(num) => return JsonNumber::Decimal(num),
|
||||||
|
Err(_) => (),
|
||||||
|
};
|
||||||
|
JsonNumber::Failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&serde_json::Number> for JsonNumber {
|
||||||
|
fn from(original: &serde_json::Number) -> Self {
|
||||||
|
match original.as_u64() {
|
||||||
|
Some(num) => return JsonNumber::UnsignedInteger(num),
|
||||||
|
None => (),
|
||||||
|
};
|
||||||
|
match original.as_i64() {
|
||||||
|
Some(num) => return JsonNumber::SignedInteger(num),
|
||||||
|
None => (),
|
||||||
|
};
|
||||||
|
match original.as_f64() {
|
||||||
|
Some(num) => return JsonNumber::Decimal(num),
|
||||||
|
None => (),
|
||||||
|
};
|
||||||
|
JsonNumber::Failure
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&OwnedLiteral> for JsonNumber {
|
||||||
|
fn from(original: &OwnedLiteral) -> Self {
|
||||||
|
match original {
|
||||||
|
OwnedLiteral::LPositiveInteger(num) => JsonNumber::UnsignedInteger(*num),
|
||||||
|
OwnedLiteral::LString(text) => text.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compare json numbers
|
||||||
|
///
|
||||||
|
/// While this function can be called with two strings, it would not
|
||||||
|
/// make sense because javascript does not use numeric comparisons for
|
||||||
|
/// strings
|
||||||
|
fn compare_json_numbers<S, O>(self_input: S, other_input: O) -> Option<Ordering>
|
||||||
|
where
|
||||||
|
S: Into<JsonNumber>,
|
||||||
|
O: Into<JsonNumber>,
|
||||||
|
{
|
||||||
|
let self_number: JsonNumber = self_input.into();
|
||||||
|
let other_number: JsonNumber = other_input.into();
|
||||||
|
// println!(
|
||||||
|
// "compare_number_and_string {:?} | {:?}",
|
||||||
|
// self_number, other_number
|
||||||
|
// );
|
||||||
|
// TODO: Figure out how javascript compares floats and ints
|
||||||
|
match (self_number, other_number) {
|
||||||
|
(JsonNumber::Failure, _) => return None,
|
||||||
|
(_, JsonNumber::Failure) => return None,
|
||||||
|
(JsonNumber::UnsignedInteger(self_num), JsonNumber::UnsignedInteger(other_num)) => {
|
||||||
|
return self_num.partial_cmp(&other_num)
|
||||||
|
}
|
||||||
|
(JsonNumber::UnsignedInteger(self_num), JsonNumber::SignedInteger(other_num)) => {
|
||||||
|
return Some(Ordering::Greater)
|
||||||
|
}
|
||||||
|
(JsonNumber::UnsignedInteger(self_num), JsonNumber::Decimal(other_num)) => return None,
|
||||||
|
|
||||||
|
(JsonNumber::SignedInteger(self_num), JsonNumber::UnsignedInteger(other_num)) => {
|
||||||
|
return Some(Ordering::Less)
|
||||||
|
}
|
||||||
|
(JsonNumber::SignedInteger(self_num), JsonNumber::SignedInteger(other_num)) => {
|
||||||
|
return self_num.partial_cmp(&other_num)
|
||||||
|
}
|
||||||
|
(JsonNumber::SignedInteger(self_num), JsonNumber::Decimal(other_num)) => return None,
|
||||||
|
|
||||||
|
(JsonNumber::Decimal(self_num), JsonNumber::UnsignedInteger(other_num)) => return None,
|
||||||
|
(JsonNumber::Decimal(self_num), JsonNumber::SignedInteger(other_num)) => return None,
|
||||||
|
(JsonNumber::Decimal(self_num), JsonNumber::Decimal(other_num)) => {
|
||||||
|
return self_num.partial_cmp(&other_num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nested_array_render() {
|
||||||
|
let x: serde_json::Value =
|
||||||
|
serde_json::from_str(r#"[3,5,[7,9]]"#).expect("Failed to parse json");
|
||||||
|
assert_eq!(
|
||||||
|
x.render(&Vec::new()),
|
||||||
|
Ok::<_, RenderError>("3,5,7,9".to_owned())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@ pub use parser::Body;
|
|||||||
pub use parser::DustTag;
|
pub use parser::DustTag;
|
||||||
pub use parser::Filter;
|
pub use parser::Filter;
|
||||||
pub use parser::KVPair;
|
pub use parser::KVPair;
|
||||||
|
pub use parser::OwnedLiteral;
|
||||||
pub use parser::RValue;
|
pub use parser::RValue;
|
||||||
pub use parser::Special;
|
pub use parser::Special;
|
||||||
pub use parser::Template;
|
pub use parser::Template;
|
||||||
|
@ -118,11 +118,16 @@ pub struct Partial<'a> {
|
|||||||
pub params: Vec<KVPair<'a>>,
|
pub params: Vec<KVPair<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum OwnedLiteral {
|
||||||
|
LString(String),
|
||||||
|
LPositiveInteger(u64),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum RValue<'a> {
|
pub enum RValue<'a> {
|
||||||
RVPath(Path<'a>),
|
RVPath(Path<'a>),
|
||||||
RVString(String),
|
RVLiteral(OwnedLiteral),
|
||||||
RVPositiveInteger(u64),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
@ -226,8 +231,12 @@ fn postitive_integer_literal(i: &str) -> IResult<&str, u64> {
|
|||||||
fn rvalue(i: &str) -> IResult<&str, RValue> {
|
fn rvalue(i: &str) -> IResult<&str, RValue> {
|
||||||
alt((
|
alt((
|
||||||
map(path, RValue::RVPath),
|
map(path, RValue::RVPath),
|
||||||
map(quoted_string, RValue::RVString),
|
map(quoted_string, |s| {
|
||||||
map(postitive_integer_literal, RValue::RVPositiveInteger),
|
RValue::RVLiteral(OwnedLiteral::LString(s))
|
||||||
|
}),
|
||||||
|
map(postitive_integer_literal, |num| {
|
||||||
|
RValue::RVLiteral(OwnedLiteral::LPositiveInteger(num))
|
||||||
|
}),
|
||||||
))(i)
|
))(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -911,7 +920,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
KVPair {
|
KVPair {
|
||||||
key: "animal",
|
key: "animal",
|
||||||
value: RValue::RVString("cat".to_owned())
|
value: RValue::RVLiteral(OwnedLiteral::LString("cat".to_owned()))
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@ -934,7 +943,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
KVPair {
|
KVPair {
|
||||||
key: "animal",
|
key: "animal",
|
||||||
value: RValue::RVString("cat".to_owned())
|
value: RValue::RVLiteral(OwnedLiteral::LString("cat".to_owned()))
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@ -953,11 +962,11 @@ mod tests {
|
|||||||
params: vec![
|
params: vec![
|
||||||
KVPair {
|
KVPair {
|
||||||
key: "a",
|
key: "a",
|
||||||
value: RValue::RVString("foo".to_owned())
|
value: RValue::RVLiteral(OwnedLiteral::LString("foo".to_owned()))
|
||||||
},
|
},
|
||||||
KVPair {
|
KVPair {
|
||||||
key: "b",
|
key: "b",
|
||||||
value: RValue::RVPositiveInteger(179)
|
value: RValue::RVLiteral(OwnedLiteral::LPositiveInteger(179))
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@ -980,7 +989,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
KVPair {
|
KVPair {
|
||||||
key: "value",
|
key: "value",
|
||||||
value: RValue::RVString("cat".to_owned())
|
value: RValue::RVLiteral(OwnedLiteral::LString("cat".to_owned()))
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
contents: Some(Body {
|
contents: Some(Body {
|
||||||
@ -1016,7 +1025,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
KVPair {
|
KVPair {
|
||||||
key: "value",
|
key: "value",
|
||||||
value: RValue::RVString("cat".to_owned())
|
value: RValue::RVLiteral(OwnedLiteral::LString("cat".to_owned()))
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
contents: None,
|
contents: None,
|
||||||
@ -1122,23 +1131,33 @@ mod tests {
|
|||||||
params: vec![
|
params: vec![
|
||||||
KVPair {
|
KVPair {
|
||||||
key: "v1",
|
key: "v1",
|
||||||
value: RValue::RVString("b".to_owned())
|
value: RValue::RVLiteral(OwnedLiteral::LString(
|
||||||
|
"b".to_owned()
|
||||||
|
))
|
||||||
},
|
},
|
||||||
KVPair {
|
KVPair {
|
||||||
key: "v2",
|
key: "v2",
|
||||||
value: RValue::RVString("b".to_owned())
|
value: RValue::RVLiteral(OwnedLiteral::LString(
|
||||||
|
"b".to_owned()
|
||||||
|
))
|
||||||
},
|
},
|
||||||
KVPair {
|
KVPair {
|
||||||
key: "v3",
|
key: "v3",
|
||||||
value: RValue::RVString("b".to_owned())
|
value: RValue::RVLiteral(OwnedLiteral::LString(
|
||||||
|
"b".to_owned()
|
||||||
|
))
|
||||||
},
|
},
|
||||||
KVPair {
|
KVPair {
|
||||||
key: "v4",
|
key: "v4",
|
||||||
value: RValue::RVString("b".to_owned())
|
value: RValue::RVLiteral(OwnedLiteral::LString(
|
||||||
|
"b".to_owned()
|
||||||
|
))
|
||||||
},
|
},
|
||||||
KVPair {
|
KVPair {
|
||||||
key: "v5",
|
key: "v5",
|
||||||
value: RValue::RVString("b".to_owned())
|
value: RValue::RVLiteral(OwnedLiteral::LString(
|
||||||
|
"b".to_owned()
|
||||||
|
))
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use std::fmt;
|
|||||||
/// Fatal errors while rendering.
|
/// Fatal errors while rendering.
|
||||||
///
|
///
|
||||||
/// A RenderError will halt rendering.
|
/// A RenderError will halt rendering.
|
||||||
|
#[derive(PartialEq)]
|
||||||
pub enum RenderError {
|
pub enum RenderError {
|
||||||
Generic(String),
|
Generic(String),
|
||||||
TemplateNotFound(String),
|
TemplateNotFound(String),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::parser::KVPair;
|
use crate::parser::KVPair;
|
||||||
use crate::parser::{Filter, RValue};
|
use crate::parser::{Filter, OwnedLiteral, RValue};
|
||||||
use crate::renderer::context_element::CompareContextElement;
|
use crate::renderer::context_element::CompareContextElement;
|
||||||
use crate::renderer::context_element::ContextElement;
|
use crate::renderer::context_element::ContextElement;
|
||||||
use crate::renderer::walking::owned_walk_path;
|
use crate::renderer::walking::owned_walk_path;
|
||||||
@ -21,11 +21,10 @@ use std::{cmp::Ordering, collections::HashMap};
|
|||||||
/// are imposing the cost of copying the data in the renderer because
|
/// 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
|
/// the parser has no reason to not be able to reference data from the
|
||||||
/// input string.
|
/// input string.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum OwnedRValue {
|
pub enum OwnedRValue {
|
||||||
RVPath(OwnedPath),
|
RVPath(OwnedPath),
|
||||||
RVString(String),
|
RVLiteral(OwnedLiteral),
|
||||||
RVPositiveInteger(u64),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
@ -36,11 +35,10 @@ pub struct OwnedPath {
|
|||||||
impl From<&RValue<'_>> for OwnedRValue {
|
impl From<&RValue<'_>> for OwnedRValue {
|
||||||
fn from(original: &RValue<'_>) -> Self {
|
fn from(original: &RValue<'_>) -> Self {
|
||||||
match original {
|
match original {
|
||||||
RValue::RVString(text) => OwnedRValue::RVString(text.to_owned()),
|
RValue::RVLiteral(literal) => OwnedRValue::RVLiteral(literal.clone()),
|
||||||
RValue::RVPath(path) => OwnedRValue::RVPath(OwnedPath {
|
RValue::RVPath(path) => OwnedRValue::RVPath(OwnedPath {
|
||||||
keys: path.keys.iter().map(|k| k.to_string()).collect(),
|
keys: path.keys.iter().map(|k| k.to_string()).collect(),
|
||||||
}),
|
}),
|
||||||
RValue::RVPositiveInteger(num) => OwnedRValue::RVPositiveInteger(*num),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,8 +90,7 @@ impl Walkable for ParametersContext {
|
|||||||
let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?;
|
let rval = self.params.get(segment).ok_or(WalkError::CantWalk)?;
|
||||||
match rval {
|
match rval {
|
||||||
OwnedRValue::RVPath(path) => owned_walk_path(&self.breadcrumbs, &path.keys),
|
OwnedRValue::RVPath(path) => owned_walk_path(&self.breadcrumbs, &path.keys),
|
||||||
OwnedRValue::RVString(text) => Ok(text),
|
OwnedRValue::RVLiteral(literal) => Ok(literal),
|
||||||
OwnedRValue::RVPositiveInteger(num) => Ok(num),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -129,45 +126,71 @@ impl CompareContextElement for ParametersContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextElement for String {}
|
impl ContextElement for OwnedLiteral {}
|
||||||
|
|
||||||
impl Renderable for String {
|
impl Renderable for OwnedLiteral {
|
||||||
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
|
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
|
||||||
Ok(self.clone())
|
match self {
|
||||||
}
|
OwnedLiteral::LString(text) => Ok(text.clone()),
|
||||||
}
|
OwnedLiteral::LPositiveInteger(num) => Ok(num.to_string()),
|
||||||
|
|
||||||
impl Loopable for String {
|
|
||||||
fn get_loop_elements(&self) -> Vec<&dyn ContextElement> {
|
|
||||||
if self.is_empty() {
|
|
||||||
Vec::new()
|
|
||||||
} else {
|
|
||||||
vec![self]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Walkable for String {
|
impl Loopable for OwnedLiteral {
|
||||||
|
fn get_loop_elements(&self) -> Vec<&dyn ContextElement> {
|
||||||
|
match self {
|
||||||
|
OwnedLiteral::LString(text) => {
|
||||||
|
if text.is_empty() {
|
||||||
|
Vec::new()
|
||||||
|
} else {
|
||||||
|
vec![self]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OwnedLiteral::LPositiveInteger(num) => vec![self],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Walkable for OwnedLiteral {
|
||||||
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> {
|
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> {
|
||||||
Err(WalkError::CantWalk)
|
Err(WalkError::CantWalk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompareContextElement for String {
|
impl CompareContextElement for OwnedLiteral {
|
||||||
fn equals(&self, other: &dyn ContextElement) -> bool {
|
fn equals(&self, other: &dyn ContextElement) -> bool {
|
||||||
// If its a String then compare them directly, otherwise defer
|
// println!("equals literal {:?} | {:?}", self, other);
|
||||||
// to the other type's implementation of CompareContextElement
|
// If its an OwnedLiteral then compare them directly,
|
||||||
// since the end user could add any type.
|
// 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>() {
|
match other.to_any().downcast_ref::<Self>() {
|
||||||
None => other.equals(self),
|
None => other.equals(self),
|
||||||
Some(other_string) => self == other_string,
|
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> {
|
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
||||||
// If its a string then compare them directly, otherwise defer
|
// println!("partial_compare literal {:?} | {:?}", self, other);
|
||||||
// to the other type's implementation of CompareContextElement
|
// If its an OwnedLiteral then compare them directly,
|
||||||
// since the end user could add any type.
|
// 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>() {
|
match other.to_any().downcast_ref::<Self>() {
|
||||||
None => match other.partial_compare(self) {
|
None => match other.partial_compare(self) {
|
||||||
None => None,
|
None => None,
|
||||||
@ -177,56 +200,21 @@ impl CompareContextElement for String {
|
|||||||
Ordering::Less => Some(Ordering::Greater),
|
Ordering::Less => Some(Ordering::Greater),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Some(other_string) => self.partial_cmp(other_string),
|
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)) => {
|
||||||
impl ContextElement for u64 {}
|
self_num.to_string().partial_cmp(other_text)
|
||||||
|
}
|
||||||
impl Renderable for u64 {
|
(OwnedLiteral::LString(self_text), OwnedLiteral::LPositiveInteger(other_num)) => {
|
||||||
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
|
self_text.partial_cmp(&other_num.to_string())
|
||||||
Ok(self.to_string())
|
}
|
||||||
}
|
(
|
||||||
}
|
OwnedLiteral::LPositiveInteger(self_num),
|
||||||
|
OwnedLiteral::LPositiveInteger(other_num),
|
||||||
impl Loopable for u64 {
|
) => self_num.partial_cmp(other_num),
|
||||||
fn get_loop_elements(&self) -> Vec<&dyn ContextElement> {
|
|
||||||
vec![self]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Walkable for u64 {
|
|
||||||
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> {
|
|
||||||
Err(WalkError::CantWalk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CompareContextElement for u64 {
|
|
||||||
fn equals(&self, other: &dyn ContextElement) -> bool {
|
|
||||||
// If its a u64 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_num) => self == other_num,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
|
||||||
// If its a u64 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_num) => self.partial_cmp(other_num),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,19 +343,19 @@ impl<'a> DustRenderer<'a> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
(Ok(left_side_unwrapped), Ok(right_side_unwrapped)) => {
|
(Ok(left_side_unwrapped), Ok(right_side_unwrapped)) => {
|
||||||
return match left_side_unwrapped.partial_cmp(&right_side_unwrapped) {
|
if left_side_unwrapped >= right_side_unwrapped {
|
||||||
Some(Ordering::Greater) | Some(Ordering::Equal) | None => self
|
return self.render_maybe_body(
|
||||||
.render_maybe_body(
|
¶meterized_block.contents,
|
||||||
¶meterized_block.contents,
|
breadcrumbs,
|
||||||
breadcrumbs,
|
blocks,
|
||||||
blocks,
|
);
|
||||||
),
|
} else {
|
||||||
Some(Ordering::Less) => self.render_maybe_body(
|
return self.render_maybe_body(
|
||||||
¶meterized_block.else_contents,
|
¶meterized_block.else_contents,
|
||||||
breadcrumbs,
|
breadcrumbs,
|
||||||
blocks,
|
blocks,
|
||||||
),
|
);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -415,19 +415,19 @@ impl<'a> DustRenderer<'a> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
(Ok(left_side_unwrapped), Ok(right_side_unwrapped)) => {
|
(Ok(left_side_unwrapped), Ok(right_side_unwrapped)) => {
|
||||||
return match left_side_unwrapped.partial_cmp(&right_side_unwrapped) {
|
if left_side_unwrapped <= right_side_unwrapped {
|
||||||
Some(Ordering::Less) | Some(Ordering::Equal) | None => self
|
return self.render_maybe_body(
|
||||||
.render_maybe_body(
|
¶meterized_block.contents,
|
||||||
¶meterized_block.contents,
|
breadcrumbs,
|
||||||
breadcrumbs,
|
blocks,
|
||||||
blocks,
|
);
|
||||||
),
|
} else {
|
||||||
Some(Ordering::Greater) => self.render_maybe_body(
|
return self.render_maybe_body(
|
||||||
¶meterized_block.else_contents,
|
¶meterized_block.else_contents,
|
||||||
breadcrumbs,
|
breadcrumbs,
|
||||||
blocks,
|
blocks,
|
||||||
),
|
);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,9 +477,8 @@ impl<'a> DustRenderer<'a> {
|
|||||||
match param_map.get(key) {
|
match param_map.get(key) {
|
||||||
None => None,
|
None => None,
|
||||||
Some(rval) => match rval {
|
Some(rval) => match rval {
|
||||||
RValue::RVString(text) => Some(Ok(text)),
|
RValue::RVLiteral(literal) => Some(Ok(literal)),
|
||||||
RValue::RVPath(path) => Some(walk_path(breadcrumbs, &path.keys)),
|
RValue::RVPath(path) => Some(walk_path(breadcrumbs, &path.keys)),
|
||||||
RValue::RVPositiveInteger(num) => Some(Ok(num)),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -494,6 +493,81 @@ mod tests {
|
|||||||
use crate::renderer::context_element::Walkable;
|
use crate::renderer::context_element::Walkable;
|
||||||
use crate::renderer::CompareContextElement;
|
use crate::renderer::CompareContextElement;
|
||||||
|
|
||||||
|
impl ContextElement for String {}
|
||||||
|
|
||||||
|
impl Renderable for String {
|
||||||
|
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
|
||||||
|
Ok(self.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Loopable for String {
|
||||||
|
fn get_loop_elements(&self) -> Vec<&dyn ContextElement> {
|
||||||
|
if self.is_empty() {
|
||||||
|
Vec::new()
|
||||||
|
} else {
|
||||||
|
vec![self]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Walkable for String {
|
||||||
|
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> {
|
||||||
|
Err(WalkError::CantWalk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompareContextElement for String {
|
||||||
|
fn equals(&self, other: &dyn ContextElement) -> bool {
|
||||||
|
match other.to_any().downcast_ref::<Self>() {
|
||||||
|
None => false,
|
||||||
|
Some(other_string) => self == other_string,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
||||||
|
match other.to_any().downcast_ref::<Self>() {
|
||||||
|
None => None,
|
||||||
|
Some(other_string) => self.partial_cmp(other_string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ContextElement for u64 {}
|
||||||
|
|
||||||
|
impl Renderable for u64 {
|
||||||
|
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
|
||||||
|
Ok(self.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Loopable for u64 {
|
||||||
|
fn get_loop_elements(&self) -> Vec<&dyn ContextElement> {
|
||||||
|
vec![self]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Walkable for u64 {
|
||||||
|
fn walk(&self, segment: &str) -> Result<&dyn ContextElement, WalkError> {
|
||||||
|
Err(WalkError::CantWalk)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompareContextElement for u64 {
|
||||||
|
fn equals(&self, other: &dyn ContextElement) -> bool {
|
||||||
|
match other.to_any().downcast_ref::<Self>() {
|
||||||
|
None => false,
|
||||||
|
Some(other_num) => self == other_num,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
||||||
|
match other.to_any().downcast_ref::<Self>() {
|
||||||
|
None => None,
|
||||||
|
Some(other_num) => self.partial_cmp(other_num),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<I: 'static + ContextElement + Clone> ContextElement for HashMap<String, I> {}
|
impl<I: 'static + ContextElement + Clone> ContextElement for HashMap<String, I> {}
|
||||||
|
|
||||||
impl<I: ContextElement> Renderable for HashMap<String, I> {
|
impl<I: ContextElement> Renderable for HashMap<String, I> {
|
||||||
@ -520,6 +594,11 @@ mod tests {
|
|||||||
fn equals(&self, other: &dyn ContextElement) -> bool {
|
fn equals(&self, other: &dyn ContextElement) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
|
||||||
|
// TODO: Implement
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user