411 lines
13 KiB
Rust
411 lines
13 KiB
Rust
use anyhow::anyhow;
|
|
use chrono::{DateTime, Utc};
|
|
use std::cmp::Ordering;
|
|
use std::collections::HashMap;
|
|
use std::fmt::{Display, Formatter};
|
|
use std::hash::{Hash, Hasher};
|
|
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct StructDefinition {
|
|
fields: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct StructValue {
|
|
definition: StructDefinition,
|
|
fields: Vec<Value>,
|
|
}
|
|
|
|
impl StructValue {
|
|
pub fn new(definition: StructDefinition) -> Self {
|
|
Self {
|
|
definition,
|
|
fields: Vec::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Display for StructValue {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
for (i, field) in self.definition.fields.iter().enumerate() {
|
|
write!(f, "{}: {}", field, self.fields[i])?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum Value {
|
|
U32(u32),
|
|
I32(i32),
|
|
U64(u64),
|
|
I64(i64),
|
|
F32(f32),
|
|
F64(f64),
|
|
String(String),
|
|
Char(char),
|
|
Bool(bool),
|
|
Date(DateTime<Utc>),
|
|
Enum,
|
|
List(Vec<Value>),
|
|
Map(HashMap<Value, Value>),
|
|
Struct(StructValue),
|
|
Error(String),
|
|
Void,
|
|
}
|
|
|
|
impl Into<Value> for i32 {
|
|
fn into(self) -> Value {
|
|
Value::I32(self)
|
|
}
|
|
}
|
|
|
|
impl Into<Value> for i64 {
|
|
fn into(self) -> Value {
|
|
Value::I64(self)
|
|
}
|
|
}
|
|
|
|
impl Into<Value> for u32 {
|
|
fn into(self) -> Value {
|
|
Value::U32(self)
|
|
}
|
|
}
|
|
|
|
impl Into<Value> for u64 {
|
|
fn into(self) -> Value {
|
|
Value::U64(self)
|
|
}
|
|
}
|
|
|
|
impl Into<Value> for f32 {
|
|
fn into(self) -> Value {
|
|
Value::F32(self)
|
|
}
|
|
}
|
|
|
|
impl Into<Value> for f64 {
|
|
fn into(self) -> Value {
|
|
Value::F64(self)
|
|
}
|
|
}
|
|
|
|
impl Into<Value> for &str {
|
|
fn into(self) -> Value {
|
|
Value::String(self.to_string())
|
|
}
|
|
}
|
|
|
|
impl From<String> for Value {
|
|
fn from(s: String) -> Self {
|
|
Value::String(s.clone())
|
|
}
|
|
}
|
|
|
|
impl From<&String> for Value {
|
|
fn from(s: &String) -> Self {
|
|
Value::String(s.clone())
|
|
}
|
|
}
|
|
|
|
impl Into<Value> for char {
|
|
fn into(self) -> Value {
|
|
Value::Char(self)
|
|
}
|
|
}
|
|
|
|
impl Into<Value> for bool {
|
|
fn into(self) -> Value {
|
|
Value::Bool(self)
|
|
}
|
|
}
|
|
|
|
impl Into<Value> for DateTime<Utc> {
|
|
fn into(self) -> Value {
|
|
Value::Date(self)
|
|
}
|
|
}
|
|
|
|
impl Display for Value {
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
match &self {
|
|
&Value::U32(v) => write!(f, "{}", v),
|
|
&Value::U64(v) => write!(f, "{}", v),
|
|
&Value::String(v) => write!(f, "{}", v),
|
|
&Value::Bool(v) => write!(f, "{}", v),
|
|
&Value::I32(v) => write!(f, "{}", v),
|
|
&Value::I64(v) => write!(f, "{}", v),
|
|
&Value::F32(v) => write!(f, "{}", v),
|
|
&Value::F64(v) => write!(f, "{}", v),
|
|
&Value::Char(v) => write!(f, "{}", v),
|
|
&Value::Date(v) => write!(f, "{}", v),
|
|
&Value::Enum => write!(f, "enum"),
|
|
&Value::Struct(v) => write!(f, "{}", v),
|
|
&Value::List(v) => write!(f, "{:?}", v),
|
|
&Value::Map(v) => write!(f, "map"),
|
|
&Value::Error(v) => write!(f, "{}", v),
|
|
&Value::Void => write!(f, "()"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Neg for &Value {
|
|
type Output = anyhow::Result<Value>;
|
|
|
|
fn neg(self) -> Self::Output {
|
|
match self {
|
|
Value::I32(i) => Ok(Value::I32(-i)),
|
|
Value::I64(i) => Ok(Value::I64(-i)),
|
|
Value::F32(i) => Ok(Value::F32(-i)),
|
|
Value::F64(i) => Ok(Value::F64(-i)),
|
|
_ => Err(anyhow!("Cannot negate")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Add<&Value> for &Value {
|
|
type Output = anyhow::Result<Value>;
|
|
|
|
fn add(self, rhs: &Value) -> Self::Output {
|
|
if let Value::List(s) = self {
|
|
let mut copy = s.clone();
|
|
copy.push(rhs.clone());
|
|
Ok(Value::List(copy))
|
|
} else if let Value::List(rhs) = rhs {
|
|
let mut copy = rhs.clone();
|
|
copy.push(self.clone());
|
|
Ok(Value::List(copy))
|
|
} else {
|
|
match (self, rhs) {
|
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a + b)),
|
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a + b)),
|
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a + b)),
|
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a + b)),
|
|
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a + b)),
|
|
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a + b)),
|
|
(Value::String(s), Value::I32(i)) => Ok(format!("{}{}", s, i).into()),
|
|
(Value::String(s), Value::I64(i)) => Ok(format!("{}{}", s, i).into()),
|
|
(Value::String(s), Value::U32(u)) => Ok(Value::String(format!("{}{}", s, u))),
|
|
(Value::String(s), Value::U64(u)) => Ok(Value::String(format!("{}{}", s, u))),
|
|
(Value::String(s), Value::F32(f)) => Ok(Value::String(format!("{}{}", s, f))),
|
|
(Value::String(s), Value::F64(f)) => Ok(Value::String(format!("{}{}", s, f))),
|
|
(Value::String(s), Value::Bool(b)) => Ok(Value::String(format!("{}{}", s, b))),
|
|
(Value::String(s), Value::Char(c)) => Ok(Value::String(format!("{}{}", s, c))),
|
|
(Value::String(s1), Value::String(s2)) => {
|
|
Ok(Value::String(format!("{}{}", s1, s2)))
|
|
}
|
|
(Value::String(s1), Value::Map(m)) => Ok(Value::String(format!("{}{:?}", s1, m))),
|
|
//enum?
|
|
_ => Err(anyhow!("Cannot add")),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Sub<&Value> for &Value {
|
|
type Output = anyhow::Result<Value>;
|
|
|
|
fn sub(self, rhs: &Value) -> Self::Output {
|
|
match (self, rhs) {
|
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a - b)),
|
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a - b)),
|
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a - b)),
|
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a - b)),
|
|
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a - b)),
|
|
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a - b)),
|
|
//enum?
|
|
_ => Err(anyhow!("Cannot subtract")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Mul<&Value> for &Value {
|
|
type Output = anyhow::Result<Value>;
|
|
|
|
fn mul(self, rhs: &Value) -> Self::Output {
|
|
match (self, rhs) {
|
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a * b)),
|
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a * b)),
|
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a * b)),
|
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a * b)),
|
|
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a * b)),
|
|
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a * b)),
|
|
_ => Err(anyhow!("Cannot multiply")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Div<&Value> for &Value {
|
|
type Output = anyhow::Result<Value>;
|
|
|
|
fn div(self, rhs: &Value) -> Self::Output {
|
|
match (self, rhs) {
|
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a / b)),
|
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a / b)),
|
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a / b)),
|
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a / b)),
|
|
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a / b)),
|
|
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a / b)),
|
|
_ => Err(anyhow!("Cannot divide")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BitAnd<&Value> for &Value {
|
|
type Output = anyhow::Result<Value>;
|
|
fn bitand(self, rhs: &Value) -> Self::Output {
|
|
match (self, rhs) {
|
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a & b)),
|
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a & b)),
|
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a & b)),
|
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a & b)),
|
|
_ => Err(anyhow!("Cannot do bitwise-and on")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BitOr<&Value> for &Value {
|
|
type Output = anyhow::Result<Value>;
|
|
fn bitor(self, rhs: &Value) -> Self::Output {
|
|
match (self, rhs) {
|
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a | b)),
|
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a | b)),
|
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a | b)),
|
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a | b)),
|
|
_ => Err(anyhow!("Cannot do bitwise-or on")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BitXor<&Value> for &Value {
|
|
type Output = anyhow::Result<Value>;
|
|
fn bitxor(self, rhs: &Value) -> Self::Output {
|
|
match (self, rhs) {
|
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a ^ b)),
|
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a ^ b)),
|
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a ^ b)),
|
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a ^ b)),
|
|
_ => Err(anyhow!("Cannot do bitwise-xor on")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Not for &Value {
|
|
type Output = anyhow::Result<Value>;
|
|
|
|
fn not(self) -> Self::Output {
|
|
match (self) {
|
|
Value::Bool(b) => Ok(Value::Bool(!b)),
|
|
Value::I32(i32) => Ok(Value::I32(!i32)),
|
|
Value::I64(i64) => Ok(Value::I64(!i64)),
|
|
Value::U32(u32) => Ok(Value::U32(!u32)),
|
|
Value::U64(u64) => Ok(Value::U64(!u64)),
|
|
_ => Err(anyhow!("Cannot calculate not")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Shl<&Value> for &Value {
|
|
type Output = anyhow::Result<Value>;
|
|
fn shl(self, rhs: &Value) -> Self::Output {
|
|
match (self, rhs) {
|
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a << b)),
|
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a << b)),
|
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a << b)),
|
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a << b)),
|
|
_ => Err(anyhow!("Cannot shift left on")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Shr<&Value> for &Value {
|
|
type Output = anyhow::Result<Value>;
|
|
fn shr(self, rhs: &Value) -> Self::Output {
|
|
match (self, rhs) {
|
|
(Value::I32(a), Value::I32(b)) => Ok(Value::I32(a >> b)),
|
|
(Value::I64(a), Value::I64(b)) => Ok(Value::I64(a >> b)),
|
|
(Value::U32(a), Value::U32(b)) => Ok(Value::U32(a >> b)),
|
|
(Value::U64(a), Value::U64(b)) => Ok(Value::U64(a >> b)),
|
|
_ => Err(anyhow!("Cannot shift right on")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq for Value {
|
|
fn eq(&self, rhs: &Self) -> bool {
|
|
match (self, rhs) {
|
|
(Value::I32(a), Value::I32(b)) => a == b,
|
|
(Value::I64(a), Value::I64(b)) => a == b,
|
|
(Value::U32(a), Value::U32(b)) => a == b,
|
|
(Value::U64(a), Value::U64(b)) => a == b,
|
|
(Value::F32(a), Value::F32(b)) => a == b,
|
|
(Value::F64(a), Value::F64(b)) => a == b,
|
|
(Value::Bool(a), Value::Bool(b)) => a == b,
|
|
(Value::String(a), Value::String(b)) => a == b,
|
|
(Value::Char(a), Value::Char(b)) => a == b,
|
|
(Value::Date(a), Value::Date(b)) => a == b,
|
|
// (Value::List(a), Value::List(b)) => a == b,
|
|
// (Value::Map(a), Value::Map(b)) => {
|
|
// let mut equal = true;
|
|
// for (k, v) in a.iter() {
|
|
// if !b.contains_key(k) || b.get(k).unwrap() != v {
|
|
// //safe unwrap
|
|
// equal = false;
|
|
// break;
|
|
// }
|
|
// }
|
|
// equal
|
|
// }
|
|
// struct?
|
|
_ => false, //?
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Eq for Value {}
|
|
|
|
impl PartialOrd for Value {
|
|
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
|
match (self, rhs) {
|
|
(Value::I32(a), Value::I32(b)) => Some(a.partial_cmp(b)?),
|
|
(Value::I64(a), Value::I64(b)) => Some(a.partial_cmp(b)?),
|
|
(Value::U32(a), Value::U32(b)) => Some(a.partial_cmp(b)?),
|
|
(Value::U64(a), Value::U64(b)) => Some(a.partial_cmp(b)?),
|
|
(Value::F32(a), Value::F32(b)) => Some(a.partial_cmp(b)?),
|
|
(Value::F64(a), Value::F64(b)) => Some(a.partial_cmp(b)?),
|
|
(Value::String(a), Value::String(b)) => Some(a.partial_cmp(b)?),
|
|
(Value::Char(a), Value::Char(b)) => Some(a.partial_cmp(b)?),
|
|
(Value::Date(a), Value::Date(b)) => Some(a.partial_cmp(b)?),
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Hash for Value {
|
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
std::mem::discriminant(self).hash(state);
|
|
|
|
// Then hash the fields
|
|
match self {
|
|
Value::I32(i32) => i32.hash(state),
|
|
Value::I64(i64) => i64.hash(state),
|
|
Value::U32(u32) => u32.hash(state),
|
|
Value::U64(u64) => u64.hash(state),
|
|
Value::F32(f32) => f32.to_bits().hash(state),
|
|
Value::F64(f64) => f64.to_bits().hash(state),
|
|
Value::String(s) => s.hash(state),
|
|
Value::Char(c) => c.hash(state),
|
|
Value::Bool(b) => b.hash(state),
|
|
Value::Date(d) => d.hash(state),
|
|
Value::List(l) => l.hash(state),
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
// impl Ord for Value {
|
|
// fn cmp(&self, rhs: &Self) -> Ordering {
|
|
// self.partial_cmp(rhs).unwrap()
|
|
// }
|
|
// }
|