use alloc::string::String;
#[cfg(feature = "use_serde")]
use serde;
#[derive(Clone, Debug, PartialOrd)]
#[cfg_attr(feature = "use_serde", derive(serde::Deserialize, serde::Serialize))]
pub enum Value {
Boolean(bool),
Float(f64),
Integer(i128),
String(String),
}
impl core::ops::Not for Value {
type Output = Self;
fn not(self) -> Self::Output {
use Value::*;
match self {
Boolean(x) => Boolean(!x),
Float(x) => Float(-x),
Integer(x) => Integer(-x),
_ => panic!("Type of {:?} cannot be negated", self),
}
}
}
#[allow(clippy::suspicious_arithmetic_impl)]
impl core::ops::Add for Value {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
use Value::*;
match (self, rhs) {
(Boolean(a), Boolean(b)) => Boolean(a || b),
(Float(a), Float(b)) => Float(a + b),
(Float(a), Integer(b)) => Float(a + b as f64),
(Integer(a), Integer(b)) => Integer(a + b),
(Integer(a), Float(b)) => Float(a as f64 + b),
(a, b) => panic!("Types of {:?} and {:?} cannot be added together", a, b),
}
}
}
#[allow(clippy::suspicious_arithmetic_impl)]
impl core::ops::Mul for Value {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
use Value::*;
match (self, rhs) {
(Boolean(a), Boolean(b)) => Boolean(a && b),
(Float(a), Float(b)) => Float(a * b),
(Float(a), Integer(b)) => Float(a * b as f64),
(Integer(a), Integer(b)) => Integer(a * b),
(Integer(a), Float(b)) => Float(a as f64 * b),
(a, b) => panic!("Types of {:?} and {:?} cannot be multiplied together", a, b),
}
}
}
impl core::ops::Sub for Value {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
self + !rhs
}
}
impl core::cmp::PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
use Value::*;
match (self, other) {
(Boolean(a), Boolean(b)) => a == b,
(Float(a), Float(b)) => (a - b) * (a - b) < 0.000_000_000_000_000_000_1,
(Float(a), Integer(b)) => {
(a - *b as f64) * (a - *b as f64) < 0.000_000_000_000_000_000_1
}
(Integer(a), Integer(b)) => a == b,
(Integer(a), Float(b)) => {
(*a as f64 - b) * (*a as f64 - *b) < 0.000_000_000_000_000_000_1
}
(String(a), String(b)) => a == b,
_ => false,
}
}
}
#[cfg(test)]
mod tests {
use crate::core::value::Value::*;
#[test]
fn test_negation() {
assert_eq!(!Boolean(true), Boolean(false));
assert_eq!(!Boolean(false), Boolean(true));
assert_eq!(!Float(0.), Float(0.));
assert_eq!(!Float(1.1), Float(-1.1));
assert_eq!(!Integer(0), Integer(0));
assert_eq!(!Integer(1), Integer(-1));
}
#[test]
fn test_addition() {
assert_eq!(Boolean(false) + Boolean(false), Boolean(false));
assert_eq!(Boolean(false) + Boolean(true), Boolean(true));
assert_eq!(Boolean(true) + Boolean(false), Boolean(true));
assert_eq!(Boolean(true) + Boolean(true), Boolean(true));
assert_eq!(Float(1.1) + Float(2.2), Float(3.3));
assert_eq!(Float(1.1) + Float(-2.2), Float(-1.1));
assert_eq!(Float(1.1) + Integer(2), Float(3.1));
assert_eq!(Float(1.1) + Integer(-2), Float(-0.9));
assert_eq!(Integer(1) + Integer(2), Integer(3));
assert_eq!(Integer(1) + Integer(-2), Integer(-1));
assert_eq!(Integer(1) + Float(2.2), Float(3.2));
assert_eq!(Integer(1) + Float(-2.1), Float(-1.1));
}
#[test]
fn test_subtraction() {
assert_eq!(Boolean(false) - Boolean(false), Boolean(true));
assert_eq!(Boolean(false) - Boolean(true), Boolean(false));
assert_eq!(Boolean(true) - Boolean(false), Boolean(true));
assert_eq!(Boolean(true) - Boolean(true), Boolean(true));
assert_eq!(Float(1.1) - Float(2.2), Float(-1.1));
assert_eq!(Float(1.1) - Float(-2.2), Float(3.3));
assert_eq!(Float(1.1) - Integer(2), Float(-0.9));
assert_eq!(Float(1.1) - Integer(-2), Float(3.1));
assert_eq!(Integer(1) - Integer(2), Integer(-1));
assert_eq!(Integer(1) - Integer(-2), Integer(3));
assert_eq!(Integer(1) - Float(2.2), Float(-1.2));
assert_eq!(Integer(1) - Float(-2.2), Float(3.2));
}
#[test]
fn test_multiplication() {
assert_eq!(Boolean(false) * Boolean(false), Boolean(false));
assert_eq!(Boolean(false) * Boolean(true), Boolean(false));
assert_eq!(Boolean(true) * Boolean(false), Boolean(false));
assert_eq!(Boolean(true) * Boolean(true), Boolean(true));
assert_eq!(Float(1.1) * Float(2.2), Float(2.42));
assert_eq!(Float(1.1) * Float(-2.2), Float(-2.42));
assert_eq!(Float(1.1) * Integer(2), Float(2.2));
assert_eq!(Float(1.1) * Integer(-2), Float(-2.2));
assert_eq!(Integer(1) * Integer(2), Integer(2));
assert_eq!(Integer(1) * Integer(-2), Integer(-2));
assert_eq!(Integer(1) * Float(2.2), Float(2.2));
assert_eq!(Integer(1) * Float(-2.2), Float(-2.2));
}
#[test]
fn test_comparison() {
assert_eq!(Boolean(false) == Boolean(false), true);
assert_eq!(Boolean(false) == Boolean(true), false);
assert_eq!(Boolean(true) == Boolean(false), false);
assert_eq!(Boolean(true) == Boolean(true), true);
assert_eq!(Float(1.1) == Float(1.1), true);
assert_eq!(Float(1.1) == Float(2.2), false);
assert_eq!(Float(-1.1) == Float(-1.1), true);
assert_eq!(Float(-1.1) == Float(-2.2), false);
assert_eq!(Float(1.1) == Float(-1.1), false);
assert_eq!(Float(1.) == Integer(1), true);
assert_eq!(Float(-1.) == Integer(-1), true);
assert_eq!(Integer(1) == Integer(1), true);
assert_eq!(Integer(1) == Integer(2), false);
assert_eq!(Integer(-1) == Integer(-1), true);
assert_eq!(Integer(-1) == Integer(-2), false);
assert_eq!(Integer(1) == Integer(-1), false);
assert_eq!(Integer(1) == Float(1.), true);
assert_eq!(Integer(-1) == Float(-1.), true);
}
}