186 lines
4.9 KiB
Rust
186 lines
4.9 KiB
Rust
use std::{
|
|
fmt::Display,
|
|
ops::{Add, Div, Mul, Sub},
|
|
};
|
|
|
|
#[derive(Debug, Clone, PartialEq, Default)]
|
|
pub enum Value {
|
|
Int(i32),
|
|
Float(f32),
|
|
String(String),
|
|
Bool(bool),
|
|
Char(char),
|
|
#[default]
|
|
Nothing,
|
|
Error,
|
|
}
|
|
|
|
impl Eq for Value {}
|
|
|
|
// impl Value {
|
|
// pub fn as_int(&self) -> Option<i32> {
|
|
// match self {
|
|
// Value::Int(v) => Some(*v),
|
|
// _ => None,
|
|
// }
|
|
// }
|
|
// pub fn as_float(&self) -> Option<f32> {
|
|
// match self {
|
|
// Value::Float(v) => Some(*v),
|
|
// _ => None,
|
|
// }
|
|
// }
|
|
// pub fn as_string(&self) -> Option<String> {
|
|
// match self {
|
|
// Value::String(v) => Some(v.clone()),
|
|
// _ => None,
|
|
// }
|
|
// }
|
|
// pub fn as_bool(&self) -> Option<bool> {
|
|
// match self {
|
|
// Value::Bool(v) => Some(*v),
|
|
// _ => None,
|
|
// }
|
|
// }
|
|
// pub fn as_char(&self) -> Option<char> {
|
|
// match self {
|
|
// Value::Char(v) => Some(*v),
|
|
// _ => None,
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
impl Value {
|
|
pub fn is_truthy(&self) -> bool {
|
|
match self {
|
|
Value::Int(v) => *v != 0,
|
|
Value::Float(v) => *v != 0.0,
|
|
Value::String(v) => !v.is_empty(),
|
|
Value::Bool(v) => *v,
|
|
Value::Char(v) => *v != '\0',
|
|
Value::Nothing => false,
|
|
Value::Error => false,
|
|
}
|
|
}
|
|
|
|
pub fn value_kind(&self) -> &'static str {
|
|
match self {
|
|
Value::Int(_) => "int",
|
|
Value::Float(_) => "float",
|
|
Value::String(_) => "string",
|
|
Value::Bool(_) => "bool",
|
|
Value::Char(_) => "char",
|
|
Value::Nothing => "nothing",
|
|
Value::Error => "error",
|
|
}
|
|
}
|
|
}
|
|
|
|
macro_rules! math_trait {
|
|
($trait_name:ty, $function_name:ident) => {
|
|
impl $trait_name for Value {
|
|
type Output = Value;
|
|
fn $function_name(self, other: Value) -> Self::Output {
|
|
match (self, other) {
|
|
(Value::Int(lhs), Value::Int(rhs)) => Value::Int(lhs.$function_name(rhs)),
|
|
(Value::Float(lhs), Value::Float(rhs)) => Value::Float(lhs.$function_name(rhs)),
|
|
_ => Value::Error,
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
math_trait!(Add, add);
|
|
math_trait!(Sub, sub);
|
|
math_trait!(Mul, mul);
|
|
math_trait!(Div, div);
|
|
|
|
impl Display for Value {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(
|
|
f,
|
|
"{}",
|
|
match self {
|
|
Value::Int(v) => v.to_string(),
|
|
Value::Float(v) => v.to_string(),
|
|
Value::String(v) => v.clone(),
|
|
Value::Bool(v) => v.to_string(),
|
|
Value::Char(v) => v.to_string(),
|
|
Value::Nothing => "()".to_string(),
|
|
Value::Error => "Error".to_string(),
|
|
}
|
|
)
|
|
}
|
|
}
|
|
|
|
impl From<()> for Value {
|
|
fn from(_: ()) -> Self {
|
|
Value::Nothing
|
|
}
|
|
}
|
|
|
|
pub trait FromValue {
|
|
fn from_value(v: &Value) -> Option<&Self>;
|
|
}
|
|
|
|
macro_rules! from_impl {
|
|
($($type:ty => $variant:ident),+) => {
|
|
$(
|
|
impl From<$type> for Value {
|
|
fn from(v: $type) -> Self {
|
|
Value::$variant(v)
|
|
}
|
|
}
|
|
|
|
impl FromValue for $type{
|
|
fn from_value(v: &Value) -> Option<&Self> {
|
|
match v {
|
|
Value::$variant(v) => Some(v),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
)+
|
|
};
|
|
}
|
|
|
|
impl FromValue for Value {
|
|
fn from_value(v: &Value) -> Option<&Self> {
|
|
Some(v)
|
|
}
|
|
}
|
|
|
|
from_impl!(i32 => Int, f32 => Float, String => String, bool => Bool, char => Char);
|
|
|
|
impl From<&'_ str> for Value {
|
|
fn from(v: &str) -> Self {
|
|
Value::String(v.to_string())
|
|
}
|
|
}
|
|
|
|
impl FromValue for str {
|
|
fn from_value(v: &Value) -> Option<&Self> {
|
|
match v {
|
|
Value::String(v) => Some(v.as_str()),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialOrd for Value {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
match (self, other) {
|
|
(Value::Int(lhs), Value::Int(rhs)) => lhs.partial_cmp(rhs),
|
|
(Value::Float(lhs), Value::Float(rhs)) => lhs.partial_cmp(rhs),
|
|
(Value::String(lhs), Value::String(rhs)) => lhs.partial_cmp(rhs),
|
|
(Value::Bool(lhs), Value::Bool(rhs)) => lhs.partial_cmp(rhs),
|
|
(Value::Char(lhs), Value::Char(rhs)) => lhs.partial_cmp(rhs),
|
|
(Value::Nothing, Value::Nothing) => Some(std::cmp::Ordering::Equal),
|
|
(Value::Int(lhs), Value::Float(rhs)) => (*lhs as f32).partial_cmp(rhs),
|
|
(Value::Float(lhs), Value::Int(rhs)) => lhs.partial_cmp(&(*rhs as f32)),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|