use crate::types::STEP_LABEL_INLINE;
use std::hash::{Hash, Hasher};
use smallvec::SmallVec;
use smol_str::SmolStr;
use crate::types::{
element::Property,
keys::{EdgeKey, VertexKey},
};
#[derive(Debug, Clone)]
pub enum Primitive {
Null,
Bool(bool),
Int32(i32),
Int64(i64),
UInt16(u16),
Float32(f32),
Float64(f64),
String(SmolStr),
Uuid(u128),
Bytes(Vec<u8>),
}
impl PartialEq for Primitive {
#[inline]
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Null, Self::Null) => true,
(Self::Bool(a), Self::Bool(b)) => a == b,
(Self::Int32(a), Self::Int32(b)) => a == b,
(Self::Int64(a), Self::Int64(b)) => a == b,
(Self::UInt16(a), Self::UInt16(b)) => a == b,
(Self::Float32(a), Self::Float32(b)) => a.to_bits() == b.to_bits(),
(Self::Float64(a), Self::Float64(b)) => a.to_bits() == b.to_bits(),
(Self::String(a), Self::String(b)) => a == b,
(Self::Uuid(a), Self::Uuid(b)) => a == b,
(Self::Bytes(a), Self::Bytes(b)) => a == b,
_ => false,
}
}
}
impl Eq for Primitive {}
impl Primitive {
#[inline]
pub fn is_integer(&self) -> bool {
matches!(self, Self::Int32(_) | Self::Int64(_) | Self::UInt16(_))
}
#[inline]
pub fn is_numeric(&self) -> bool {
matches!(self, Self::Int32(_) | Self::Int64(_) | Self::UInt16(_) | Self::Float32(_) | Self::Float64(_))
}
#[inline]
pub fn to_i64(&self) -> Option<i64> {
match self {
Self::Int32(v) => Some(*v as i64),
Self::Int64(v) => Some(*v),
Self::UInt16(v) => Some(*v as i64),
_ => None,
}
}
#[inline]
pub fn to_f64(&self) -> Option<f64> {
match self {
Self::Int32(v) => Some(*v as f64),
Self::Int64(v) => Some(*v as f64),
Self::UInt16(v) => Some(*v as f64),
Self::Float32(v) => Some(*v as f64),
Self::Float64(v) => Some(*v),
_ => None,
}
}
#[inline]
fn loose_eq(&self, other: &Self) -> bool {
if self.is_integer() && other.is_integer() {
return self.to_i64() == other.to_i64();
}
if self.is_numeric() && other.is_numeric() {
return self.to_f64() == other.to_f64();
}
self == other
}
}
impl PartialOrd for Primitive {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if self.is_integer() && other.is_integer() {
return self.to_i64().unwrap().partial_cmp(&other.to_i64().unwrap());
}
if self.is_numeric() && other.is_numeric() {
return self.to_f64().unwrap().partial_cmp(&other.to_f64().unwrap());
}
match (self, other) {
(Self::Null, Self::Null) => Some(std::cmp::Ordering::Equal),
(Self::Bool(a), Self::Bool(b)) => a.partial_cmp(b),
(Self::String(a), Self::String(b)) => a.partial_cmp(b),
(Self::Uuid(a), Self::Uuid(b)) => a.partial_cmp(b),
(Self::Bytes(a), Self::Bytes(b)) => a.partial_cmp(b),
_ => None,
}
}
}
impl Hash for Primitive {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {
Self::Null => {}
Self::Bool(v) => v.hash(state),
Self::Int32(v) => v.hash(state),
Self::Int64(v) => v.hash(state),
Self::UInt16(v) => v.hash(state),
Self::Float32(v) => v.to_bits().hash(state),
Self::Float64(v) => v.to_bits().hash(state),
Self::String(v) => v.hash(state),
Self::Uuid(v) => v.hash(state),
Self::Bytes(v) => v.hash(state),
}
}
}
impl From<bool> for Primitive {
fn from(v: bool) -> Self {
Self::Bool(v)
}
}
impl From<i32> for Primitive {
fn from(v: i32) -> Self {
Self::Int32(v)
}
}
impl From<i64> for Primitive {
fn from(v: i64) -> Self {
Self::Int64(v)
}
}
impl From<u16> for Primitive {
fn from(v: u16) -> Self {
Self::UInt16(v)
}
}
impl From<f32> for Primitive {
fn from(v: f32) -> Self {
Self::Float32(v)
}
}
impl From<f64> for Primitive {
fn from(v: f64) -> Self {
Self::Float64(v)
}
}
impl From<&str> for Primitive {
fn from(v: &str) -> Self {
Self::String(SmolStr::new(v))
}
}
impl From<String> for Primitive {
fn from(v: String) -> Self {
Self::String(SmolStr::from(v))
}
}
impl From<SmolStr> for Primitive {
fn from(v: SmolStr) -> Self {
Self::String(v)
}
}
#[derive(Debug, Clone)]
pub enum GValue {
Vertex(VertexKey),
Edge(EdgeKey),
Property(Property),
Scalar(Primitive),
List(Vec<GValue>),
#[allow(dead_code)]
Map(Vec<(GValue, GValue)>),
Path(Vec<(GValue, Option<SmallVec<[SmolStr; STEP_LABEL_INLINE]>>)>),
}
impl PartialEq for GValue {
#[inline]
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Vertex(a), Self::Vertex(b)) => a == b,
(Self::Edge(a), Self::Edge(b)) => a == b,
(Self::Property(a), Self::Property(b)) => a == b,
(Self::Scalar(a), Self::Scalar(b)) => a == b,
(Self::List(a), Self::List(b)) => a == b,
(Self::Map(a), Self::Map(b)) => a == b,
(Self::Path(a), Self::Path(b)) => a == b,
_ => false,
}
}
}
impl Eq for GValue {}
impl Hash for GValue {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
std::mem::discriminant(self).hash(state);
match self {
Self::Vertex(key) => key.hash(state),
Self::Edge(key) => key.hash(state),
Self::Property(p) => p.hash(state),
Self::Scalar(p) => p.hash(state),
Self::List(list) => {
list.len().hash(state);
for item in list.iter() {
item.hash(state);
}
}
Self::Map(map) => {
map.len().hash(state);
for (k, v) in map.iter() {
k.hash(state);
v.hash(state);
}
}
Self::Path(path) => {
path.len().hash(state);
for item in path.iter() {
item.hash(state);
}
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PrimitivePredicate {
Eq(Primitive),
Ne(Primitive),
Gt(Primitive),
Gte(Primitive),
Lt(Primitive),
Lte(Primitive),
Between(Primitive, Primitive),
Within(Vec<Primitive>),
Without(Vec<Primitive>),
}
impl PrimitivePredicate {
#[inline]
pub fn evaluate(&self, val: &Primitive) -> bool {
match self {
Self::Eq(p) => val.loose_eq(p),
Self::Ne(p) => !val.loose_eq(p),
Self::Gt(p) => matches!(val.partial_cmp(p), Some(std::cmp::Ordering::Greater)),
Self::Gte(p) => matches!(val.partial_cmp(p), Some(std::cmp::Ordering::Greater | std::cmp::Ordering::Equal)),
Self::Lt(p) => matches!(val.partial_cmp(p), Some(std::cmp::Ordering::Less)),
Self::Lte(p) => matches!(val.partial_cmp(p), Some(std::cmp::Ordering::Less | std::cmp::Ordering::Equal)),
Self::Between(lo, hi) => {
matches!(val.partial_cmp(lo), Some(std::cmp::Ordering::Greater | std::cmp::Ordering::Equal))
&& matches!(val.partial_cmp(hi), Some(std::cmp::Ordering::Less))
}
Self::Within(vs) => vs.iter().any(|v| val.loose_eq(v)),
Self::Without(vs) => !vs.iter().any(|v| val.loose_eq(v)),
}
}
pub fn map(self, f: impl Fn(Primitive) -> Primitive) -> Self {
match self {
Self::Eq(v) => Self::Eq(f(v)),
Self::Ne(v) => Self::Ne(f(v)),
Self::Gt(v) => Self::Gt(f(v)),
Self::Gte(v) => Self::Gte(f(v)),
Self::Lt(v) => Self::Lt(f(v)),
Self::Lte(v) => Self::Lte(f(v)),
Self::Between(lo, hi) => Self::Between(f(lo), f(hi)),
Self::Within(vs) => Self::Within(vs.into_iter().map(f).collect()),
Self::Without(vs) => Self::Without(vs.into_iter().map(f).collect()),
}
}
pub fn values(&self) -> Box<dyn Iterator<Item = &Primitive> + '_> {
match self {
Self::Eq(v) | Self::Ne(v) | Self::Gt(v) | Self::Gte(v) | Self::Lt(v) | Self::Lte(v) => {
Box::new(std::iter::once(v))
}
Self::Between(lo, hi) => Box::new([lo, hi].into_iter()),
Self::Within(vs) | Self::Without(vs) => Box::new(vs.iter()),
}
}
}