change number representation

main
Ziyang Hu 2 years ago
parent 8150e3573e
commit ee5d60817c

@ -26,7 +26,7 @@ rmp-serde = "1.1.0"
rmpv = "1.0.0" rmpv = "1.0.0"
base64 = "0.13.0" base64 = "0.13.0"
chrono = "0.4.19" chrono = "0.4.19"
ordered-float = { version = "3.0", features = ["serde"] } num-traits = "0.2.15"
itertools = "0.10.3" itertools = "0.10.3"
pest = "2.2.1" pest = "2.2.1"
pest_derive = "2.2.1" pest_derive = "2.2.1"

@ -12,5 +12,3 @@
* [x] public API * [x] public API
* [x] sorting * [x] sorting
* [ ] range scan * [ ] range scan
comparators can have problems when sorting mixed integers and floats

@ -1,9 +1,9 @@
use std::cmp::{max, min}; use std::cmp::{max, min, Ordering};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use crate::data::value::DataValue; use crate::data::value::{DataValue, Number};
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct Aggregation { pub(crate) struct Aggregation {
@ -37,10 +37,12 @@ macro_rules! define_aggr {
define_aggr!(AGGR_COUNT, false); define_aggr!(AGGR_COUNT, false);
fn aggr_count(accum: &DataValue, current: &DataValue) -> Result<DataValue> { fn aggr_count(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
match (accum, current) { match (accum, current) {
(DataValue::Guard, DataValue::Guard) => Ok(DataValue::Int(0)), (DataValue::Guard, DataValue::Guard) => Ok(DataValue::Number(Number::Int(0))),
(DataValue::Guard, _) => Ok(DataValue::Int(1)), (DataValue::Guard, _) => Ok(DataValue::Number(Number::Int(1))),
(DataValue::Int(i), DataValue::Guard) => Ok(DataValue::Int(*i)), (DataValue::Number(Number::Int(i)), DataValue::Guard) => {
(DataValue::Int(i), _) => Ok(DataValue::Int(*i + 1)), Ok(DataValue::Number(Number::Int(*i)))
}
(DataValue::Number(Number::Int(i)), _) => Ok(DataValue::Number(Number::Int(*i + 1))),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -48,16 +50,29 @@ fn aggr_count(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
define_aggr!(AGGR_SUM, false); define_aggr!(AGGR_SUM, false);
fn aggr_sum(accum: &DataValue, current: &DataValue) -> Result<DataValue> { fn aggr_sum(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
match (accum, current) { match (accum, current) {
(DataValue::Guard, DataValue::Guard) => Ok(DataValue::Int(0)), (DataValue::Guard, DataValue::Guard) => Ok(DataValue::Number(Number::Int(0))),
(DataValue::Guard, DataValue::Int(i)) => Ok(DataValue::Int(*i)), (DataValue::Guard, DataValue::Number(Number::Int(i))) => {
(DataValue::Guard, DataValue::Float(f)) => Ok(DataValue::Float(f.0.into())), Ok(DataValue::Number(Number::Int(*i)))
(DataValue::Int(i), DataValue::Guard) => Ok(DataValue::Int(*i)), }
(DataValue::Float(f), DataValue::Guard) => Ok(DataValue::Float(f.0.into())), (DataValue::Guard, DataValue::Number(Number::Float(f))) => {
(DataValue::Int(i), DataValue::Int(j)) => Ok(DataValue::Int(*i + *j)), Ok(DataValue::Number(Number::Float(*f)))
(DataValue::Int(j), DataValue::Float(i)) | (DataValue::Float(i), DataValue::Int(j)) => { }
Ok(DataValue::Float((i.0 + (*j as f64)).into())) (DataValue::Number(Number::Int(i)), DataValue::Guard) => {
} Ok(DataValue::Number(Number::Int(*i)))
(DataValue::Float(i), DataValue::Float(j)) => Ok(DataValue::Float((i.0 + j.0).into())), }
(DataValue::Number(Number::Float(f)), DataValue::Guard) => {
Ok(DataValue::Number(Number::Float(*f)))
}
(DataValue::Number(Number::Int(i)), DataValue::Number(Number::Int(j))) => {
Ok(DataValue::Number(Number::Int(*i + *j)))
}
(DataValue::Number(Number::Int(j)), DataValue::Number(Number::Float(i)))
| (DataValue::Number(Number::Float(i)), DataValue::Number(Number::Int(j))) => {
Ok(DataValue::Number(Number::Float(*i + (*j as f64))))
}
(DataValue::Number(Number::Float(i)), DataValue::Number(Number::Float(j))) => {
Ok(DataValue::Number(Number::Float(*i + *j)))
}
(i, j) => bail!( (i, j) => bail!(
"cannot compute min: encountered value {:?} for aggregate {:?}", "cannot compute min: encountered value {:?} for aggregate {:?}",
j, j,
@ -69,14 +84,31 @@ fn aggr_sum(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
define_aggr!(AGGR_MIN, true); define_aggr!(AGGR_MIN, true);
fn aggr_min(accum: &DataValue, current: &DataValue) -> Result<DataValue> { fn aggr_min(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
match (accum, current) { match (accum, current) {
(DataValue::Guard, DataValue::Int(i)) => Ok(DataValue::Int(*i)), (DataValue::Guard, DataValue::Number(Number::Int(i))) => {
(DataValue::Guard, DataValue::Float(f)) => Ok(DataValue::Float(f.0.into())), Ok(DataValue::Number(Number::Int(*i)))
(DataValue::Int(i), DataValue::Int(j)) => Ok(DataValue::Int(min(*i, *j))),
(DataValue::Int(j), DataValue::Float(i)) | (DataValue::Float(i), DataValue::Int(j)) => {
Ok(DataValue::Float(min(i.clone(), (*j as f64).into())))
} }
(DataValue::Float(i), DataValue::Float(j)) => { (DataValue::Guard, DataValue::Number(Number::Float(f))) => {
Ok(DataValue::Float(min(i.clone(), j.clone()))) Ok(DataValue::Number(Number::Float(*f)))
}
(DataValue::Number(Number::Int(i)), DataValue::Number(Number::Int(j))) => {
Ok(DataValue::Number(Number::Int(min(*i, *j))))
}
(DataValue::Number(Number::Int(j)), DataValue::Number(Number::Float(i)))
| (DataValue::Number(Number::Float(i)), DataValue::Number(Number::Int(j))) => {
let m = match i.total_cmp(&(*j as f64)) {
Ordering::Less => *i,
Ordering::Equal => *i,
Ordering::Greater => *j as f64,
};
Ok(DataValue::Number(Number::Float(m)))
}
(DataValue::Number(Number::Float(i)), DataValue::Number(Number::Float(j))) => {
let m = match i.total_cmp(j) {
Ordering::Less => *i,
Ordering::Equal => *i,
Ordering::Greater => *j,
};
Ok(DataValue::Number(Number::Float(m)))
} }
(i, j) => bail!( (i, j) => bail!(
"cannot compute min: encountered value {:?} for aggregate {:?}", "cannot compute min: encountered value {:?} for aggregate {:?}",
@ -89,15 +121,34 @@ fn aggr_min(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
define_aggr!(AGGR_MAX, true); define_aggr!(AGGR_MAX, true);
fn aggr_max(accum: &DataValue, current: &DataValue) -> Result<DataValue> { fn aggr_max(accum: &DataValue, current: &DataValue) -> Result<DataValue> {
match (accum, current) { match (accum, current) {
(DataValue::Guard, DataValue::Int(i)) => Ok(DataValue::Int(*i)), (DataValue::Guard, DataValue::Number(Number::Int(i))) => {
(DataValue::Guard, DataValue::Float(f)) => Ok(DataValue::Float(f.0.into())), Ok(DataValue::Number(Number::Int(*i)))
(DataValue::Float(f), DataValue::Guard) => Ok(DataValue::Float(f.0.into())), }
(DataValue::Int(i), DataValue::Int(j)) => Ok(DataValue::Int(max(*i, *j))), (DataValue::Guard, DataValue::Number(Number::Float(f))) => {
(DataValue::Int(j), DataValue::Float(i)) | (DataValue::Float(i), DataValue::Int(j)) => { Ok(DataValue::Number(Number::Float(*f)))
Ok(DataValue::Float(max(i.clone(), (*j as f64).into()))) }
} (DataValue::Number(Number::Float(f)), DataValue::Guard) => {
(DataValue::Float(i), DataValue::Float(j)) => { Ok(DataValue::Number(Number::Float(*f)))
Ok(DataValue::Float(max(i.clone(), j.clone()))) }
(DataValue::Number(Number::Int(i)), DataValue::Number(Number::Int(j))) => {
Ok(DataValue::Number(Number::Int(max(*i, *j))))
}
(DataValue::Number(Number::Int(j)), DataValue::Number(Number::Float(i)))
| (DataValue::Number(Number::Float(i)), DataValue::Number(Number::Int(j))) => {
let m = match i.total_cmp(&(*j as f64)) {
Ordering::Less => *j as f64,
Ordering::Equal => *i,
Ordering::Greater => *i,
};
Ok(DataValue::Number(Number::Float(m)))
}
(DataValue::Number(Number::Float(i)), DataValue::Number(Number::Float(j))) => {
let m = match i.total_cmp(j) {
Ordering::Less => *j,
Ordering::Equal => *i,
Ordering::Greater => *i,
};
Ok(DataValue::Number(Number::Float(m)))
} }
(i, j) => bail!( (i, j) => bail!(
"cannot compute min: encountered value {:?} for aggregate {:?}", "cannot compute min: encountered value {:?} for aggregate {:?}",

@ -12,7 +12,7 @@ use crate::data::id::{AttrId, TxId};
use crate::data::json::JsonValue; use crate::data::json::JsonValue;
use crate::data::symb::Symbol; use crate::data::symb::Symbol;
use crate::data::triple::StoreOp; use crate::data::triple::StoreOp;
use crate::data::value::DataValue; use crate::data::value::{DataValue, Number};
use crate::parse::triple::TempIdCtx; use crate::parse::triple::TempIdCtx;
#[repr(u8)] #[repr(u8)]
@ -116,7 +116,7 @@ impl AttributeTyping {
pub(crate) fn coerce_value(&self, val: DataValue) -> Result<DataValue> { pub(crate) fn coerce_value(&self, val: DataValue) -> Result<DataValue> {
match self { match self {
AttributeTyping::Ref | AttributeTyping::Component => match val { AttributeTyping::Ref | AttributeTyping::Component => match val {
DataValue::Int(s) if s > 0 => Ok(DataValue::Int(s)), DataValue::Number(Number::Int(s)) if s > 0 => Ok(DataValue::Number(Number::Int(s))),
val => Err(self.type_err(val).into()), val => Err(self.type_err(val).into()),
}, },
AttributeTyping::Bool => { AttributeTyping::Bool => {
@ -127,15 +127,15 @@ impl AttributeTyping {
} }
} }
AttributeTyping::Int => { AttributeTyping::Int => {
if matches!(val, DataValue::Int(_)) { if matches!(val, DataValue::Number(Number::Int(_))) {
Ok(val) Ok(val)
} else { } else {
Err(self.type_err(val).into()) Err(self.type_err(val).into())
} }
} }
AttributeTyping::Float => match val { AttributeTyping::Float => match val {
v @ DataValue::Float(_) => Ok(v), v @ DataValue::Number(Number::Float(_)) => Ok(v),
DataValue::Int(i) => Ok(DataValue::Float((i as f64).into())), DataValue::Number(Number::Int(i)) => Ok(DataValue::Number(Number::Float(i as f64))),
val => Err(self.type_err(val).into()), val => Err(self.type_err(val).into()),
}, },
AttributeTyping::String => { AttributeTyping::String => {
@ -154,7 +154,7 @@ impl AttributeTyping {
} }
AttributeTyping::Timestamp => match val { AttributeTyping::Timestamp => match val {
val @ DataValue::Timestamp(_) => Ok(val), val @ DataValue::Timestamp(_) => Ok(val),
DataValue::Int(i) => Ok(DataValue::Timestamp(i)), DataValue::Number(Number::Int(i)) => Ok(DataValue::Timestamp(i)),
val => Err(self.type_err(val).into()), val => Err(self.type_err(val).into()),
}, },
AttributeTyping::Bytes => { AttributeTyping::Bytes => {

@ -5,11 +5,10 @@ use std::ops::Rem;
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use itertools::Itertools; use itertools::Itertools;
use ordered_float::{Float, OrderedFloat};
use crate::data::symb::Symbol; use crate::data::symb::Symbol;
use crate::data::tuple::Tuple; use crate::data::tuple::Tuple;
use crate::data::value::DataValue; use crate::data::value::{DataValue, Number};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) enum Expr { pub(crate) enum Expr {
@ -139,38 +138,22 @@ fn op_neq(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_GT, 2, false, true); define_op!(OP_GT, 2, false, true);
fn op_gt(args: &[DataValue]) -> Result<DataValue> { fn op_gt(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(match (&args[0], &args[1]) { Ok(DataValue::Bool(args[0] > args[1]))
(DataValue::Int(a), DataValue::Float(b)) => OrderedFloat(*a as f64) > *b,
(DataValue::Float(a), DataValue::Int(b)) => *a > OrderedFloat(*b as f64),
(_, _) => args[0] > args[1],
}))
} }
define_op!(OP_GE, 2, false, true); define_op!(OP_GE, 2, false, true);
fn op_ge(args: &[DataValue]) -> Result<DataValue> { fn op_ge(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(match (&args[0], &args[1]) { Ok(DataValue::Bool(args[0] >= args[1]))
(DataValue::Int(a), DataValue::Float(b)) => OrderedFloat(*a as f64) >= *b,
(DataValue::Float(a), DataValue::Int(b)) => *a >= OrderedFloat(*b as f64),
(_, _) => args[0] >= args[1],
}))
} }
define_op!(OP_LT, 2, false, true); define_op!(OP_LT, 2, false, true);
fn op_lt(args: &[DataValue]) -> Result<DataValue> { fn op_lt(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(match (&args[0], &args[1]) { Ok(DataValue::Bool(args[0] < args[1]))
(DataValue::Int(a), DataValue::Float(b)) => OrderedFloat(*a as f64) < *b,
(DataValue::Float(a), DataValue::Int(b)) => *a < OrderedFloat(*b as f64),
(_, _) => args[0] < args[1],
}))
} }
define_op!(OP_LE, 2, false, true); define_op!(OP_LE, 2, false, true);
fn op_le(args: &[DataValue]) -> Result<DataValue> { fn op_le(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(match (&args[0], &args[1]) { Ok(DataValue::Bool(args[0] <= args[1]))
(DataValue::Int(a), DataValue::Float(b)) => OrderedFloat(*a as f64) <= *b,
(DataValue::Float(a), DataValue::Int(b)) => *a <= OrderedFloat(*b as f64),
(_, _) => args[0] <= args[1],
}))
} }
define_op!(OP_ADD, 0, true, false); define_op!(OP_ADD, 0, true, false);
@ -179,15 +162,15 @@ fn op_add(args: &[DataValue]) -> Result<DataValue> {
let mut f_accum = 0.0f64; let mut f_accum = 0.0f64;
for arg in args { for arg in args {
match arg { match arg {
DataValue::Int(i) => i_accum += i, DataValue::Number(Number::Int(i)) => i_accum += i,
DataValue::Float(f) => f_accum += f.0, DataValue::Number(Number::Float(f)) => f_accum += f,
v => bail!("unexpected arg {:?} for OP_ADD", v), v => bail!("unexpected arg {:?} for OP_ADD", v),
} }
} }
if f_accum == 0.0f64 { if f_accum == 0.0f64 {
Ok(DataValue::Int(i_accum)) Ok(DataValue::Number(Number::Int(i_accum)))
} else { } else {
Ok(DataValue::Float((i_accum as f64 + f_accum).into())) Ok(DataValue::Number(Number::Float(i_accum as f64 + f_accum)))
} }
} }
@ -196,22 +179,14 @@ fn op_max(args: &[DataValue]) -> Result<DataValue> {
let res = args let res = args
.iter() .iter()
.try_fold(None, |accum, nxt| match (accum, nxt) { .try_fold(None, |accum, nxt| match (accum, nxt) {
(None, d @ DataValue::Int(_)) => Ok(Some(d.clone())), (None, d @ DataValue::Number(_)) => Ok(Some(d.clone())),
(None, d @ DataValue::Float(_)) => Ok(Some(d.clone())), (Some(DataValue::Number(a)), DataValue::Number(b)) => {
(Some(DataValue::Int(a)), DataValue::Int(b)) => Ok(Some(DataValue::Int(a.max(*b)))), Ok(Some(DataValue::Number(a.max(*b))))
(Some(DataValue::Int(a)), DataValue::Float(b)) => {
Ok(Some(DataValue::Float(b.0.max(a as f64).into())))
}
(Some(DataValue::Float(a)), DataValue::Int(b)) => {
Ok(Some(DataValue::Float(a.0.max(*b as f64).into())))
}
(Some(DataValue::Float(a)), DataValue::Float(b)) => {
Ok(Some(DataValue::Float(a.0.max(b.0).into())))
} }
v => bail!("unexpected arg {:?} for OP_MAX", v), v => bail!("unexpected arg {:?} for OP_MAX", v),
})?; })?;
match res { match res {
None => Ok(DataValue::Float(f64::neg_infinity().into())), None => Ok(DataValue::Number(Number::Float(f64::NEG_INFINITY))),
Some(v) => Ok(v), Some(v) => Ok(v),
} }
} }
@ -221,22 +196,14 @@ fn op_min(args: &[DataValue]) -> Result<DataValue> {
let res = args let res = args
.iter() .iter()
.try_fold(None, |accum, nxt| match (accum, nxt) { .try_fold(None, |accum, nxt| match (accum, nxt) {
(None, d @ DataValue::Int(_)) => Ok(Some(d.clone())), (None, d @ DataValue::Number(_)) => Ok(Some(d.clone())),
(None, d @ DataValue::Float(_)) => Ok(Some(d.clone())), (Some(DataValue::Number(a)), DataValue::Number(b)) => {
(Some(DataValue::Int(a)), DataValue::Int(b)) => Ok(Some(DataValue::Int(a.min(*b)))), Ok(Some(DataValue::Number(a.min(*b))))
(Some(DataValue::Int(a)), DataValue::Float(b)) => {
Ok(Some(DataValue::Float(b.0.min(a as f64).into())))
}
(Some(DataValue::Float(a)), DataValue::Int(b)) => {
Ok(Some(DataValue::Float(a.0.min(*b as f64).into())))
}
(Some(DataValue::Float(a)), DataValue::Float(b)) => {
Ok(Some(DataValue::Float(a.0.min(b.0).into())))
} }
v => bail!("unexpected arg {:?} for OP_MIN", v), v => bail!("unexpected arg {:?} for OP_MIN", v),
})?; })?;
match res { match res {
None => Ok(DataValue::Float(f64::infinity().into())), None => Ok(DataValue::Number(Number::Float(f64::INFINITY))),
Some(v) => Ok(v), Some(v) => Ok(v),
} }
} }
@ -244,10 +211,18 @@ fn op_min(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_SUB, 2, false, false); define_op!(OP_SUB, 2, false, false);
fn op_sub(args: &[DataValue]) -> Result<DataValue> { fn op_sub(args: &[DataValue]) -> Result<DataValue> {
Ok(match (&args[0], &args[1]) { Ok(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Int(b)) => DataValue::Int(*a - *b), (DataValue::Number(Number::Int(a)), DataValue::Number(Number::Int(b))) => {
(DataValue::Float(a), DataValue::Float(b)) => DataValue::Float(*a - *b), DataValue::Number(Number::Int(*a - *b))
(DataValue::Int(a), DataValue::Float(b)) => DataValue::Float(((*a as f64) - b.0).into()), }
(DataValue::Float(a), DataValue::Int(b)) => DataValue::Float((a.0 - (*b as f64)).into()), (DataValue::Number(Number::Float(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float(*a - *b))
}
(DataValue::Number(Number::Int(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float((*a as f64) - b))
}
(DataValue::Number(Number::Float(a)), DataValue::Number(Number::Int(b))) => {
DataValue::Number(Number::Float(a - (*b as f64)))
}
v => bail!("unexpected arg {:?} for OP_SUB", v), v => bail!("unexpected arg {:?} for OP_SUB", v),
}) })
} }
@ -258,27 +233,33 @@ fn op_mul(args: &[DataValue]) -> Result<DataValue> {
let mut f_accum = 1.0f64; let mut f_accum = 1.0f64;
for arg in args { for arg in args {
match arg { match arg {
DataValue::Int(i) => i_accum *= i, DataValue::Number(Number::Int(i)) => i_accum *= i,
DataValue::Float(f) => f_accum *= f.0, DataValue::Number(Number::Float(f)) => f_accum *= f,
v => bail!("unexpected arg {:?} for OP_MUL", v), v => bail!("unexpected arg {:?} for OP_MUL", v),
} }
} }
if f_accum == 1.0f64 { if f_accum == 1.0f64 {
Ok(DataValue::Int(i_accum)) Ok(DataValue::Number(Number::Int(i_accum)))
} else { } else {
Ok(DataValue::Float((i_accum as f64 + f_accum).into())) Ok(DataValue::Number(Number::Float(i_accum as f64 + f_accum)))
} }
} }
define_op!(OP_DIV, 2, false, false); define_op!(OP_DIV, 2, false, false);
fn op_div(args: &[DataValue]) -> Result<DataValue> { fn op_div(args: &[DataValue]) -> Result<DataValue> {
Ok(match (&args[0], &args[1]) { Ok(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Int(b)) => { (DataValue::Number(Number::Int(a)), DataValue::Number(Number::Int(b))) => {
DataValue::Float(((*a as f64) / (*b as f64)).into()) DataValue::Number(Number::Float((*a as f64) / (*b as f64)))
}
(DataValue::Number(Number::Float(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float(*a / *b))
}
(DataValue::Number(Number::Int(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float((*a as f64) / b))
}
(DataValue::Number(Number::Float(a)), DataValue::Number(Number::Int(b))) => {
DataValue::Number(Number::Float(a / (*b as f64)))
} }
(DataValue::Float(a), DataValue::Float(b)) => DataValue::Float(*a / *b),
(DataValue::Int(a), DataValue::Float(b)) => DataValue::Float(((*a as f64) / b.0).into()),
(DataValue::Float(a), DataValue::Int(b)) => DataValue::Float((a.0 / (*b as f64)).into()),
v => bail!("unexpected arg {:?} for OP_DIV", v), v => bail!("unexpected arg {:?} for OP_DIV", v),
}) })
} }
@ -286,8 +267,8 @@ fn op_div(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_MINUS, 1, false, false); define_op!(OP_MINUS, 1, false, false);
fn op_minus(args: &[DataValue]) -> Result<DataValue> { fn op_minus(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] { Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(-(*i)), DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(-(*i))),
DataValue::Float(f) => DataValue::Float(-(*f)), DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(-(*f))),
v => bail!("unexpected arg {:?} for OP_MINUS", v), v => bail!("unexpected arg {:?} for OP_MINUS", v),
}) })
} }
@ -295,8 +276,8 @@ fn op_minus(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_ABS, 1, false, false); define_op!(OP_ABS, 1, false, false);
fn op_abs(args: &[DataValue]) -> Result<DataValue> { fn op_abs(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] { Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(i.abs()), DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(i.abs())),
DataValue::Float(f) => DataValue::Float(f.abs()), DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(f.abs())),
v => bail!("unexpected arg {:?} for OP_ABS", v), v => bail!("unexpected arg {:?} for OP_ABS", v),
}) })
} }
@ -304,8 +285,8 @@ fn op_abs(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_SIGNUM, 1, false, false); define_op!(OP_SIGNUM, 1, false, false);
fn op_signum(args: &[DataValue]) -> Result<DataValue> { fn op_signum(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] { Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(i.signum()), DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(i.signum())),
DataValue::Float(f) => DataValue::Float(f.signum()), DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(f.signum())),
v => bail!("unexpected arg {:?} for OP_SIGNUM", v), v => bail!("unexpected arg {:?} for OP_SIGNUM", v),
}) })
} }
@ -313,8 +294,8 @@ fn op_signum(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_FLOOR, 1, false, false); define_op!(OP_FLOOR, 1, false, false);
fn op_floor(args: &[DataValue]) -> Result<DataValue> { fn op_floor(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] { Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(*i), DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(*i)),
DataValue::Float(f) => DataValue::Float(f.floor()), DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(f.floor())),
v => bail!("unexpected arg {:?} for OP_FLOOR", v), v => bail!("unexpected arg {:?} for OP_FLOOR", v),
}) })
} }
@ -322,8 +303,8 @@ fn op_floor(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_CEIL, 1, false, false); define_op!(OP_CEIL, 1, false, false);
fn op_ceil(args: &[DataValue]) -> Result<DataValue> { fn op_ceil(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] { Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(*i), DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(*i)),
DataValue::Float(f) => DataValue::Float(f.ceil()), DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(f.ceil())),
v => bail!("unexpected arg {:?} for OP_CEIL", v), v => bail!("unexpected arg {:?} for OP_CEIL", v),
}) })
} }
@ -331,8 +312,8 @@ fn op_ceil(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_ROUND, 1, false, false); define_op!(OP_ROUND, 1, false, false);
fn op_round(args: &[DataValue]) -> Result<DataValue> { fn op_round(args: &[DataValue]) -> Result<DataValue> {
Ok(match &args[0] { Ok(match &args[0] {
DataValue::Int(i) => DataValue::Int(*i), DataValue::Number(Number::Int(i)) => DataValue::Number(Number::Int(*i)),
DataValue::Float(f) => DataValue::Float(f.round()), DataValue::Number(Number::Float(f)) => DataValue::Number(Number::Float(f.round())),
v => bail!("unexpected arg {:?} for OP_ROUND", v), v => bail!("unexpected arg {:?} for OP_ROUND", v),
}) })
} }
@ -340,211 +321,219 @@ fn op_round(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_EXP, 1, false, false); define_op!(OP_EXP, 1, false, false);
fn op_exp(args: &[DataValue]) -> Result<DataValue> { fn op_exp(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_EXP", v), v => bail!("unexpected arg {:?} for OP_EXP", v),
}; };
Ok(DataValue::Float(a.exp().into())) Ok(DataValue::Number(Number::Float(a.exp())))
} }
define_op!(OP_EXP2, 1, false, false); define_op!(OP_EXP2, 1, false, false);
fn op_exp2(args: &[DataValue]) -> Result<DataValue> { fn op_exp2(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_EXP2", v), v => bail!("unexpected arg {:?} for OP_EXP2", v),
}; };
Ok(DataValue::Float(a.exp2().into())) Ok(DataValue::Number(Number::Float(a.exp2())))
} }
define_op!(OP_LN, 1, false, false); define_op!(OP_LN, 1, false, false);
fn op_ln(args: &[DataValue]) -> Result<DataValue> { fn op_ln(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_LN", v), v => bail!("unexpected arg {:?} for OP_LN", v),
}; };
Ok(DataValue::Float(a.ln().into())) Ok(DataValue::Number(Number::Float(a.ln())))
} }
define_op!(OP_LOG2, 1, false, false); define_op!(OP_LOG2, 1, false, false);
fn op_log2(args: &[DataValue]) -> Result<DataValue> { fn op_log2(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_LOG2", v), v => bail!("unexpected arg {:?} for OP_LOG2", v),
}; };
Ok(DataValue::Float(a.log2().into())) Ok(DataValue::Number(Number::Float(a.log2())))
} }
define_op!(OP_LOG10, 1, false, false); define_op!(OP_LOG10, 1, false, false);
fn op_log10(args: &[DataValue]) -> Result<DataValue> { fn op_log10(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_LOG10", v), v => bail!("unexpected arg {:?} for OP_LOG10", v),
}; };
Ok(DataValue::Float(a.log10().into())) Ok(DataValue::Number(Number::Float(a.log10())))
} }
define_op!(OP_SIN, 1, false, false); define_op!(OP_SIN, 1, false, false);
fn op_sin(args: &[DataValue]) -> Result<DataValue> { fn op_sin(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_SIN", v), v => bail!("unexpected arg {:?} for OP_SIN", v),
}; };
Ok(DataValue::Float(a.sin().into())) Ok(DataValue::Number(Number::Float(a.sin())))
} }
define_op!(OP_COS, 1, false, false); define_op!(OP_COS, 1, false, false);
fn op_cos(args: &[DataValue]) -> Result<DataValue> { fn op_cos(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_COS", v), v => bail!("unexpected arg {:?} for OP_COS", v),
}; };
Ok(DataValue::Float(a.cos().into())) Ok(DataValue::Number(Number::Float(a.cos())))
} }
define_op!(OP_TAN, 1, false, false); define_op!(OP_TAN, 1, false, false);
fn op_tan(args: &[DataValue]) -> Result<DataValue> { fn op_tan(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_TAN", v), v => bail!("unexpected arg {:?} for OP_TAN", v),
}; };
Ok(DataValue::Float(a.tan().into())) Ok(DataValue::Number(Number::Float(a.tan())))
} }
define_op!(OP_ASIN, 1, false, false); define_op!(OP_ASIN, 1, false, false);
fn op_asin(args: &[DataValue]) -> Result<DataValue> { fn op_asin(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ASIN", v), v => bail!("unexpected arg {:?} for OP_ASIN", v),
}; };
Ok(DataValue::Float(a.asin().into())) Ok(DataValue::Number(Number::Float(a.asin())))
} }
define_op!(OP_ACOS, 1, false, false); define_op!(OP_ACOS, 1, false, false);
fn op_acos(args: &[DataValue]) -> Result<DataValue> { fn op_acos(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ACOS", v), v => bail!("unexpected arg {:?} for OP_ACOS", v),
}; };
Ok(DataValue::Float(a.acos().into())) Ok(DataValue::Number(Number::Float(a.acos())))
} }
define_op!(OP_ATAN, 1, false, false); define_op!(OP_ATAN, 1, false, false);
fn op_atan(args: &[DataValue]) -> Result<DataValue> { fn op_atan(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ATAN", v), v => bail!("unexpected arg {:?} for OP_ATAN", v),
}; };
Ok(DataValue::Float(a.atan().into())) Ok(DataValue::Number(Number::Float(a.atan())))
} }
define_op!(OP_ATAN2, 2, false, false); define_op!(OP_ATAN2, 2, false, false);
fn op_atan2(args: &[DataValue]) -> Result<DataValue> { fn op_atan2(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ATAN2", v), v => bail!("unexpected arg {:?} for OP_ATAN2", v),
}; };
let b = match &args[1] { let b = match &args[1] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ATAN2", v), v => bail!("unexpected arg {:?} for OP_ATAN2", v),
}; };
Ok(DataValue::Float(a.atan2(b).into())) Ok(DataValue::Number(Number::Float(a.atan2(b))))
} }
define_op!(OP_SINH, 1, false, false); define_op!(OP_SINH, 1, false, false);
fn op_sinh(args: &[DataValue]) -> Result<DataValue> { fn op_sinh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_SINH", v), v => bail!("unexpected arg {:?} for OP_SINH", v),
}; };
Ok(DataValue::Float(a.sinh().into())) Ok(DataValue::Number(Number::Float(a.sinh())))
} }
define_op!(OP_COSH, 1, false, false); define_op!(OP_COSH, 1, false, false);
fn op_cosh(args: &[DataValue]) -> Result<DataValue> { fn op_cosh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_COSH", v), v => bail!("unexpected arg {:?} for OP_COSH", v),
}; };
Ok(DataValue::Float(a.cosh().into())) Ok(DataValue::Number(Number::Float(a.cosh())))
} }
define_op!(OP_TANH, 1, false, false); define_op!(OP_TANH, 1, false, false);
fn op_tanh(args: &[DataValue]) -> Result<DataValue> { fn op_tanh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_TANH", v), v => bail!("unexpected arg {:?} for OP_TANH", v),
}; };
Ok(DataValue::Float(a.tanh().into())) Ok(DataValue::Number(Number::Float(a.tanh())))
} }
define_op!(OP_ASINH, 1, false, false); define_op!(OP_ASINH, 1, false, false);
fn op_asinh(args: &[DataValue]) -> Result<DataValue> { fn op_asinh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ASINH", v), v => bail!("unexpected arg {:?} for OP_ASINH", v),
}; };
Ok(DataValue::Float(a.asinh().into())) Ok(DataValue::Number(Number::Float(a.asinh())))
} }
define_op!(OP_ACOSH, 1, false, false); define_op!(OP_ACOSH, 1, false, false);
fn op_acosh(args: &[DataValue]) -> Result<DataValue> { fn op_acosh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ACOSH", v), v => bail!("unexpected arg {:?} for OP_ACOSH", v),
}; };
Ok(DataValue::Float(a.acosh().into())) Ok(DataValue::Number(Number::Float(a.acosh())))
} }
define_op!(OP_ATANH, 1, false, false); define_op!(OP_ATANH, 1, false, false);
fn op_atanh(args: &[DataValue]) -> Result<DataValue> { fn op_atanh(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_ATANH", v), v => bail!("unexpected arg {:?} for OP_ATANH", v),
}; };
Ok(DataValue::Float(a.atanh().into())) Ok(DataValue::Number(Number::Float(a.atanh())))
} }
define_op!(OP_POW, 2, false, false); define_op!(OP_POW, 2, false, false);
fn op_pow(args: &[DataValue]) -> Result<DataValue> { fn op_pow(args: &[DataValue]) -> Result<DataValue> {
let a = match &args[0] { let a = match &args[0] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_POW", v), v => bail!("unexpected arg {:?} for OP_POW", v),
}; };
let b = match &args[1] { let b = match &args[1] {
DataValue::Int(i) => *i as f64, DataValue::Number(Number::Int(i)) => *i as f64,
DataValue::Float(f) => f.0, DataValue::Number(Number::Float(f)) => *f,
v => bail!("unexpected arg {:?} for OP_POW", v), v => bail!("unexpected arg {:?} for OP_POW", v),
}; };
Ok(DataValue::Float(a.powf(b).into())) Ok(DataValue::Number(Number::Float(a.powf(b))))
} }
define_op!(OP_MOD, 2, false, false); define_op!(OP_MOD, 2, false, false);
fn op_mod(args: &[DataValue]) -> Result<DataValue> { fn op_mod(args: &[DataValue]) -> Result<DataValue> {
Ok(match (&args[0], &args[1]) { Ok(match (&args[0], &args[1]) {
(DataValue::Int(a), DataValue::Int(b)) => DataValue::Int(a.rem(b)), (DataValue::Number(Number::Int(a)), DataValue::Number(Number::Int(b))) => {
(DataValue::Float(a), DataValue::Float(b)) => DataValue::Float(a.rem(*b)), DataValue::Number(Number::Int(a.rem(b)))
(DataValue::Int(a), DataValue::Float(b)) => DataValue::Float(((*a as f64).rem(b.0)).into()), }
(DataValue::Float(a), DataValue::Int(b)) => DataValue::Float((a.0.rem(*b as f64)).into()), (DataValue::Number(Number::Float(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float(a.rem(*b)))
}
(DataValue::Number(Number::Int(a)), DataValue::Number(Number::Float(b))) => {
DataValue::Number(Number::Float((*a as f64).rem(b)))
}
(DataValue::Number(Number::Float(a)), DataValue::Number(Number::Int(b))) => {
DataValue::Number(Number::Float(a.rem(*b as f64)))
}
v => bail!("unexpected arg {:?} for OP_MOD", v), v => bail!("unexpected arg {:?} for OP_MOD", v),
}) })
} }
@ -632,19 +621,25 @@ fn op_is_null(args: &[DataValue]) -> Result<DataValue> {
define_op!(OP_IS_INT, 1, false, true); define_op!(OP_IS_INT, 1, false, true);
fn op_is_int(args: &[DataValue]) -> Result<DataValue> { fn op_is_int(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(matches!(args[0], DataValue::Int(_)))) Ok(DataValue::Bool(matches!(
args[0],
DataValue::Number(Number::Int(_))
)))
} }
define_op!(OP_IS_FLOAT, 1, false, true); define_op!(OP_IS_FLOAT, 1, false, true);
fn op_is_float(args: &[DataValue]) -> Result<DataValue> { fn op_is_float(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(matches!(args[0], DataValue::Float(_)))) Ok(DataValue::Bool(matches!(
args[0],
DataValue::Number(Number::Float(_))
)))
} }
define_op!(OP_IS_NUM, 1, false, true); define_op!(OP_IS_NUM, 1, false, true);
fn op_is_num(args: &[DataValue]) -> Result<DataValue> { fn op_is_num(args: &[DataValue]) -> Result<DataValue> {
Ok(DataValue::Bool(matches!( Ok(DataValue::Bool(matches!(
args[0], args[0],
DataValue::Int(_) | DataValue::Float(_) DataValue::Number(Number::Int(_)) | DataValue::Number(Number::Float(_))
))) )))
} }

@ -90,7 +90,7 @@ impl EntityId {
pub(crate) const MAX_PERM: EntityId = EntityId(0x00ff_ffff_ff00_0000); pub(crate) const MAX_PERM: EntityId = EntityId(0x00ff_ffff_ff00_0000);
pub(crate) fn to_value(&self) -> DataValue { pub(crate) fn to_value(&self) -> DataValue {
DataValue::Int(self.0 as i64) DataValue::from(self.0 as i64)
} }
pub(crate) fn from_bytes(b: &[u8]) -> Self { pub(crate) fn from_bytes(b: &[u8]) -> Self {

@ -5,7 +5,7 @@ pub(crate) use serde_json::Value as JsonValue;
use crate::data::attr::{Attribute, AttributeCardinality, AttributeIndex, AttributeTyping}; use crate::data::attr::{Attribute, AttributeCardinality, AttributeIndex, AttributeTyping};
use crate::data::id::{AttrId, EntityId, TxId}; use crate::data::id::{AttrId, EntityId, TxId};
use crate::data::symb::Symbol; use crate::data::symb::Symbol;
use crate::data::value::DataValue; use crate::data::value::{DataValue, Number};
impl From<JsonValue> for DataValue { impl From<JsonValue> for DataValue {
fn from(v: JsonValue) -> Self { fn from(v: JsonValue) -> Self {
@ -13,9 +13,9 @@ impl From<JsonValue> for DataValue {
JsonValue::Null => DataValue::Null, JsonValue::Null => DataValue::Null,
JsonValue::Bool(b) => DataValue::Bool(b), JsonValue::Bool(b) => DataValue::Bool(b),
JsonValue::Number(n) => match n.as_i64() { JsonValue::Number(n) => match n.as_i64() {
Some(i) => DataValue::Int(i), Some(i) => DataValue::from(i),
None => match n.as_f64() { None => match n.as_f64() {
Some(f) => DataValue::Float(f.into()), Some(f) => DataValue::from(f),
None => DataValue::String(n.to_string().into()), None => DataValue::String(n.to_string().into()),
}, },
}, },
@ -38,9 +38,9 @@ impl<'a> From<&'a JsonValue> for DataValue {
JsonValue::Null => DataValue::Null, JsonValue::Null => DataValue::Null,
JsonValue::Bool(b) => DataValue::Bool(*b), JsonValue::Bool(b) => DataValue::Bool(*b),
JsonValue::Number(n) => match n.as_i64() { JsonValue::Number(n) => match n.as_i64() {
Some(i) => DataValue::Int(i), Some(i) => DataValue::from(i),
None => match n.as_f64() { None => match n.as_f64() {
Some(f) => DataValue::Float(f.into()), Some(f) => DataValue::from(f),
None => DataValue::String(n.to_string().into()), None => DataValue::String(n.to_string().into()),
}, },
}, },
@ -62,8 +62,8 @@ impl From<DataValue> for JsonValue {
match v { match v {
DataValue::Null => JsonValue::Null, DataValue::Null => JsonValue::Null,
DataValue::Bool(b) => JsonValue::Bool(b), DataValue::Bool(b) => JsonValue::Bool(b),
DataValue::Int(i) => JsonValue::Number(i.into()), DataValue::Number(Number::Int(i)) => JsonValue::Number(i.into()),
DataValue::Float(f) => json!(f.0), DataValue::Number(Number::Float(f)) => json!(f),
DataValue::String(t) => JsonValue::String(t.into()), DataValue::String(t) => JsonValue::String(t.into()),
DataValue::Uuid(uuid) => JsonValue::String(uuid.to_string()), DataValue::Uuid(uuid) => JsonValue::String(uuid.to_string()),
DataValue::Bytes(bytes) => JsonValue::String(base64::encode(bytes)), DataValue::Bytes(bytes) => JsonValue::String(base64::encode(bytes)),
@ -73,7 +73,7 @@ impl From<DataValue> for JsonValue {
DataValue::DescVal(v) => JsonValue::from(*v.0), DataValue::DescVal(v) => JsonValue::from(*v.0),
DataValue::Bottom => JsonValue::Null, DataValue::Bottom => JsonValue::Null,
DataValue::Timestamp(i) => JsonValue::Number(i.into()), DataValue::Timestamp(i) => JsonValue::Number(i.into()),
DataValue::Guard => JsonValue::Null DataValue::Guard => JsonValue::Null,
} }
} }
} }
@ -99,18 +99,11 @@ impl TryFrom<&'_ JsonValue> for Attribute {
None => AttrId(0), None => AttrId(0),
Some(v) => AttrId::try_from(v)?, Some(v) => AttrId::try_from(v)?,
}; };
let name = map.get("name").ok_or_else(|| { let name = map
anyhow!( .get("name")
"expect field 'name' in attribute definition, got {}", .ok_or_else(|| anyhow!("expect field 'name' in attribute definition, got {}", value))?;
value
)
})?;
let symb = Symbol::try_from(name)?; let symb = Symbol::try_from(name)?;
ensure!( ensure!(!symb.is_reserved(), "cannot use reserved symbol {}", symb);
!symb.is_reserved(),
"cannot use reserved symbol {}",
symb
);
let cardinality = map let cardinality = map
.get("cardinality") .get("cardinality")
.ok_or_else(|| anyhow!("expect field 'cardinality' in {}", value))? .ok_or_else(|| anyhow!("expect field 'cardinality' in {}", value))?

@ -1,8 +1,7 @@
use std::cmp::Reverse; use std::cmp::{Ordering, Reverse};
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Display, Formatter};
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use ordered_float::OrderedFloat;
use rmp_serde::Serializer; use rmp_serde::Serializer;
use serde::Serialize; use serde::Serialize;
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
@ -21,9 +20,7 @@ pub(crate) enum DataValue {
#[serde(rename = "b")] #[serde(rename = "b")]
Bool(bool), Bool(bool),
#[serde(rename = "i")] #[serde(rename = "i")]
Int(i64), Number(Number),
#[serde(rename = "f")]
Float(OrderedFloat<f64>),
#[serde(rename = "s")] #[serde(rename = "s")]
String(SmartString<LazyCompact>), String(SmartString<LazyCompact>),
#[serde(rename = "u")] #[serde(rename = "u")]
@ -43,6 +40,83 @@ pub(crate) enum DataValue {
Bottom, Bottom,
} }
impl From<i64> for DataValue {
fn from(v: i64) -> Self {
DataValue::Number(Number::Int(v))
}
}
impl From<f64> for DataValue {
fn from(v: f64) -> Self {
DataValue::Number(Number::Float(v))
}
}
#[derive(Copy, Clone, Deserialize, Serialize)]
pub(crate) enum Number {
#[serde(rename = "i")]
Int(i64),
#[serde(rename = "f")]
Float(f64),
}
impl PartialEq for Number {
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Eq for Number {}
impl Display for Number {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Number::Int(i) => write!(f, "{}", i),
Number::Float(n) => write!(f, "{}", n),
}
}
}
impl Debug for Number {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Number::Int(i) => write!(f, "{}", i),
Number::Float(n) => write!(f, "{}", n),
}
}
}
impl PartialOrd for Number {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Number {
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Number::Int(i), Number::Float(r)) => {
let l = *i as f64;
match l.total_cmp(&r) {
Ordering::Less => Ordering::Less,
Ordering::Equal => Ordering::Less,
Ordering::Greater => Ordering::Greater,
}
}
(Number::Float(l), Number::Int(i)) => {
let r = *i as f64;
match l.total_cmp(&r) {
Ordering::Less => Ordering::Less,
Ordering::Equal => Ordering::Greater,
Ordering::Greater => Ordering::Greater,
}
}
(Number::Int(l), Number::Int(r)) => l.cmp(r),
(Number::Float(l), Number::Float(r)) => l.total_cmp(r),
}
}
}
impl Debug for DataValue { impl Debug for DataValue {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
@ -52,12 +126,9 @@ impl Debug for DataValue {
DataValue::Bool(b) => { DataValue::Bool(b) => {
write!(f, "{}", b) write!(f, "{}", b)
} }
DataValue::Int(i) => { DataValue::Number(i) => {
write!(f, "{}", i) write!(f, "{}", i)
} }
DataValue::Float(n) => {
write!(f, "{}", n.0)
}
DataValue::String(s) => { DataValue::String(s) => {
write!(f, "{:?}", s) write!(f, "{:?}", s)
} }
@ -101,7 +172,7 @@ impl DataValue {
pub(crate) fn get_entity_id(&self) -> Result<EntityId> { pub(crate) fn get_entity_id(&self) -> Result<EntityId> {
match self { match self {
DataValue::Int(id) => Ok(EntityId(*id as u64)), DataValue::Number(Number::Int(id)) => Ok(EntityId(*id as u64)),
_ => bail!("type mismatch: expect type EntId, got value {:?}", self), _ => bail!("type mismatch: expect type EntId, got value {:?}", self),
} }
} }

@ -633,7 +633,7 @@ impl SessionTx {
if let Some(o) = value_rep.as_object() { if let Some(o) = value_rep.as_object() {
return if attr.val_type.is_ref_type() { return if attr.val_type.is_ref_type() {
let eid = self.parse_eid_from_map(o, vld)?; let eid = self.parse_eid_from_map(o, vld)?;
Ok(InputTerm::Const(DataValue::Int(eid.0 as i64))) Ok(InputTerm::Const(DataValue::from(eid.0 as i64)))
} else { } else {
Ok(InputTerm::Const(self.parse_value_from_map(o, attr)?)) Ok(InputTerm::Const(self.parse_value_from_map(o, attr)?))
}; };

@ -36,7 +36,7 @@ impl SessionTx {
val val
}) })
.collect_vec(); .collect_vec();
key.push(DataValue::Int(idx as i64)); key.push(DataValue::from(idx as i64));
let key = Tuple(key); let key = Tuple(key);
let encoded_key = key.encode_as_key_for_epoch(ret.id, 0); let encoded_key = key.encode_as_key_for_epoch(ret.id, 0);
let encoded_val = tuple.encode_as_key_for_epoch(ret.id, 0); let encoded_val = tuple.encode_as_key_for_epoch(ret.id, 0);

@ -136,7 +136,7 @@ impl TempStore {
vals.push(tuple.0[idx].clone()); vals.push(tuple.0[idx].clone());
} }
} }
vals.push(DataValue::Int(serial as i64)); vals.push(DataValue::from(serial as i64));
self.db self.db
.put(&Tuple(vals).encode_as_key_for_epoch(self.id, 0), &[]) .put(&Tuple(vals).encode_as_key_for_epoch(self.id, 0), &[])
} }

@ -1,6 +1,6 @@
{"_temp_id": "3742", "continent.code": "EU", "continent.desc": "Europe"} {"_temp_id": "3742", "continent.code": "EU", "continent.desc": "Europe"}
{"_temp_id": "3743", "continent.code": "AF", "continent.desc": "Africa"} {"_temp_id": "3743", "continent.code": "AF", "continent.desc": "Africa"}
{"_temp_id": "3744", "continent.desc": "North America"} {"_temp_id": "3744", "continent.code": "NA", "continent.desc": "North America"}
{"_temp_id": "3745", "continent.code": "SA", "continent.desc": "South America"} {"_temp_id": "3745", "continent.code": "SA", "continent.desc": "South America"}
{"_temp_id": "3746", "continent.code": "AS", "continent.desc": "Asia"} {"_temp_id": "3746", "continent.code": "AS", "continent.desc": "Asia"}
{"_temp_id": "3747", "continent.code": "OC", "continent.desc": "Oceania"} {"_temp_id": "3747", "continent.code": "OC", "continent.desc": "Oceania"}

@ -287,5 +287,22 @@ fn air_routes() -> Result<()> {
.unwrap() .unwrap()
); );
let n_airports_by_continent_time = Instant::now();
let res = db.run_script(
r#"
airports_by_continent[?c, count(?a)] := [?a airport.iata ?_], [?c geo.contains ?a];
?[?cont, max(?count)] := airports_by_continent[?c, ?count], [?c continent.code ?cont];
?[?cont, max(?count)] := [?_ continent.code ?cont], ?count is 0;
"#,
)?;
dbg!(n_airports_by_continent_time.elapsed());
assert_eq!(
res,
serde_json::Value::from_str(
r#"[["AF",321],["AN",0],["AS",971],["EU",605],["NA",989],["OC",305],["SA",313]]"#
)
.unwrap()
);
Ok(()) Ok(())
} }

Loading…
Cancel
Save