Move ComparisonNumber into the library and add an OwnedLiteral for booleans.
This commit is contained in:
parent
8ab315abfe
commit
83c86ff9b3
112
src/bin.rs
112
src/bin.rs
@ -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 {
|
||||
|
@ -123,6 +123,11 @@ pub enum OwnedLiteral {
|
||||
LPositiveInteger(u64),
|
||||
LNegativeInteger(i64),
|
||||
LFloat(f64),
|
||||
// Unlike the other OwnedLiterals, booleans cannot occur in DustJS
|
||||
// templates because true/false are not reserved
|
||||
// names. Regardless, they are needed here for type casting in the
|
||||
// renderer.
|
||||
LBoolean(bool),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
89
src/renderer/comparison_number.rs
Normal file
89
src/renderer/comparison_number.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ComparisonNumber {
|
||||
UnsignedInteger(u64),
|
||||
SignedInteger(i64),
|
||||
Decimal(f64),
|
||||
Failure,
|
||||
}
|
||||
|
||||
/// 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
|
||||
pub 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<&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
|
||||
}
|
||||
}
|
@ -18,6 +18,13 @@ impl From<&OwnedLiteral> for MathNumber {
|
||||
fn from(original: &OwnedLiteral) -> Self {
|
||||
match original {
|
||||
OwnedLiteral::LString(_) => panic!("Strings should not be cast to numbers for math"),
|
||||
OwnedLiteral::LBoolean(boolean) => {
|
||||
if *boolean {
|
||||
MathNumber::Integer(1)
|
||||
} else {
|
||||
MathNumber::Integer(0)
|
||||
}
|
||||
}
|
||||
OwnedLiteral::LPositiveInteger(num) => {
|
||||
return MathNumber::Integer((*num).try_into().unwrap())
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! This module contains a renderer for a rust implementation of LinkedIn Dust
|
||||
|
||||
mod breadcrumb_tree;
|
||||
mod comparison_number;
|
||||
mod context_element;
|
||||
mod errors;
|
||||
mod inline_partial_tree;
|
||||
@ -11,6 +12,8 @@ mod renderer;
|
||||
mod select_context;
|
||||
mod walking;
|
||||
|
||||
pub use comparison_number::compare_json_numbers;
|
||||
pub use comparison_number::ComparisonNumber;
|
||||
pub use context_element::Castable;
|
||||
pub use context_element::CompareContextElement;
|
||||
pub use context_element::ContextElement;
|
||||
|
@ -3,6 +3,8 @@ use crate::parser::KVPair;
|
||||
use crate::parser::OwnedLiteral;
|
||||
use crate::parser::RValue;
|
||||
use crate::renderer::breadcrumb_tree::BreadcrumbTreeElement;
|
||||
use crate::renderer::comparison_number::compare_json_numbers;
|
||||
use crate::renderer::comparison_number::ComparisonNumber;
|
||||
use crate::renderer::context_element::CompareContextElement;
|
||||
use crate::renderer::context_element::ContextElement;
|
||||
use crate::renderer::context_element::IceResult;
|
||||
@ -160,6 +162,7 @@ impl ContextElement for OwnedLiteral {}
|
||||
impl Truthiness for OwnedLiteral {
|
||||
fn is_truthy(&self) -> bool {
|
||||
match self {
|
||||
OwnedLiteral::LBoolean(boolean) => *boolean,
|
||||
OwnedLiteral::LString(text) => !text.is_empty(),
|
||||
OwnedLiteral::LPositiveInteger(_num) => true,
|
||||
OwnedLiteral::LNegativeInteger(_num) => true,
|
||||
@ -171,6 +174,7 @@ impl Truthiness for OwnedLiteral {
|
||||
impl Renderable for OwnedLiteral {
|
||||
fn render(&self, _filters: &Vec<Filter>) -> Result<String, RenderError> {
|
||||
match self {
|
||||
OwnedLiteral::LBoolean(boolean) => Ok(boolean.to_string()),
|
||||
OwnedLiteral::LString(text) => Ok(text.clone()),
|
||||
OwnedLiteral::LPositiveInteger(num) => Ok(num.to_string()),
|
||||
OwnedLiteral::LNegativeInteger(num) => Ok(num.to_string()),
|
||||
@ -194,6 +198,9 @@ impl Walkable for OwnedLiteral {
|
||||
impl Sizable for OwnedLiteral {
|
||||
fn get_size<'a>(&'a self) -> Option<IceResult<'a>> {
|
||||
match self {
|
||||
OwnedLiteral::LBoolean(_) => {
|
||||
Some(IceResult::from_owned(OwnedLiteral::LPositiveInteger(0)))
|
||||
}
|
||||
OwnedLiteral::LFloat(_) => Some(IceResult::from_borrowed(self)),
|
||||
OwnedLiteral::LPositiveInteger(_) => Some(IceResult::from_borrowed(self)),
|
||||
OwnedLiteral::LNegativeInteger(_) => Some(IceResult::from_borrowed(self)),
|
||||
@ -258,9 +265,11 @@ impl CompareContextElement for OwnedLiteral {
|
||||
OwnedLiteral::LNegativeInteger(self_num),
|
||||
OwnedLiteral::LNegativeInteger(other_num),
|
||||
) => self_num == other_num,
|
||||
(OwnedLiteral::LString(_self_text), _) | (_, OwnedLiteral::LString(_self_text)) => {
|
||||
false
|
||||
(OwnedLiteral::LBoolean(self_bool), OwnedLiteral::LBoolean(other_bool)) => {
|
||||
self_bool == other_bool
|
||||
}
|
||||
(OwnedLiteral::LString(_), _) | (_, OwnedLiteral::LString(_)) => false,
|
||||
(OwnedLiteral::LBoolean(_), _) | (_, OwnedLiteral::LBoolean(_)) => false,
|
||||
(OwnedLiteral::LFloat(self_num), OwnedLiteral::LFloat(other_num)) => {
|
||||
self_num == other_num
|
||||
}
|
||||
@ -315,70 +324,12 @@ impl CompareContextElement for OwnedLiteral {
|
||||
},
|
||||
},
|
||||
Some(other_literal) => match (self, other_literal) {
|
||||
// If they're both strings, compare them directly
|
||||
(OwnedLiteral::LString(self_text), OwnedLiteral::LString(other_text)) => {
|
||||
self_text.partial_cmp(other_text)
|
||||
}
|
||||
(
|
||||
OwnedLiteral::LPositiveInteger(self_num),
|
||||
OwnedLiteral::LPositiveInteger(other_num),
|
||||
) => self_num.partial_cmp(other_num),
|
||||
(
|
||||
OwnedLiteral::LNegativeInteger(self_num),
|
||||
OwnedLiteral::LNegativeInteger(other_num),
|
||||
) => self_num.partial_cmp(other_num),
|
||||
(OwnedLiteral::LFloat(self_num), OwnedLiteral::LFloat(other_num)) => {
|
||||
self_num.partial_cmp(other_num)
|
||||
}
|
||||
(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::LNegativeInteger(self_num), OwnedLiteral::LString(other_text)) => {
|
||||
self_num.to_string().partial_cmp(other_text)
|
||||
}
|
||||
(OwnedLiteral::LString(self_text), OwnedLiteral::LNegativeInteger(other_num)) => {
|
||||
self_text.partial_cmp(&other_num.to_string())
|
||||
}
|
||||
(OwnedLiteral::LFloat(self_num), OwnedLiteral::LString(other_text)) => {
|
||||
self_num.to_string().partial_cmp(other_text)
|
||||
}
|
||||
(OwnedLiteral::LString(self_text), OwnedLiteral::LFloat(other_num)) => {
|
||||
self_text.partial_cmp(&other_num.to_string())
|
||||
}
|
||||
(OwnedLiteral::LPositiveInteger(self_num), OwnedLiteral::LFloat(other_num)) => {
|
||||
(*self_num as f64).partial_cmp(other_num)
|
||||
}
|
||||
(OwnedLiteral::LFloat(self_num), OwnedLiteral::LPositiveInteger(other_num)) => {
|
||||
self_num.partial_cmp(&(*other_num as f64))
|
||||
}
|
||||
(OwnedLiteral::LNegativeInteger(self_num), OwnedLiteral::LFloat(other_num)) => {
|
||||
(*self_num as f64).partial_cmp(other_num)
|
||||
}
|
||||
(OwnedLiteral::LFloat(self_num), OwnedLiteral::LNegativeInteger(other_num)) => {
|
||||
self_num.partial_cmp(&(*other_num as f64))
|
||||
}
|
||||
(
|
||||
OwnedLiteral::LPositiveInteger(self_num),
|
||||
OwnedLiteral::LNegativeInteger(other_num),
|
||||
) => {
|
||||
if *self_num < std::i64::MAX as u64 {
|
||||
(*self_num as i64).partial_cmp(other_num)
|
||||
} else {
|
||||
Some(Ordering::Greater)
|
||||
}
|
||||
}
|
||||
(
|
||||
OwnedLiteral::LNegativeInteger(self_num),
|
||||
OwnedLiteral::LPositiveInteger(other_num),
|
||||
) => {
|
||||
if *other_num < std::i64::MAX as u64 {
|
||||
self_num.partial_cmp(&(*other_num as i64))
|
||||
} else {
|
||||
Some(Ordering::Less)
|
||||
}
|
||||
}
|
||||
// Otherwise, convert to numbers and compare them that way
|
||||
(_, _) => return compare_json_numbers(self, other_literal),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -481,3 +432,27 @@ impl CompareContextElement for OwnedLiteral {
|
||||
.map(IceResult::from_owned)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&OwnedLiteral> for ComparisonNumber {
|
||||
fn from(original: &OwnedLiteral) -> Self {
|
||||
match original {
|
||||
OwnedLiteral::LBoolean(boolean) => {
|
||||
if *boolean {
|
||||
ComparisonNumber::UnsignedInteger(1)
|
||||
} else {
|
||||
ComparisonNumber::UnsignedInteger(0)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user