use serde::{Deserialize, Serialize};
use std::hash::{Hash, Hasher};
#[derive(
Debug,
Clone,
PartialEq,
PartialOrd,
Eq,
Hash,
Serialize,
Deserialize,
bincode::Encode,
bincode::Decode,
)]
pub enum DataType {
I32,
F64,
Bool,
String,
DateTime,
}
#[derive(Debug, Clone, Serialize, Deserialize, bincode::Encode, bincode::Decode)]
pub enum Value {
Null,
I32(i32),
F64(f64),
Bool(bool),
String(String),
DateTime(i64),
}
impl Value {
pub fn data_type(&self) -> DataType {
match self {
Value::I32(_) => DataType::I32,
Value::F64(_) => DataType::F64,
Value::Bool(_) => DataType::Bool,
Value::String(_) => DataType::String,
Value::DateTime(_) => DataType::DateTime,
Value::Null => panic!("Cannot get data type of a Null value"),
}
}
pub fn as_i32(&self) -> Option<i32> {
match self {
Value::I32(v) => Some(*v),
_ => None,
}
}
pub fn as_f64(&self) -> Option<f64> {
match self {
Value::F64(v) => Some(*v),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(v) => Some(*v),
_ => None,
}
}
pub fn as_string(&self) -> Option<&String> {
match self {
Value::String(v) => Some(v),
_ => None,
}
}
pub fn as_datetime(&self) -> Option<i64> {
match self {
Value::DateTime(v) => Some(*v),
_ => None,
}
}
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::Null, Value::Null) => true,
(Value::I32(l), Value::I32(r)) => l == r,
(Value::F64(l), Value::F64(r)) => l.to_bits() == r.to_bits(), (Value::Bool(l), Value::Bool(r)) => l == r,
(Value::String(l), Value::String(r)) => l == r,
(Value::DateTime(l), Value::DateTime(r)) => l == r,
_ => false,
}
}
}
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Value::Null => write!(f, "null"),
Value::I32(v) => write!(f, "{}", v),
Value::F64(v) => write!(f, "{}", v),
Value::Bool(v) => write!(f, "{}", v),
Value::String(v) => write!(f, "{}", v),
Value::DateTime(v) => write!(f, "{}", v),
}
}
}
impl Eq for Value {}
impl Value {
fn discriminant(&self) -> u8 {
match self {
Value::Null => 0,
Value::I32(_) => 1,
Value::F64(_) => 2,
Value::Bool(_) => 3,
Value::String(_) => 4,
Value::DateTime(_) => 5,
}
}
}
impl Hash for Value {
fn hash<H: Hasher>(&self, state: &mut H) {
match self {
Value::Null => 0.hash(state),
Value::I32(v) => v.hash(state),
Value::F64(v) => v.to_bits().hash(state), Value::Bool(v) => v.hash(state),
Value::String(v) => v.hash(state),
Value::DateTime(v) => v.hash(state),
}
}
}
impl PartialOrd for Value {
#[allow(clippy::non_canonical_partial_ord_impl)]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
use std::cmp::Ordering;
match (self, other) {
(Value::Null, Value::Null) => Some(Ordering::Equal),
(Value::Null, _) => Some(Ordering::Less),
(_, Value::Null) => Some(Ordering::Greater),
(Value::I32(a), Value::I32(b)) => a.partial_cmp(b),
(Value::F64(a), Value::F64(b)) => a.partial_cmp(b),
(Value::Bool(a), Value::Bool(b)) => a.partial_cmp(b),
(Value::String(a), Value::String(b)) => a.partial_cmp(b),
(Value::DateTime(a), Value::DateTime(b)) => a.partial_cmp(b),
(Value::I32(a), Value::F64(b)) => (*a as f64).partial_cmp(b),
(Value::F64(a), Value::I32(b)) => a.partial_cmp(&(*b as f64)),
_ => None,
}
}
}
impl Ord for Value {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
if let Some(ord) = self.partial_cmp(other) {
ord
} else {
self.discriminant().cmp(&other.discriminant())
}
}
}
#[derive(
Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, bincode::Encode, bincode::Decode,
)]
pub enum FlatValue {
Null,
I32(i32),
F64(u64), Bool(bool),
String(Vec<u8>), DateTime(i64),
}
impl From<Value> for FlatValue {
fn from(value: Value) -> Self {
match value {
Value::Null => FlatValue::Null,
Value::I32(v) => FlatValue::I32(v),
Value::F64(v) => FlatValue::F64(v.to_bits()),
Value::Bool(v) => FlatValue::Bool(v),
Value::String(v) => FlatValue::String(v.into_bytes()),
Value::DateTime(v) => FlatValue::DateTime(v),
}
}
}
impl From<FlatValue> for Value {
fn from(flat_value: FlatValue) -> Self {
match flat_value {
FlatValue::Null => Value::Null,
FlatValue::I32(v) => Value::I32(v),
FlatValue::F64(v) => Value::F64(f64::from_bits(v)),
FlatValue::Bool(v) => Value::Bool(v),
FlatValue::String(v) => Value::String(String::from_utf8(v).unwrap_or_default()), FlatValue::DateTime(v) => Value::DateTime(v),
}
}
}