use crate::Error;
use std::collections::BTreeMap;
#[derive(Clone, Debug)]
pub enum Value {
Null,
Bool(bool),
Int(i64),
Float(f64),
String(String),
Bytes(Vec<u8>),
Timestamp(i64),
Duration(i64),
Uuid(uuid::Uuid),
List(Vec<Value>),
Map(BTreeMap<String, Value>),
Tuple(Vec<Value>),
Enum { ty: String, variant: String },
}
impl Value {
pub fn as_int(&self) -> Result<i64, Error> {
match self {
Value::Int(n) => Ok(*n),
other => Err(Error::TypeMismatch {
expected: "Int".into(),
got: other.type_name().into(),
}),
}
}
pub fn as_duration_ms(&self) -> Result<i64, Error> {
match self {
Value::Duration(ms) => Ok(*ms),
other => Err(Error::TypeMismatch {
expected: "Duration".into(),
got: other.type_name().into(),
}),
}
}
pub fn as_string(&self) -> Result<&str, Error> {
match self {
Value::String(s) => Ok(s.as_str()),
other => Err(Error::TypeMismatch {
expected: "String".into(),
got: other.type_name().into(),
}),
}
}
pub fn as_bool(&self) -> Result<bool, Error> {
match self {
Value::Bool(b) => Ok(*b),
other => Err(Error::TypeMismatch {
expected: "Bool".into(),
got: other.type_name().into(),
}),
}
}
pub fn as_float(&self) -> Result<f64, Error> {
match self {
Value::Float(f) => Ok(*f),
Value::Int(n) => Ok(*n as f64),
other => Err(Error::TypeMismatch {
expected: "Float".into(),
got: other.type_name().into(),
}),
}
}
pub fn type_name(&self) -> &'static str {
match self {
Value::Null => "Null",
Value::Bool(_) => "Bool",
Value::Int(_) => "Int",
Value::Float(_) => "Float",
Value::String(_) => "String",
Value::Bytes(_) => "Bytes",
Value::Timestamp(_) => "Timestamp",
Value::Duration(_) => "Duration",
Value::Uuid(_) => "Uuid",
Value::List(_) => "List",
Value::Map(_) => "Map",
Value::Tuple(_) => "Tuple",
Value::Enum { .. } => "Enum",
}
}
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Value::Null, Value::Null) => true,
(Value::Bool(a), Value::Bool(b)) => a == b,
(Value::Int(a), Value::Int(b)) => a == b,
(Value::Float(a), Value::Float(b)) => a.to_bits() == b.to_bits(),
(Value::String(a), Value::String(b)) => a == b,
(Value::Bytes(a), Value::Bytes(b)) => a == b,
(Value::Timestamp(a), Value::Timestamp(b)) => a == b,
(Value::Duration(a), Value::Duration(b)) => a == b,
(Value::Uuid(a), Value::Uuid(b)) => a == b,
(Value::List(a), Value::List(b)) => a == b,
(Value::Map(a), Value::Map(b)) => a == b,
(Value::Tuple(a), Value::Tuple(b)) => a == b,
(Value::Enum { ty: t1, variant: v1 }, Value::Enum { ty: t2, variant: v2 }) => {
t1 == t2 && v1 == v2
}
_ => false,
}
}
}
impl Eq for Value {}
impl PartialOrd for Value {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Value {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
use std::cmp::Ordering;
if std::mem::discriminant(self) != std::mem::discriminant(other) {
return self.type_name().cmp(other.type_name());
}
match (self, other) {
(Value::Null, Value::Null) => Ordering::Equal,
(Value::Bool(a), Value::Bool(b)) => a.cmp(b),
(Value::Int(a), Value::Int(b)) => a.cmp(b),
(Value::Float(a), Value::Float(b)) => a.to_bits().cmp(&b.to_bits()),
(Value::String(a), Value::String(b)) => a.cmp(b),
(Value::Bytes(a), Value::Bytes(b)) => a.cmp(b),
(Value::Timestamp(a), Value::Timestamp(b)) => a.cmp(b),
(Value::Duration(a), Value::Duration(b)) => a.cmp(b),
(Value::Uuid(a), Value::Uuid(b)) => a.cmp(b),
(Value::List(a), Value::List(b)) => a.cmp(b),
(Value::Map(a), Value::Map(b)) => a.cmp(b),
(Value::Tuple(a), Value::Tuple(b)) => a.cmp(b),
(Value::Enum { ty: t1, variant: v1 }, Value::Enum { ty: t2, variant: v2 }) => {
t1.cmp(t2).then_with(|| v1.cmp(v2))
}
_ => Ordering::Equal,
}
}
}
impl std::hash::Hash for Value {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {
Value::Null => {}
Value::Bool(b) => b.hash(state),
Value::Int(n) => n.hash(state),
Value::Float(f) => f.to_bits().hash(state),
Value::String(s) => s.hash(state),
Value::Bytes(b) => b.hash(state),
Value::Timestamp(t) => t.hash(state),
Value::Duration(d) => d.hash(state),
Value::Uuid(u) => u.hash(state),
Value::List(l) => l.hash(state),
Value::Map(m) => m.hash(state),
Value::Tuple(t) => t.hash(state),
Value::Enum { ty, variant } => {
ty.hash(state);
variant.hash(state);
}
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Type {
Primitive(PrimitiveType),
List(Box<Type>),
Optional(Box<Type>),
Map(Box<Type>, Box<Type>),
Tuple(Vec<Type>),
Enum(String),
Molecule(MoleculeKindId),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum PrimitiveType {
Bool,
Int,
Float,
String,
Bytes,
Timestamp,
Duration,
Uuid,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct MoleculeKindId(pub u32);