Add implementation based on MathNumber.
This commit is contained in:
parent
df0ae05648
commit
d9ce011113
139
src/bin.rs
139
src/bin.rs
@ -18,9 +18,11 @@ use renderer::Truthiness;
|
||||
use renderer::WalkError;
|
||||
use renderer::Walkable;
|
||||
use std::cmp::Ordering;
|
||||
use std::convert::TryInto;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::{self, Read};
|
||||
use std::ops::Add;
|
||||
use std::path::Path;
|
||||
|
||||
mod parser;
|
||||
@ -391,11 +393,9 @@ impl CompareContextElement for serde_json::Value {
|
||||
}
|
||||
|
||||
fn math_add<'a>(&self, other: &dyn ContextElement) -> Option<IceResult<'a>> {
|
||||
match (
|
||||
self,
|
||||
other.to_any().downcast_ref::<Self>(),
|
||||
other.to_any().downcast_ref::<OwnedLiteral>(),
|
||||
) {
|
||||
let other_json = other.to_any().downcast_ref::<Self>();
|
||||
let other_literal = other.to_any().downcast_ref::<OwnedLiteral>();
|
||||
match (self, other_json, other_literal) {
|
||||
// If its neither of those types, then it is unimplemented
|
||||
(_, None, None) => panic!("Math operation on unimplemented type"),
|
||||
// Since this is specifically for the math helper, non-primitives are not supported
|
||||
@ -408,45 +408,13 @@ impl CompareContextElement for serde_json::Value {
|
||||
| (_, Some(serde_json::Value::String(_)), _)
|
||||
| (_, _, Some(OwnedLiteral::LString(_))) => None,
|
||||
// Handle other serde_json::Value
|
||||
(
|
||||
serde_json::Value::Number(self_num),
|
||||
Some(serde_json::Value::Number(other_num)),
|
||||
_,
|
||||
) => {
|
||||
match (
|
||||
self_num.as_u64(),
|
||||
other_num.as_u64(),
|
||||
self_num.as_i64(),
|
||||
other_num.as_i64(),
|
||||
self_num.as_f64(),
|
||||
other_num.as_f64(),
|
||||
) {
|
||||
// If both numbers are integers, we can pass them into math_ints
|
||||
(Some(self_num), Some(other_num), _, _, _, _) => {
|
||||
math_ints(self_num, other_num, std::ops::Add::add)
|
||||
.map(IceResult::from_owned)
|
||||
}
|
||||
(_, _, Some(self_num), Some(other_num), _, _) => {
|
||||
math_ints(self_num, other_num, std::ops::Add::add)
|
||||
.map(IceResult::from_owned)
|
||||
}
|
||||
(Some(self_num), _, _, Some(other_num), _, _) => {
|
||||
math_ints(self_num, other_num, std::ops::Add::add)
|
||||
.map(IceResult::from_owned)
|
||||
}
|
||||
(_, Some(other_num), Some(self_num), _, _, _) => {
|
||||
math_ints(self_num, other_num, std::ops::Add::add)
|
||||
.map(IceResult::from_owned)
|
||||
}
|
||||
// Otherwise they'll be floats and we can just do the math directly
|
||||
(_, _, _, _, Some(self_num), Some(other_num)) => Some(IceResult::from_owned(
|
||||
OwnedLiteral::LFloat(self_num + other_num),
|
||||
)),
|
||||
_ => panic!("Unhandled operation, some integer must not have cast to a float."),
|
||||
}
|
||||
}
|
||||
(_, Some(other_json_value), _) => (std::convert::Into::<MathNumber>::into(self)
|
||||
+ std::convert::Into::<MathNumber>::into(other_json_value))
|
||||
.map(IceResult::from_owned),
|
||||
// Handle literals
|
||||
_ => todo!(),
|
||||
(_, _, Some(other_literal)) => (std::convert::Into::<MathNumber>::into(self)
|
||||
+ std::convert::Into::<MathNumber>::into(other_literal))
|
||||
.map(IceResult::from_owned),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -593,6 +561,91 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum MathNumber {
|
||||
Integer(i128),
|
||||
Decimal(f64),
|
||||
Failure,
|
||||
}
|
||||
|
||||
impl From<&serde_json::Value> for MathNumber {
|
||||
fn from(original: &serde_json::Value) -> Self {
|
||||
match original {
|
||||
serde_json::Value::Null => MathNumber::Integer(0),
|
||||
serde_json::Value::Bool(boolean) => {
|
||||
if *boolean {
|
||||
MathNumber::Integer(1)
|
||||
} else {
|
||||
MathNumber::Integer(0)
|
||||
}
|
||||
}
|
||||
serde_json::Value::Number(num) => num.into(),
|
||||
serde_json::Value::String(text) => {
|
||||
panic!("Strings should not be cast to numbers for math")
|
||||
}
|
||||
serde_json::Value::Array(_) => {
|
||||
panic!("Only primitives should be cast to numbers for comparisons")
|
||||
}
|
||||
serde_json::Value::Object(_) => {
|
||||
panic!("Only primitives should be cast to numbers for comparisons")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&serde_json::Number> for MathNumber {
|
||||
fn from(original: &serde_json::Number) -> Self {
|
||||
match original.as_u64() {
|
||||
Some(num) => return MathNumber::Integer(num.try_into().unwrap()),
|
||||
None => (),
|
||||
};
|
||||
match original.as_i64() {
|
||||
Some(num) => return MathNumber::Integer(num.into()),
|
||||
None => (),
|
||||
};
|
||||
match original.as_f64() {
|
||||
Some(num) => return MathNumber::Decimal(num),
|
||||
None => (),
|
||||
};
|
||||
MathNumber::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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
Loading…
Reference in New Issue
Block a user