Move ComparisonNumber into the library and add an OwnedLiteral for booleans.

This commit is contained in:
Tom Alexander
2020-06-14 17:08:01 -04:00
parent 8ab315abfe
commit 83c86ff9b3
6 changed files with 148 additions and 169 deletions

View File

@@ -4,8 +4,10 @@ use crate::renderer::CompareContextElement;
use parser::Filter;
use parser::OwnedLiteral;
use parser::Template;
use renderer::compare_json_numbers;
use renderer::compile_template;
use renderer::Castable;
use renderer::ComparisonNumber;
use renderer::CompileError;
use renderer::ContextElement;
use renderer::DustRenderer;
@@ -399,6 +401,9 @@ impl CompareContextElement for serde_json::Value {
Some(OwnedLiteral::LString(other_string)) => {
return self.as_str().map_or(false, |s| s == other_string)
}
Some(OwnedLiteral::LBoolean(boolean)) => {
return self.equals(&serde_json::Value::Bool(*boolean) as &dyn ContextElement);
}
Some(OwnedLiteral::LPositiveInteger(other_num)) => {
let other_json_num: serde_json::Number = std::convert::From::from(*other_num);
return self
@@ -450,7 +455,7 @@ impl CompareContextElement for serde_json::Value {
_,
Some(OwnedLiteral::LString(other_string)),
) => return self_string.partial_cmp(&other_string),
// Otherwise, convert to numbers are compare them that way
// Otherwise, convert to numbers and compare them that way
(_, Some(json_other), _) => return compare_json_numbers(self, json_other),
(_, _, Some(literal_other)) => return compare_json_numbers(self, literal_other),
_ => panic!("Unimplemented comparison type."),
@@ -606,14 +611,6 @@ impl CompareContextElement for serde_json::Value {
}
}
#[derive(Debug)]
enum ComparisonNumber {
UnsignedInteger(u64),
SignedInteger(i64),
Decimal(f64),
Failure,
}
impl From<&serde_json::Value> for ComparisonNumber {
/// Convert from a JSON value to a number for comparison based on
/// the logic described at
@@ -640,24 +637,6 @@ impl From<&serde_json::Value> for ComparisonNumber {
}
}
impl From<&String> for ComparisonNumber {
fn from(original: &String) -> Self {
match original.parse::<u64>() {
Ok(num) => return ComparisonNumber::UnsignedInteger(num),
Err(_) => (),
};
match original.parse::<i64>() {
Ok(num) => return ComparisonNumber::SignedInteger(num),
Err(_) => (),
};
match original.parse::<f64>() {
Ok(num) => return ComparisonNumber::Decimal(num),
Err(_) => (),
};
ComparisonNumber::Failure
}
}
impl From<&serde_json::Number> for ComparisonNumber {
fn from(original: &serde_json::Number) -> Self {
match original.as_u64() {
@@ -676,85 +655,6 @@ impl From<&serde_json::Number> for ComparisonNumber {
}
}
impl From<&OwnedLiteral> for ComparisonNumber {
fn from(original: &OwnedLiteral) -> Self {
match original {
OwnedLiteral::LPositiveInteger(num) => ComparisonNumber::UnsignedInteger(*num),
OwnedLiteral::LNegativeInteger(num) => ComparisonNumber::SignedInteger(*num),
OwnedLiteral::LString(text) => text.into(),
OwnedLiteral::LFloat(num) => {
if num.is_nan() {
ComparisonNumber::Failure
} else {
ComparisonNumber::Decimal(*num)
}
}
}
}
}
/// 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<ComparisonNumber>,
O: Into<ComparisonNumber>,
{
let self_number: ComparisonNumber = self_input.into();
let other_number: ComparisonNumber = other_input.into();
match (self_number, other_number) {
(ComparisonNumber::Failure, _) => return None,
(_, ComparisonNumber::Failure) => return None,
(
ComparisonNumber::UnsignedInteger(self_num),
ComparisonNumber::UnsignedInteger(other_num),
) => return self_num.partial_cmp(&other_num),
(
ComparisonNumber::UnsignedInteger(self_num),
ComparisonNumber::SignedInteger(other_num),
) => {
if self_num < std::i64::MAX as u64 {
return (self_num as i64).partial_cmp(&other_num);
} else {
return Some(Ordering::Greater);
}
}
(ComparisonNumber::UnsignedInteger(self_num), ComparisonNumber::Decimal(other_num)) => {
return (self_num as f64).partial_cmp(&other_num)
}
(
ComparisonNumber::SignedInteger(self_num),
ComparisonNumber::UnsignedInteger(other_num),
) => {
if other_num < std::i64::MAX as u64 {
return self_num.partial_cmp(&(other_num as i64));
} else {
return Some(Ordering::Less);
}
}
(ComparisonNumber::SignedInteger(self_num), ComparisonNumber::SignedInteger(other_num)) => {
return self_num.partial_cmp(&other_num)
}
(ComparisonNumber::SignedInteger(self_num), ComparisonNumber::Decimal(other_num)) => {
return (self_num as f64).partial_cmp(&other_num)
}
(ComparisonNumber::Decimal(self_num), ComparisonNumber::UnsignedInteger(other_num)) => {
return self_num.partial_cmp(&(other_num as f64))
}
(ComparisonNumber::Decimal(self_num), ComparisonNumber::SignedInteger(other_num)) => {
return self_num.partial_cmp(&(other_num as f64))
}
(ComparisonNumber::Decimal(self_num), ComparisonNumber::Decimal(other_num)) => {
return self_num.partial_cmp(&other_num)
}
}
}
impl From<&serde_json::Value> for MathNumber {
fn from(original: &serde_json::Value) -> Self {
match original {