use serde_json::Value;
use crate::to_value;
use crate::error::Error;
pub trait Math {
fn add(&self, value: &Value) -> Result<Value, Error>;
fn mul(&self, value: &Value) -> Result<Value, Error>;
fn sub(&self, value: &Value) -> Result<Value, Error>;
fn div(&self, value: &Value) -> Result<Value, Error>;
fn rem(&self, value: &Value) -> Result<Value, Error>;
fn eq(&self, value: &Value) -> Result<Value, Error>;
fn ne(&self, value: &Value) -> Result<Value, Error>;
fn gt(&self, value: &Value) -> Result<Value, Error>;
fn lt(&self, value: &Value) -> Result<Value, Error>;
fn ge(&self, value: &Value) -> Result<Value, Error>;
fn le(&self, value: &Value) -> Result<Value, Error>;
}
impl Math for Value {
fn add(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
if self.is_f64() || value.is_f64() {
Ok(to_value(self.get_f64() + value.get_f64()))
} else if self.is_i64() || value.is_i64() {
Ok(to_value(self.get_i64() + value.get_i64()))
} else {
Ok(to_value(self.get_u64() + value.get_u64()))
}
} else if self.is_string() && value.is_string() {
Ok(to_value(self.get_string() + value.get_str()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn mul(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
if self.is_f64() || value.is_f64() {
Ok(to_value(self.get_f64() * value.get_f64()))
} else if self.is_i64() || value.is_i64() {
Ok(to_value(self.get_i64() * value.get_i64()))
} else {
Ok(to_value(self.get_u64() * value.get_u64()))
}
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn sub(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
if self.is_f64() || value.is_f64() {
Ok(to_value(self.get_f64() - value.get_f64()))
} else {
Ok(to_value(self.get_i64() - value.get_i64()))
}
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn div(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
if value.get_f64() == 0.0 {
return Err(Error::DivisionByZero);
}
Ok(to_value(self.get_f64() / value.get_f64()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn rem(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
if self.is_f64() || value.is_f64() {
if value.get_f64() == 0.0 {
return Err(Error::ModuloByZero);
}
Ok(to_value(self.get_f64() % value.get_f64()))
} else if self.is_i64() || value.is_i64() {
if value.get_i64() == 0 {
return Err(Error::ModuloByZero);
}
Ok(to_value(self.get_i64() % value.get_i64()))
} else {
if value.get_u64() == 0 {
return Err(Error::ModuloByZero);
}
Ok(to_value(self.get_u64() % value.get_u64()))
}
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn eq(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() == value.get_f64()))
} else {
Ok(to_value(self == value))
}
}
fn ne(&self, value: &Value) -> Result<Value, Error> {
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() != value.get_f64()))
} else {
Ok(to_value(self != value))
}
}
fn gt(&self, value: &Value) -> Result<Value, Error> {
if self.is_null() || value.is_null() {
return Ok(to_value(false));
}
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() > value.get_f64()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn lt(&self, value: &Value) -> Result<Value, Error> {
if self.is_null() || value.is_null() {
return Ok(to_value(false));
}
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() < value.get_f64()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn ge(&self, value: &Value) -> Result<Value, Error> {
if self.is_null() || value.is_null() {
return Ok(to_value(false));
}
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() >= value.get_f64()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
fn le(&self, value: &Value) -> Result<Value, Error> {
if self.is_null() || value.is_null() {
return Ok(to_value(false));
}
if self.is_number() && value.is_number() {
Ok(to_value(self.get_f64() <= value.get_f64()))
} else {
Err(Error::UnsupportedTypes(self.format(), value.format()))
}
}
}
trait Type {
fn get_f64(&self) -> f64;
fn get_string(&self) -> String;
fn get_str(&self) -> &str;
fn get_u64(&self) -> u64;
fn get_i64(&self) -> i64;
fn format(&self) -> String;
}
impl Type for Value {
fn get_f64(&self) -> f64 {
match *self {
Value::Number(ref n) => n.as_f64().unwrap(),
_ => panic!("not a number"),
}
}
fn get_string(&self) -> String {
self.as_str().unwrap().to_owned()
}
fn get_str(&self) -> &str {
self.as_str().unwrap()
}
fn get_u64(&self) -> u64 {
self.as_u64().unwrap()
}
fn get_i64(&self) -> i64 {
self.as_i64().unwrap()
}
fn format(&self) -> String {
format!("{:?}", self)
}
}