Move MathNumber into the library.
While this will be used for the OwnedLiterals since they must always exhibit the original DustJS behavior, I am going to keep exposing separate math functions for ContextElement instead of simply requiring them to implement Into<MathNumber> since people might want to implement math in unusual ways with unusual types.
This commit is contained in:
parent
d9ce011113
commit
d6ad7c28f3
45
src/bin.rs
45
src/bin.rs
@ -5,13 +5,13 @@ use parser::Filter;
|
|||||||
use parser::OwnedLiteral;
|
use parser::OwnedLiteral;
|
||||||
use parser::Template;
|
use parser::Template;
|
||||||
use renderer::compile_template;
|
use renderer::compile_template;
|
||||||
use renderer::math_ints;
|
|
||||||
use renderer::CompileError;
|
use renderer::CompileError;
|
||||||
use renderer::ContextElement;
|
use renderer::ContextElement;
|
||||||
use renderer::DustRenderer;
|
use renderer::DustRenderer;
|
||||||
use renderer::IceResult;
|
use renderer::IceResult;
|
||||||
use renderer::IntoContextElement;
|
use renderer::IntoContextElement;
|
||||||
use renderer::Loopable;
|
use renderer::Loopable;
|
||||||
|
use renderer::MathNumber;
|
||||||
use renderer::RenderError;
|
use renderer::RenderError;
|
||||||
use renderer::Renderable;
|
use renderer::Renderable;
|
||||||
use renderer::Truthiness;
|
use renderer::Truthiness;
|
||||||
@ -22,7 +22,6 @@ use std::convert::TryInto;
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::ops::Add;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
mod parser;
|
mod parser;
|
||||||
@ -561,13 +560,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum MathNumber {
|
|
||||||
Integer(i128),
|
|
||||||
Decimal(f64),
|
|
||||||
Failure,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&serde_json::Value> for MathNumber {
|
impl From<&serde_json::Value> for MathNumber {
|
||||||
fn from(original: &serde_json::Value) -> Self {
|
fn from(original: &serde_json::Value) -> Self {
|
||||||
match original {
|
match original {
|
||||||
@ -611,41 +603,6 @@ impl From<&serde_json::Number> for MathNumber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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::LPositiveInteger(num) => {
|
|
||||||
return MathNumber::Integer((*num).try_into().unwrap())
|
|
||||||
}
|
|
||||||
OwnedLiteral::LNegativeInteger(num) => return MathNumber::Integer((*num).into()),
|
|
||||||
OwnedLiteral::LFloat(num) => return MathNumber::Decimal(*num),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add<MathNumber> for MathNumber {
|
|
||||||
type Output = Option<OwnedLiteral>;
|
|
||||||
|
|
||||||
fn add(self, other: MathNumber) -> Self::Output {
|
|
||||||
match (self, other) {
|
|
||||||
(MathNumber::Failure, _) | (_, MathNumber::Failure) => None,
|
|
||||||
(MathNumber::Integer(self_num), MathNumber::Integer(other_num)) => {
|
|
||||||
math_ints(self_num, other_num, std::ops::Add::add)
|
|
||||||
}
|
|
||||||
(MathNumber::Decimal(self_num), MathNumber::Decimal(other_num)) => {
|
|
||||||
Some(OwnedLiteral::LFloat(self_num + other_num))
|
|
||||||
}
|
|
||||||
(MathNumber::Integer(self_num), MathNumber::Decimal(other_num)) => {
|
|
||||||
Some(OwnedLiteral::LFloat((self_num as f64) + other_num))
|
|
||||||
}
|
|
||||||
(MathNumber::Decimal(self_num), MathNumber::Integer(other_num)) => {
|
|
||||||
Some(OwnedLiteral::LFloat(self_num + (other_num as f64)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
76
src/renderer/math.rs
Normal file
76
src/renderer/math.rs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
use crate::parser::OwnedLiteral;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum MathNumber {
|
||||||
|
Integer(i128),
|
||||||
|
Decimal(f64),
|
||||||
|
Failure,
|
||||||
|
}
|
||||||
|
|
||||||
|
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::LPositiveInteger(num) => {
|
||||||
|
return MathNumber::Integer((*num).try_into().unwrap())
|
||||||
|
}
|
||||||
|
OwnedLiteral::LNegativeInteger(num) => return MathNumber::Integer((*num).into()),
|
||||||
|
OwnedLiteral::LFloat(num) => return MathNumber::Decimal(*num),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add<MathNumber> for MathNumber {
|
||||||
|
type Output = Option<OwnedLiteral>;
|
||||||
|
|
||||||
|
fn add(self, other: MathNumber) -> Self::Output {
|
||||||
|
match (self, other) {
|
||||||
|
(MathNumber::Failure, _) | (_, MathNumber::Failure) => None,
|
||||||
|
(MathNumber::Integer(self_num), MathNumber::Integer(other_num)) => {
|
||||||
|
math_ints(self_num, other_num, std::ops::Add::add)
|
||||||
|
}
|
||||||
|
(MathNumber::Decimal(self_num), MathNumber::Decimal(other_num)) => {
|
||||||
|
Some(OwnedLiteral::LFloat(self_num + other_num))
|
||||||
|
}
|
||||||
|
(MathNumber::Integer(self_num), MathNumber::Decimal(other_num)) => {
|
||||||
|
Some(OwnedLiteral::LFloat((self_num as f64) + other_num))
|
||||||
|
}
|
||||||
|
(MathNumber::Decimal(self_num), MathNumber::Integer(other_num)) => {
|
||||||
|
Some(OwnedLiteral::LFloat(self_num + (other_num as f64)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For math operations that take in integers and return integers
|
||||||
|
/// (add, subtract, multiply)
|
||||||
|
pub fn math_ints<L, R, F>(left: L, right: R, operation: F) -> Option<OwnedLiteral>
|
||||||
|
where
|
||||||
|
L: Into<i128>,
|
||||||
|
R: Into<i128>,
|
||||||
|
F: Fn(i128, i128) -> i128,
|
||||||
|
{
|
||||||
|
let result = operation(left.into(), right.into());
|
||||||
|
std::convert::TryInto::<u64>::try_into(result)
|
||||||
|
.map(OwnedLiteral::LPositiveInteger)
|
||||||
|
.ok()
|
||||||
|
.or(std::convert::TryInto::<i64>::try_into(result)
|
||||||
|
.map(OwnedLiteral::LNegativeInteger)
|
||||||
|
.ok())
|
||||||
|
}
|
||||||
|
|
||||||
|
// /// For math operations that take in integers and return integers
|
||||||
|
// /// (add, subtract, multiply)
|
||||||
|
// fn math_floats<L, R, F>(left: L, right: R, operation: F) -> Option<OwnedLiteral>
|
||||||
|
// where
|
||||||
|
// L: Into<f64>,
|
||||||
|
// R: Into<f64>,
|
||||||
|
// F: Fn(f64, f64) -> f64,
|
||||||
|
// {
|
||||||
|
// let result = operation(left.into(), right.into());
|
||||||
|
// std::convert::TryInto::<f64>::try_into(result)
|
||||||
|
// .map(OwnedLiteral::LFloat)
|
||||||
|
// .ok()
|
||||||
|
// }
|
@ -5,6 +5,7 @@ mod context_element;
|
|||||||
mod errors;
|
mod errors;
|
||||||
mod inline_partial_tree;
|
mod inline_partial_tree;
|
||||||
mod iteration_context;
|
mod iteration_context;
|
||||||
|
mod math;
|
||||||
mod parameters_context;
|
mod parameters_context;
|
||||||
mod renderer;
|
mod renderer;
|
||||||
mod select_context;
|
mod select_context;
|
||||||
@ -21,7 +22,7 @@ pub use context_element::Walkable;
|
|||||||
pub use errors::CompileError;
|
pub use errors::CompileError;
|
||||||
pub use errors::RenderError;
|
pub use errors::RenderError;
|
||||||
pub use errors::WalkError;
|
pub use errors::WalkError;
|
||||||
pub use parameters_context::math_ints;
|
pub use math::MathNumber;
|
||||||
pub use renderer::compile_template;
|
pub use renderer::compile_template;
|
||||||
pub use renderer::DustRenderer;
|
pub use renderer::DustRenderer;
|
||||||
pub use select_context::SelectContext;
|
pub use select_context::SelectContext;
|
||||||
|
@ -7,6 +7,7 @@ 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::IceResult;
|
||||||
use crate::renderer::context_element::IntoContextElement;
|
use crate::renderer::context_element::IntoContextElement;
|
||||||
|
use crate::renderer::math::MathNumber;
|
||||||
use crate::renderer::walking::walk_path;
|
use crate::renderer::walking::walk_path;
|
||||||
use crate::renderer::DustRenderer;
|
use crate::renderer::DustRenderer;
|
||||||
use crate::renderer::Loopable;
|
use crate::renderer::Loopable;
|
||||||
@ -18,7 +19,6 @@ use crate::renderer::Walkable;
|
|||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryInto;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParametersContext<'a> {
|
pub struct ParametersContext<'a> {
|
||||||
@ -334,85 +334,12 @@ impl CompareContextElement for OwnedLiteral {
|
|||||||
// type.
|
// type.
|
||||||
match other.to_any().downcast_ref::<Self>() {
|
match other.to_any().downcast_ref::<Self>() {
|
||||||
None => other.math_add(self),
|
None => other.math_add(self),
|
||||||
Some(other_literal) => {
|
Some(other_literal) => match (self, other_literal) {
|
||||||
match (self, other_literal) {
|
(OwnedLiteral::LString(_), _) | (_, OwnedLiteral::LString(_)) => None,
|
||||||
(OwnedLiteral::LString(_), _) | (_, OwnedLiteral::LString(_)) => None,
|
(_, _) => (std::convert::Into::<MathNumber>::into(self)
|
||||||
(
|
+ std::convert::Into::<MathNumber>::into(other_literal))
|
||||||
OwnedLiteral::LPositiveInteger(self_num),
|
.map(IceResult::from_owned),
|
||||||
OwnedLiteral::LPositiveInteger(other_num),
|
},
|
||||||
) => math_ints(*self_num, *other_num, std::ops::Add::add)
|
|
||||||
.map(IceResult::from_owned),
|
|
||||||
(
|
|
||||||
OwnedLiteral::LNegativeInteger(self_num),
|
|
||||||
OwnedLiteral::LNegativeInteger(other_num),
|
|
||||||
) => math_ints(*self_num, *other_num, std::ops::Add::add)
|
|
||||||
.map(IceResult::from_owned),
|
|
||||||
(
|
|
||||||
OwnedLiteral::LPositiveInteger(self_num),
|
|
||||||
OwnedLiteral::LNegativeInteger(other_num),
|
|
||||||
) => math_ints(*self_num, *other_num, std::ops::Add::add)
|
|
||||||
.map(IceResult::from_owned),
|
|
||||||
(
|
|
||||||
OwnedLiteral::LNegativeInteger(self_num),
|
|
||||||
OwnedLiteral::LPositiveInteger(other_num),
|
|
||||||
) => math_ints(*self_num, *other_num, std::ops::Add::add)
|
|
||||||
.map(IceResult::from_owned),
|
|
||||||
(OwnedLiteral::LFloat(self_num), OwnedLiteral::LFloat(other_num)) => Some(
|
|
||||||
IceResult::from_owned(OwnedLiteral::LFloat(self_num + other_num)),
|
|
||||||
),
|
|
||||||
(OwnedLiteral::LFloat(self_num), OwnedLiteral::LPositiveInteger(other_num)) => {
|
|
||||||
Some(IceResult::from_owned(OwnedLiteral::LFloat(
|
|
||||||
self_num + (*other_num as f64),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
(OwnedLiteral::LPositiveInteger(self_num), OwnedLiteral::LFloat(other_num)) => {
|
|
||||||
Some(IceResult::from_owned(OwnedLiteral::LFloat(
|
|
||||||
(*self_num as f64) + other_num,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
(OwnedLiteral::LFloat(self_num), OwnedLiteral::LNegativeInteger(other_num)) => {
|
|
||||||
Some(IceResult::from_owned(OwnedLiteral::LFloat(
|
|
||||||
self_num + (*other_num as f64),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
(OwnedLiteral::LNegativeInteger(self_num), OwnedLiteral::LFloat(other_num)) => {
|
|
||||||
Some(IceResult::from_owned(OwnedLiteral::LFloat(
|
|
||||||
(*self_num as f64) + other_num,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For math operations that take in integers and return integers
|
|
||||||
/// (add, subtract, multiply)
|
|
||||||
pub fn math_ints<L, R, F>(left: L, right: R, operation: F) -> Option<OwnedLiteral>
|
|
||||||
where
|
|
||||||
L: Into<i128>,
|
|
||||||
R: Into<i128>,
|
|
||||||
F: Fn(i128, i128) -> i128,
|
|
||||||
{
|
|
||||||
let result = operation(left.into(), right.into());
|
|
||||||
std::convert::TryInto::<u64>::try_into(result)
|
|
||||||
.map(OwnedLiteral::LPositiveInteger)
|
|
||||||
.ok()
|
|
||||||
.or(std::convert::TryInto::<i64>::try_into(result)
|
|
||||||
.map(OwnedLiteral::LNegativeInteger)
|
|
||||||
.ok())
|
|
||||||
}
|
|
||||||
|
|
||||||
// /// For math operations that take in integers and return integers
|
|
||||||
// /// (add, subtract, multiply)
|
|
||||||
// fn math_floats<L, R, F>(left: L, right: R, operation: F) -> Option<OwnedLiteral>
|
|
||||||
// where
|
|
||||||
// L: Into<f64>,
|
|
||||||
// R: Into<f64>,
|
|
||||||
// F: Fn(f64, f64) -> f64,
|
|
||||||
// {
|
|
||||||
// let result = operation(left.into(), right.into());
|
|
||||||
// std::convert::TryInto::<f64>::try_into(result)
|
|
||||||
// .map(OwnedLiteral::LFloat)
|
|
||||||
// .ok()
|
|
||||||
// }
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user