another round of refactoring
parent
bb1eeacc71
commit
304ea38e29
@ -0,0 +1,6 @@
|
||||
pub(crate) mod expr;
|
||||
pub(crate) mod op;
|
||||
pub(crate) mod tuple;
|
||||
pub(crate) mod tuple_set;
|
||||
pub(crate) mod typing;
|
||||
pub(crate) mod value;
|
@ -0,0 +1,21 @@
|
||||
use crate::data::op::Op;
|
||||
use crate::data::tuple_set::{ColId, TableId, TupleSetIdx};
|
||||
use crate::data::value::Value;
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(crate) enum Expr<'a> {
|
||||
Const(Value<'a>),
|
||||
List(Vec<Expr<'a>>),
|
||||
Dict(BTreeMap<String, Expr<'a>>),
|
||||
Variable(String),
|
||||
TableCol(TableId, ColId),
|
||||
TupleSetIdx(TupleSetIdx),
|
||||
Apply(Arc<Op>, Vec<Expr<'a>>),
|
||||
FieldAcc(String, Box<Expr<'a>>),
|
||||
IdxAcc(usize, Box<Expr<'a>>),
|
||||
}
|
||||
|
||||
pub(crate) type StaticExpr = Expr<'static>;
|
||||
|
||||
// TODO serde expr into value
|
@ -0,0 +1 @@
|
||||
pub(crate) struct Op;
|
@ -0,0 +1,47 @@
|
||||
#[repr(u8)]
|
||||
#[derive(Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub(crate) enum Tag {
|
||||
BoolFalse = 1,
|
||||
Null = 2,
|
||||
BoolTrue = 3,
|
||||
Int = 4,
|
||||
Float = 5,
|
||||
Text = 6,
|
||||
Uuid = 7,
|
||||
|
||||
Bytes = 64,
|
||||
|
||||
List = 128,
|
||||
Dict = 129,
|
||||
|
||||
DescVal = 192,
|
||||
|
||||
Max = 255,
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for Tag {
|
||||
type Error = u8;
|
||||
#[inline]
|
||||
fn try_from(u: u8) -> std::result::Result<Tag, u8> {
|
||||
use self::Tag::*;
|
||||
Ok(match u {
|
||||
1 => BoolFalse,
|
||||
2 => Null,
|
||||
3 => BoolTrue,
|
||||
4 => Int,
|
||||
5 => Float,
|
||||
6 => Text,
|
||||
7 => Uuid,
|
||||
|
||||
64 => Bytes,
|
||||
|
||||
128 => List,
|
||||
129 => Dict,
|
||||
|
||||
192 => DescVal,
|
||||
|
||||
255 => Max,
|
||||
v => return Err(v),
|
||||
})
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
pub(crate) struct TableId;
|
||||
pub(crate) struct ColId;
|
||||
pub(crate) struct TupleSetIdx;
|
@ -0,0 +1,207 @@
|
||||
use crate::data::value::{StaticValue, Value};
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::result;
|
||||
use pest::{Parser};
|
||||
use pest::iterators::Pair;
|
||||
use crate::parser::{CozoParser, Rule};
|
||||
use crate::parser::text_identifier::build_name_in_def;
|
||||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub(crate) enum TypingError {
|
||||
#[error("Not null constraint violated for {0}")]
|
||||
NotNullViolated(Typing),
|
||||
|
||||
#[error("Type mismatch: {1} cannot be interpreted as {0}")]
|
||||
TypeMismatch(Typing, StaticValue),
|
||||
|
||||
#[error("Undefined type '{0}'")]
|
||||
UndefinedType(String),
|
||||
|
||||
#[error(transparent)]
|
||||
Parse(#[from] pest::error::Error<Rule>),
|
||||
|
||||
#[error(transparent)]
|
||||
TextParse(#[from] crate::parser::text_identifier::TextParseError)
|
||||
}
|
||||
|
||||
type Result<T> = result::Result<T, TypingError>;
|
||||
|
||||
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone)]
|
||||
pub(crate) enum Typing {
|
||||
Any,
|
||||
Bool,
|
||||
Int,
|
||||
Float,
|
||||
Text,
|
||||
Uuid,
|
||||
Nullable(Box<Typing>),
|
||||
Homogeneous(Box<Typing>),
|
||||
UnnamedTuple(Vec<Typing>),
|
||||
NamedTuple(Vec<(String, Typing)>),
|
||||
}
|
||||
|
||||
impl Display for Typing {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Typing::Any => write!(f, "Any"),
|
||||
Typing::Bool => write!(f, "Bool"),
|
||||
Typing::Int => write!(f, "Int"),
|
||||
Typing::Float => write!(f, "Float"),
|
||||
Typing::Text => write!(f, "Text"),
|
||||
Typing::Uuid => write!(f, "Uuid"),
|
||||
Typing::Nullable(t) => write!(f, "?{}", t),
|
||||
Typing::Homogeneous(h) => write!(f, "[{}]", h),
|
||||
Typing::UnnamedTuple(u) => {
|
||||
let collected = u.iter().map(|v| v.to_string()).collect::<Vec<_>>();
|
||||
let joined = collected.join(",");
|
||||
write!(f, "({})", joined)
|
||||
}
|
||||
Typing::NamedTuple(n) => {
|
||||
let collected = n
|
||||
.iter()
|
||||
.map(|(k, v)| format!(r##""{}":{}"##, k, v))
|
||||
.collect::<Vec<_>>();
|
||||
let joined = collected.join(",");
|
||||
write!(f, "{{")?;
|
||||
write!(f, "{}", joined)?;
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Typing {
|
||||
pub(crate) fn coerce<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
|
||||
if *self == Typing::Any {
|
||||
return Ok(v);
|
||||
}
|
||||
if v == Value::Null {
|
||||
return if matches!(self, Typing::Nullable(_)) {
|
||||
Ok(Value::Null)
|
||||
} else {
|
||||
Err(TypingError::NotNullViolated(self.clone()))
|
||||
};
|
||||
}
|
||||
|
||||
if let Typing::Nullable(t) = self {
|
||||
return t.coerce(v);
|
||||
}
|
||||
|
||||
match self {
|
||||
Typing::Bool => self.coerce_bool(v),
|
||||
Typing::Int => self.coerce_int(v),
|
||||
Typing::Float => self.coerce_float(v),
|
||||
Typing::Text => self.coerce_text(v),
|
||||
Typing::Uuid => self.coerce_uuid(v),
|
||||
Typing::Homogeneous(t) => match v {
|
||||
Value::List(vs) => Ok(Value::List(
|
||||
vs.into_iter()
|
||||
.map(|v| t.coerce(v))
|
||||
.collect::<Result<Vec<_>>>()?,
|
||||
)),
|
||||
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
|
||||
},
|
||||
Typing::UnnamedTuple(_ut) => {
|
||||
todo!()
|
||||
}
|
||||
Typing::NamedTuple(_nt) => {
|
||||
todo!()
|
||||
}
|
||||
Typing::Any => unreachable!(),
|
||||
Typing::Nullable(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
fn coerce_bool<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
|
||||
match v {
|
||||
v @ Value::Bool(_) => Ok(v),
|
||||
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
|
||||
}
|
||||
}
|
||||
fn coerce_int<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
|
||||
match v {
|
||||
v @ Value::Int(_) => Ok(v),
|
||||
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
|
||||
}
|
||||
}
|
||||
fn coerce_float<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
|
||||
match v {
|
||||
v @ Value::Float(_) => Ok(v),
|
||||
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
|
||||
}
|
||||
}
|
||||
fn coerce_text<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
|
||||
match v {
|
||||
v @ Value::Text(_) => Ok(v),
|
||||
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
|
||||
}
|
||||
}
|
||||
fn coerce_uuid<'a>(&self, v: Value<'a>) -> Result<Value<'a>> {
|
||||
match v {
|
||||
v @ Value::Uuid(_) => Ok(v),
|
||||
_ => Err(TypingError::TypeMismatch(self.clone(), v.to_static())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl TryFrom<&str> for Typing {
|
||||
type Error = TypingError;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self> {
|
||||
let pair = CozoParser::parse(Rule::typing, value)?.next().unwrap();
|
||||
Typing::from_pair(pair)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a> TryFrom<Value<'a>> for Typing {
|
||||
type Error = TypingError;
|
||||
|
||||
fn try_from(value: Value<'a>) -> result::Result<Self, Self::Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Typing {
|
||||
pub fn from_pair<'a>(pair: Pair<Rule>) -> Result<Self> {
|
||||
Ok(match pair.as_rule() {
|
||||
Rule::simple_type => match pair.as_str() {
|
||||
"Any" => Typing::Any,
|
||||
"Bool" => Typing::Bool,
|
||||
"Int" => Typing::Int,
|
||||
"Float" => Typing::Float,
|
||||
"Text" => Typing::Text,
|
||||
"Uuid" => Typing::Uuid,
|
||||
t => return Err(TypingError::UndefinedType(t.to_string())),
|
||||
},
|
||||
Rule::nullable_type => Typing::Nullable(Box::new(Typing::from_pair(
|
||||
pair.into_inner().next().unwrap()
|
||||
)?)),
|
||||
Rule::homogeneous_list_type => Typing::Homogeneous(Box::new(Typing::from_pair(
|
||||
pair.into_inner().next().unwrap()
|
||||
)?)),
|
||||
Rule::unnamed_tuple_type => {
|
||||
let types = pair
|
||||
.into_inner()
|
||||
.map(|p| Typing::from_pair(p))
|
||||
.collect::<Result<Vec<Typing>>>()?;
|
||||
Typing::UnnamedTuple(types)
|
||||
}
|
||||
Rule::named_tuple_type => {
|
||||
let types = pair
|
||||
.into_inner()
|
||||
.map(|p| -> Result<(String, Typing)> {
|
||||
let mut ps = p.into_inner();
|
||||
let name_pair = ps.next().unwrap();
|
||||
let name = build_name_in_def(name_pair, true)?;
|
||||
let typ_pair = ps.next().unwrap();
|
||||
let typ = Typing::from_pair(typ_pair)?;
|
||||
Ok((name, typ))
|
||||
})
|
||||
.collect::<Result<Vec<(String, Typing)>>>()?;
|
||||
Typing::NamedTuple(types)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
}
|
@ -0,0 +1,260 @@
|
||||
use ordered_float::OrderedFloat;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::{min, Reverse};
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::{Debug, Display, Formatter, Write};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Clone, PartialEq, Ord, PartialOrd, Eq)]
|
||||
pub enum Value<'a> {
|
||||
Null,
|
||||
Bool(bool),
|
||||
Int(i64),
|
||||
Float(OrderedFloat<f64>),
|
||||
Uuid(Uuid),
|
||||
Text(Cow<'a, str>),
|
||||
Bytes(Cow<'a, [u8]>),
|
||||
|
||||
List(Vec<Value<'a>>),
|
||||
Dict(BTreeMap<Cow<'a, str>, Value<'a>>),
|
||||
|
||||
DescVal(Reverse<Box<Value<'a>>>),
|
||||
|
||||
EndSentinel,
|
||||
}
|
||||
|
||||
pub(crate) type StaticValue = Value<'static>;
|
||||
|
||||
impl<'a> Debug for Value<'a> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Value {{ {} }}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<()> for StaticValue {
|
||||
#[inline]
|
||||
fn from(_: ()) -> Self {
|
||||
Value::Null
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for StaticValue {
|
||||
#[inline]
|
||||
fn from(b: bool) -> Self {
|
||||
Value::Bool(b)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for StaticValue {
|
||||
#[inline]
|
||||
fn from(i: i64) -> Self {
|
||||
Value::Int(i)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for StaticValue {
|
||||
#[inline]
|
||||
fn from(i: i32) -> Self {
|
||||
Value::Int(i as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for StaticValue {
|
||||
#[inline]
|
||||
fn from(f: f64) -> Self {
|
||||
Value::Float(f.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OrderedFloat<f64>> for StaticValue {
|
||||
#[inline]
|
||||
fn from(f: OrderedFloat<f64>) -> Self {
|
||||
Value::Float(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Value<'a> {
|
||||
#[inline]
|
||||
fn from(s: &'a str) -> Self {
|
||||
Value::Text(Cow::Borrowed(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a [u8]> for Value<'a> {
|
||||
#[inline]
|
||||
fn from(v: &'a [u8]) -> Self {
|
||||
Value::Bytes(Cow::Borrowed(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for StaticValue {
|
||||
#[inline]
|
||||
fn from(s: String) -> Self {
|
||||
Value::Text(Cow::Owned(s))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for StaticValue {
|
||||
#[inline]
|
||||
fn from(v: Vec<u8>) -> Self {
|
||||
Value::Bytes(Cow::Owned(v))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Uuid> for StaticValue {
|
||||
#[inline]
|
||||
fn from(u: Uuid) -> Self {
|
||||
Value::Uuid(u)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Vec<Value<'a>>> for Value<'a> {
|
||||
#[inline]
|
||||
fn from(v: Vec<Value<'a>>) -> Self {
|
||||
Value::List(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<BTreeMap<Cow<'a, str>, Value<'a>>> for Value<'a> {
|
||||
#[inline]
|
||||
fn from(m: BTreeMap<Cow<'a, str>, Value<'a>>) -> Self {
|
||||
Value::Dict(m)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Display for Value<'a> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Value::Null => {
|
||||
write!(f, "null")?;
|
||||
}
|
||||
Value::Bool(b) => {
|
||||
write!(f, "{}", if *b { "true" } else { "false" })?;
|
||||
}
|
||||
Value::Int(i) => {
|
||||
write!(f, "{}", i)?;
|
||||
}
|
||||
Value::Float(n) => {
|
||||
write!(f, "{}", n.into_inner())?;
|
||||
}
|
||||
Value::Uuid(u) => {
|
||||
write!(f, "{}", u)?;
|
||||
}
|
||||
Value::Bytes(b) => {
|
||||
write!(f, "<{} bytes: {:?} ..>", b.len(), &b[..min(8, b.len())])?;
|
||||
}
|
||||
Value::Text(t) => {
|
||||
f.write_char('"')?;
|
||||
for char in t.chars() {
|
||||
match char {
|
||||
'"' => {
|
||||
f.write_str("\\\"")?;
|
||||
}
|
||||
'\\' => {
|
||||
f.write_str("\\\\")?;
|
||||
}
|
||||
'/' => {
|
||||
f.write_str("\\/")?;
|
||||
}
|
||||
'\x08' => {
|
||||
f.write_str("\\b")?;
|
||||
}
|
||||
'\x0c' => {
|
||||
f.write_str("\\f")?;
|
||||
}
|
||||
'\n' => {
|
||||
f.write_str("\\n")?;
|
||||
}
|
||||
'\r' => {
|
||||
f.write_str("\\r")?;
|
||||
}
|
||||
'\t' => {
|
||||
f.write_str("\\t")?;
|
||||
}
|
||||
c => {
|
||||
f.write_char(c)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
f.write_char('"')?;
|
||||
}
|
||||
Value::List(l) => {
|
||||
f.write_char('[')?;
|
||||
let mut first = true;
|
||||
for v in l.iter() {
|
||||
if !first {
|
||||
f.write_char(',')?;
|
||||
}
|
||||
Display::fmt(v, f)?;
|
||||
first = false;
|
||||
}
|
||||
f.write_char(']')?;
|
||||
}
|
||||
Value::Dict(d) => {
|
||||
f.write_char('{')?;
|
||||
let mut first = true;
|
||||
for (k, v) in d.iter() {
|
||||
if !first {
|
||||
f.write_char(',')?;
|
||||
}
|
||||
Display::fmt(&Value::Text(k.clone()), f)?;
|
||||
f.write_char(':')?;
|
||||
Display::fmt(v, f)?;
|
||||
first = false;
|
||||
}
|
||||
f.write_char('}')?;
|
||||
}
|
||||
Value::EndSentinel => write!(f, "Sentinel")?,
|
||||
Value::DescVal(Reverse(v)) => {
|
||||
write!(f, "~{}", v)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Value<'a> {
|
||||
#[inline]
|
||||
pub fn to_static(self) -> StaticValue {
|
||||
match self {
|
||||
Value::Null => Value::from(()),
|
||||
Value::Bool(b) => Value::from(b),
|
||||
Value::Int(i) => Value::from(i),
|
||||
Value::Float(f) => Value::from(f),
|
||||
Value::Uuid(u) => Value::from(u),
|
||||
Value::Text(t) => Value::from(t.into_owned()),
|
||||
Value::List(l) => l
|
||||
.into_iter()
|
||||
.map(|v| v.to_static())
|
||||
.collect::<Vec<StaticValue>>()
|
||||
.into(),
|
||||
Value::Dict(d) => d
|
||||
.into_iter()
|
||||
.map(|(k, v)| (Cow::Owned(k.into_owned()), v.to_static()))
|
||||
.collect::<BTreeMap<Cow<'static, str>, StaticValue>>()
|
||||
.into(),
|
||||
Value::EndSentinel => panic!("Cannot process sentinel value"),
|
||||
Value::Bytes(t) => Value::from(t.into_owned()),
|
||||
Value::DescVal(Reverse(val)) => Value::DescVal(Reverse(val.to_static().into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::data::value::Value;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::mem::size_of;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[test]
|
||||
fn print_sizes() {
|
||||
dbg!(size_of::<usize>());
|
||||
dbg!(size_of::<Uuid>());
|
||||
dbg!(size_of::<Cow<str>>());
|
||||
dbg!(size_of::<BTreeMap<(), ()>>());
|
||||
dbg!(size_of::<HashMap<(), ()>>());
|
||||
dbg!(size_of::<Value>());
|
||||
}
|
||||
}
|
@ -1,28 +1,7 @@
|
||||
extern crate core;
|
||||
|
||||
// pub mod value;
|
||||
// pub mod typing;
|
||||
// pub mod env;
|
||||
// pub mod ast;
|
||||
// pub mod parser;
|
||||
// pub mod eval;
|
||||
// pub mod function;
|
||||
// pub mod definition;
|
||||
// pub mod storage;
|
||||
// pub mod mutation;
|
||||
// pub mod plan;
|
||||
pub mod db;
|
||||
pub mod error;
|
||||
pub mod parser;
|
||||
pub mod relation;
|
||||
pub(crate) mod eval;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn import() {
|
||||
use cozorocks::*;
|
||||
let _o = OptionsPtr::default();
|
||||
println!("Hello");
|
||||
}
|
||||
}
|
||||
// pub mod db;
|
||||
// pub mod error;
|
||||
// pub mod relation;
|
||||
// pub(crate) mod eval;
|
||||
pub(crate) mod parser;
|
||||
pub(crate) mod data;
|
||||
pub(crate) mod logger;
|
||||
|
@ -0,0 +1,28 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
fn init_logger() {
|
||||
let _ = env_logger::builder()
|
||||
// Include all events in tests
|
||||
.filter_level(log::LevelFilter::max())
|
||||
// Ensure events are captured by `cargo test`
|
||||
.is_test(true)
|
||||
// Ignore errors initializing the logger if tests race to configure it
|
||||
.try_init();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_logger() {
|
||||
use log::{debug, error, info, log_enabled, Level};
|
||||
|
||||
init_logger();
|
||||
|
||||
debug!("this is a debug {}", "message");
|
||||
error!("this is printed by default");
|
||||
|
||||
if log_enabled!(Level::Info) {
|
||||
let x = dbg!(3 * 4);
|
||||
// expensive computation
|
||||
info!("the answer was: {}", x);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue