From 341b94bbcd2bc8ff7b8021092e65ffb6ce23f273 Mon Sep 17 00:00:00 2001 From: Ziyang Hu Date: Wed, 11 May 2022 14:23:42 +0800 Subject: [PATCH] clippy happy --- cozorocks/build.rs | 2 +- cozorocks/src/bridge.rs | 283 +++++++----- cozorocks/src/lib.rs | 168 ++++--- src/db.rs | 12 +- src/db/cnf_transform.rs | 96 ++-- src/db/ddl.rs | 190 +++++--- src/db/engine.rs | 79 ++-- src/db/env.rs | 64 ++- src/db/eval.rs | 793 ++++++++++++++++++++-------------- src/db/iterator.rs | 420 +++++++++--------- src/db/mutation.rs | 121 ++++-- src/db/plan.rs | 60 ++- src/db/query.rs | 130 ++++-- src/db/table.rs | 163 ++++--- src/error.rs | 74 ++-- src/lib.rs | 4 +- src/parser.rs | 107 ++++- src/parser/text_identifier.rs | 21 +- src/relation.rs | 8 +- src/relation/data.rs | 12 +- src/relation/key_order.rs | 17 +- src/relation/table.rs | 15 +- src/relation/tuple.rs | 158 ++++--- src/relation/typing.rs | 131 +++--- src/relation/value.rs | 343 +++++++++------ 25 files changed, 2170 insertions(+), 1301 deletions(-) diff --git a/cozorocks/build.rs b/cozorocks/build.rs index 4d0cbe84..e7880a24 100644 --- a/cozorocks/build.rs +++ b/cozorocks/build.rs @@ -26,4 +26,4 @@ fn main() { println!("cargo:rerun-if-changed=src/bridge.rs"); println!("cargo:rerun-if-changed=bridge/cozorocks.cc"); println!("cargo:rerun-if-changed=bridge/cozorocks.h"); -} \ No newline at end of file +} diff --git a/cozorocks/src/bridge.rs b/cozorocks/src/bridge.rs index a6db265f..ad0d0aab 100644 --- a/cozorocks/src/bridge.rs +++ b/cozorocks/src/bridge.rs @@ -104,7 +104,9 @@ mod ffi { fn new_transaction_options() -> UniquePtr; fn set_deadlock_detect(o: Pin<&mut TransactionOptions>, v: bool); type OptimisticTransactionOptions; - fn new_optimistic_transaction_options(cmp: &RustComparator) -> UniquePtr; + fn new_optimistic_transaction_options( + cmp: &RustComparator, + ) -> UniquePtr; type TransactionDBOptions; fn new_tdb_options() -> UniquePtr; type OptimisticTransactionDBOptions; @@ -116,7 +118,11 @@ mod ffi { fn set_allow_write_stall(o: Pin<&mut FlushOptions>, v: bool); type RustComparator; - fn new_rust_comparator(name: &str, cmp: fn(&[u8], &[u8]) -> i8, diff_bytes_can_equal: bool) -> UniquePtr; + fn new_rust_comparator( + name: &str, + cmp: fn(&[u8], &[u8]) -> i8, + diff_bytes_can_equal: bool, + ) -> UniquePtr; pub type IteratorBridge; fn seek_to_first(self: &IteratorBridge); @@ -136,26 +142,76 @@ mod ffi { fn set_savepoint(self: &TransactionBridge); fn rollback_to_savepoint(self: &TransactionBridge, status: &mut BridgeStatus); fn pop_savepoint(self: &TransactionBridge, status: &mut BridgeStatus); - fn get_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8], - status: &mut BridgeStatus) -> SharedPtr; - fn get_for_update_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8], - status: &mut BridgeStatus) -> SharedPtr; - fn get_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8], - status: &mut BridgeStatus) -> SharedPtr; - fn put_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8], val: &[u8], - status: &mut BridgeStatus); - fn put_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8], val: &[u8], - status: &mut BridgeStatus); - fn del_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8], - status: &mut BridgeStatus); - fn del_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, key: &[u8], - status: &mut BridgeStatus); - fn del_range_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, - start_key: &[u8], end_key: &[u8], status: &mut BridgeStatus); - fn flush_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, options: &FlushOptions, status: &mut BridgeStatus); - fn compact_all_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, status: &mut BridgeStatus); - fn iterator_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle) -> UniquePtr; - fn iterator_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle) -> UniquePtr; + fn get_txn( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + key: &[u8], + status: &mut BridgeStatus, + ) -> SharedPtr; + fn get_for_update_txn( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + key: &[u8], + status: &mut BridgeStatus, + ) -> SharedPtr; + fn get_raw( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + key: &[u8], + status: &mut BridgeStatus, + ) -> SharedPtr; + fn put_txn( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + key: &[u8], + val: &[u8], + status: &mut BridgeStatus, + ); + fn put_raw( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + key: &[u8], + val: &[u8], + status: &mut BridgeStatus, + ); + fn del_txn( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + key: &[u8], + status: &mut BridgeStatus, + ); + fn del_raw( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + key: &[u8], + status: &mut BridgeStatus, + ); + fn del_range_raw( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + start_key: &[u8], + end_key: &[u8], + status: &mut BridgeStatus, + ); + fn flush_raw( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + options: &FlushOptions, + status: &mut BridgeStatus, + ); + fn compact_all_raw( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + status: &mut BridgeStatus, + ); + fn iterator_txn( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + ) -> UniquePtr; + fn iterator_raw( + self: &TransactionBridge, + cf: &ColumnFamilyHandle, + ) -> UniquePtr; // fn multiget_txn(self: &TransactionBridge, cf: &ColumnFamilyHandle, // keys: &[&[u8]], statuses: &mut [BridgeStatus]) -> UniquePtr>; // fn multiget_raw(self: &TransactionBridge, cf: &ColumnFamilyHandle, @@ -164,109 +220,138 @@ mod ffi { pub type ColumnFamilyHandle; type TDBBridge; - fn begin_t_transaction(self: &TDBBridge, - w_ops: UniquePtr, - raw_w_ops: UniquePtr, - r_ops: UniquePtr, - raw_r_ops: UniquePtr, - txn_options: UniquePtr) -> UniquePtr; - fn begin_o_transaction(self: &TDBBridge, - w_ops: UniquePtr, - raw_w_ops: UniquePtr, - r_ops: UniquePtr, - raw_r_ops: UniquePtr, - txn_options: UniquePtr) -> UniquePtr; + fn begin_t_transaction( + self: &TDBBridge, + w_ops: UniquePtr, + raw_w_ops: UniquePtr, + r_ops: UniquePtr, + raw_r_ops: UniquePtr, + txn_options: UniquePtr, + ) -> UniquePtr; + fn begin_o_transaction( + self: &TDBBridge, + w_ops: UniquePtr, + raw_w_ops: UniquePtr, + r_ops: UniquePtr, + raw_r_ops: UniquePtr, + txn_options: UniquePtr, + ) -> UniquePtr; fn get_cf_handle_raw(self: &TDBBridge, name: &CxxString) -> SharedPtr; fn get_default_cf_handle_raw(self: &TDBBridge) -> SharedPtr; - fn create_column_family_raw(self: &TDBBridge, options: &Options, name: &CxxString, status: &mut BridgeStatus) -> SharedPtr; + fn create_column_family_raw( + self: &TDBBridge, + options: &Options, + name: &CxxString, + status: &mut BridgeStatus, + ) -> SharedPtr; fn drop_column_family_raw(self: &TDBBridge, name: &CxxString, status: &mut BridgeStatus); fn get_column_family_names_raw(self: &TDBBridge) -> UniquePtr>; - fn open_tdb_raw(options: &Options, - txn_options: &TransactionDBOptions, - path: &CxxString, - status: &mut BridgeStatus) -> UniquePtr; - fn open_odb_raw(options: &Options, - txn_options: &OptimisticTransactionDBOptions, - path: &CxxString, - status: &mut BridgeStatus) -> UniquePtr; + fn open_tdb_raw( + options: &Options, + txn_options: &TransactionDBOptions, + path: &CxxString, + status: &mut BridgeStatus, + ) -> UniquePtr; + fn open_odb_raw( + options: &Options, + txn_options: &OptimisticTransactionDBOptions, + path: &CxxString, + status: &mut BridgeStatus, + ) -> UniquePtr; } } pub use ffi::*; use std::fmt::Formatter; - impl std::fmt::Display for StatusBridgeCode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match *self { - StatusBridgeCode::OK => "Ok", - StatusBridgeCode::LOCK_ERROR => "LockError", - StatusBridgeCode::EXISTING_ERROR => "ExistingError", - StatusBridgeCode::NOT_FOUND_ERROR => "NotFoundError", - _ => "Unknown" - }) + write!( + f, + "{}", + match *self { + StatusBridgeCode::OK => "Ok", + StatusBridgeCode::LOCK_ERROR => "LockError", + StatusBridgeCode::EXISTING_ERROR => "ExistingError", + StatusBridgeCode::NOT_FOUND_ERROR => "NotFoundError", + _ => "Unknown", + } + ) } } impl std::fmt::Display for StatusCode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match *self { - StatusCode::kOk => "Ok", - StatusCode::kNotFound => "NotFound", - StatusCode::kCorruption => "Corruption", - StatusCode::kNotSupported => "NotSupported", - StatusCode::kInvalidArgument => "InvalidArgument", - StatusCode::kIOError => "IoError", - StatusCode::kMergeInProgress => "MergeInProgress", - StatusCode::kIncomplete => "Incomplete", - StatusCode::kShutdownInProgress => "ShutdownInProgress", - StatusCode::kTimedOut => "TimedOut", - StatusCode::kAborted => "Aborted", - StatusCode::kBusy => "Busy", - StatusCode::kExpired => "Expired", - StatusCode::kTryAgain => "TryAgain", - StatusCode::kCompactionTooLarge => "CompactionTooLarge", - StatusCode::kColumnFamilyDropped => "ColumnFamilyDropped", - StatusCode::kMaxCode => "MaxCode", - _ => "Unknown" - }) + write!( + f, + "{}", + match *self { + StatusCode::kOk => "Ok", + StatusCode::kNotFound => "NotFound", + StatusCode::kCorruption => "Corruption", + StatusCode::kNotSupported => "NotSupported", + StatusCode::kInvalidArgument => "InvalidArgument", + StatusCode::kIOError => "IoError", + StatusCode::kMergeInProgress => "MergeInProgress", + StatusCode::kIncomplete => "Incomplete", + StatusCode::kShutdownInProgress => "ShutdownInProgress", + StatusCode::kTimedOut => "TimedOut", + StatusCode::kAborted => "Aborted", + StatusCode::kBusy => "Busy", + StatusCode::kExpired => "Expired", + StatusCode::kTryAgain => "TryAgain", + StatusCode::kCompactionTooLarge => "CompactionTooLarge", + StatusCode::kColumnFamilyDropped => "ColumnFamilyDropped", + StatusCode::kMaxCode => "MaxCode", + _ => "Unknown", + } + ) } } impl std::fmt::Display for StatusSubCode { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match *self { - StatusSubCode::kNone => "None", - StatusSubCode::kMutexTimeout => "MutexTimeout", - StatusSubCode::kLockTimeout => "LockTimeout", - StatusSubCode::kLockLimit => "LockLimit", - StatusSubCode::kNoSpace => "NoSpace", - StatusSubCode::kDeadlock => "DeadLock", - StatusSubCode::kStaleFile => "StaleFile", - StatusSubCode::kMemoryLimit => "MemoryLimit", - StatusSubCode::kSpaceLimit => "SpaceLimit", - StatusSubCode::kPathNotFound => "PathNotFound", - StatusSubCode::KMergeOperandsInsufficientCapacity => "MergeOperandsInsufficientCapacity", - StatusSubCode::kManualCompactionPaused => "ManualCompactionPaused", - StatusSubCode::kOverwritten => "Overwritten", - StatusSubCode::kTxnNotPrepared => "TxnNotPrepared", - StatusSubCode::kIOFenced => "IoFenced", - StatusSubCode::kMaxSubCode => "MaxSubCode", - _ => "Unknown" - }) + write!( + f, + "{}", + match *self { + StatusSubCode::kNone => "None", + StatusSubCode::kMutexTimeout => "MutexTimeout", + StatusSubCode::kLockTimeout => "LockTimeout", + StatusSubCode::kLockLimit => "LockLimit", + StatusSubCode::kNoSpace => "NoSpace", + StatusSubCode::kDeadlock => "DeadLock", + StatusSubCode::kStaleFile => "StaleFile", + StatusSubCode::kMemoryLimit => "MemoryLimit", + StatusSubCode::kSpaceLimit => "SpaceLimit", + StatusSubCode::kPathNotFound => "PathNotFound", + StatusSubCode::KMergeOperandsInsufficientCapacity => + "MergeOperandsInsufficientCapacity", + StatusSubCode::kManualCompactionPaused => "ManualCompactionPaused", + StatusSubCode::kOverwritten => "Overwritten", + StatusSubCode::kTxnNotPrepared => "TxnNotPrepared", + StatusSubCode::kIOFenced => "IoFenced", + StatusSubCode::kMaxSubCode => "MaxSubCode", + _ => "Unknown", + } + ) } } impl std::fmt::Display for StatusSeverity { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match *self { - StatusSeverity::kNoError => "NoError", - StatusSeverity::kSoftError => "SoftError", - StatusSeverity::kHardError => "HardError", - StatusSeverity::kFatalError => "FatalError", - StatusSeverity::kUnrecoverableError => "UnrecoverableError", - StatusSeverity::kMaxSeverity => "MaxSeverity", - _ => "Unknown" - }) + write!( + f, + "{}", + match *self { + StatusSeverity::kNoError => "NoError", + StatusSeverity::kSoftError => "SoftError", + StatusSeverity::kHardError => "HardError", + StatusSeverity::kFatalError => "FatalError", + StatusSeverity::kUnrecoverableError => "UnrecoverableError", + StatusSeverity::kMaxSeverity => "MaxSeverity", + _ => "Unknown", + } + ) } } diff --git a/cozorocks/src/lib.rs b/cozorocks/src/lib.rs index d88000bd..2a76ed13 100644 --- a/cozorocks/src/lib.rs +++ b/cozorocks/src/lib.rs @@ -2,25 +2,28 @@ mod bridge; use bridge::*; -use std::fmt::{Display, Formatter}; -use std::fmt::Debug; -use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; -use cxx::{let_cxx_string}; -pub use cxx::{UniquePtr, SharedPtr}; pub use bridge::BridgeStatus; +pub use bridge::ColumnFamilyHandle; +pub use bridge::PinnableSlice; +pub use bridge::Slice; pub use bridge::StatusBridgeCode; pub use bridge::StatusCode; -pub use bridge::StatusSubCode; pub use bridge::StatusSeverity; -pub use bridge::Slice; -pub use bridge::PinnableSlice; -pub use bridge::ColumnFamilyHandle; - +pub use bridge::StatusSubCode; +use cxx::let_cxx_string; +pub use cxx::{SharedPtr, UniquePtr}; +use std::fmt::Debug; +use std::fmt::{Display, Formatter}; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; impl std::fmt::Display for BridgeStatus { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "BridgeStatus({}, {}, {}, {})", self.code, self.subcode, self.severity, self.bridge_code) + write!( + f, + "BridgeStatus({}, {}, {}, {})", + self.code, self.subcode, self.severity, self.bridge_code + ) } } @@ -31,7 +34,11 @@ pub struct BridgeError { impl Display for BridgeError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "BridgeError({}, {}, {}, {})", self.status.code, self.status.subcode, self.status.severity, self.status.bridge_code) + write!( + f, + "BridgeError({}, {}, {}, {})", + self.status.code, self.status.subcode, self.status.severity, self.status.bridge_code + ) } } @@ -55,7 +62,7 @@ impl BridgeStatus { let err: Option = self.into(); match err { Some(e) => Err(e), - None => Ok(data) + None => Ok(data), } } } @@ -63,9 +70,10 @@ impl BridgeStatus { impl From for Option { #[inline] fn from(s: BridgeStatus) -> Self { - if s.severity == StatusSeverity::kNoError && - s.bridge_code == StatusBridgeCode::OK && - s.code == StatusCode::kOk { + if s.severity == StatusSeverity::kNoError + && s.bridge_code == StatusBridgeCode::OK + && s.code == StatusCode::kOk + { None } else { Some(BridgeError { status: s }) @@ -85,12 +93,8 @@ impl AsRef<[u8]> for SlicePtr { #[inline] fn as_ref(&self) -> &[u8] { match self { - SlicePtr::Plain(s) => { - convert_slice_back(s) - } - SlicePtr::Pinnable(s) => { - convert_pinnable_slice_back(s) - } + SlicePtr::Plain(s) => convert_slice_back(s), + SlicePtr::Pinnable(s) => convert_pinnable_slice_back(s), } } } @@ -183,7 +187,6 @@ impl OptionsPtr { } } - pub struct ReadOptionsPtr(UniquePtr); impl Deref for ReadOptionsPtr { @@ -202,7 +205,6 @@ impl DerefMut for ReadOptionsPtr { } } - impl ReadOptionsPtr { #[inline] pub fn default() -> Self { @@ -457,8 +459,10 @@ impl<'a> IteratorPtr<'a> { /// `next()` must not be called on the iterator when the returned value is still used pub unsafe fn pair(&self) -> Option<(SlicePtr, SlicePtr)> { if self.is_valid() { - Some((SlicePtr::Plain(IteratorBridge::key_raw(self)), - SlicePtr::Plain(IteratorBridge::value_raw(self)))) + Some(( + SlicePtr::Plain(IteratorBridge::key_raw(self)), + SlicePtr::Plain(IteratorBridge::value_raw(self)), + )) } else { None } @@ -479,7 +483,6 @@ impl Deref for TransactionPtr { } } - impl TransactionPtr { #[inline] pub fn null() -> Self { @@ -518,7 +521,12 @@ impl TransactionPtr { status.check_err(()) } #[inline] - pub fn get(&self, transact: bool, cf: &ColumnFamilyHandle, key: impl AsRef<[u8]>) -> Result> { + pub fn get( + &self, + transact: bool, + cf: &ColumnFamilyHandle, + key: impl AsRef<[u8]>, + ) -> Result> { let mut status = BridgeStatus::default(); let res = if transact { let ret = self.get_txn(cf, key.as_ref(), &mut status); @@ -529,18 +537,27 @@ impl TransactionPtr { }; match res { Ok(r) => Ok(Some(r)), - Err(e) if e.status.code == StatusCode::kNotFound => Ok(None), - res => res.map(|_| None) + Err(e) if e.status.code == StatusCode::kNotFound => Ok(None), + res => res.map(|_| None), } } #[inline] - pub fn get_for_update(&self, cf: &ColumnFamilyHandle, key: impl AsRef<[u8]>) -> Result { + pub fn get_for_update( + &self, + cf: &ColumnFamilyHandle, + key: impl AsRef<[u8]>, + ) -> Result { let mut status = BridgeStatus::default(); let ret = self.get_for_update_txn(cf, key.as_ref(), &mut status); status.check_err(SlicePtr::Pinnable(ret)) } #[inline] - pub fn del(&self, transact: bool, cf: &ColumnFamilyHandle, key: impl AsRef<[u8]>) -> Result<()> { + pub fn del( + &self, + transact: bool, + cf: &ColumnFamilyHandle, + key: impl AsRef<[u8]>, + ) -> Result<()> { let mut status = BridgeStatus::default(); if transact { let ret = self.del_txn(cf, key.as_ref(), &mut status); @@ -551,7 +568,12 @@ impl TransactionPtr { } } #[inline] - pub fn del_range(&self, cf: &ColumnFamilyHandle, start_key: impl AsRef<[u8]>, end_key: impl AsRef<[u8]>) -> Result<()> { + pub fn del_range( + &self, + cf: &ColumnFamilyHandle, + start_key: impl AsRef<[u8]>, + end_key: impl AsRef<[u8]>, + ) -> Result<()> { let mut status = BridgeStatus::default(); let ret = self.del_range_raw(cf, start_key.as_ref(), end_key.as_ref(), &mut status); status.check_err(ret) @@ -569,7 +591,13 @@ impl TransactionPtr { status.check_err(()) } #[inline] - pub fn put(&self, transact: bool, cf: &ColumnFamilyHandle, key: impl AsRef<[u8]>, val: impl AsRef<[u8]>) -> Result<()> { + pub fn put( + &self, + transact: bool, + cf: &ColumnFamilyHandle, + key: impl AsRef<[u8]>, + val: impl AsRef<[u8]>, + ) -> Result<()> { let mut status = BridgeStatus::default(); if transact { let ret = self.put_txn(cf, key.as_ref(), val.as_ref(), &mut status); @@ -584,12 +612,12 @@ impl TransactionPtr { if transact { IteratorPtr { inner: self.iterator_txn(cf), - txn: PhantomData + txn: PhantomData, } } else { IteratorPtr { inner: self.iterator_raw(cf), - txn: PhantomData + txn: PhantomData, } } } @@ -621,43 +649,44 @@ pub enum TDBOptions { } impl DBPtr { - pub fn open(options: &OptionsPtr, t_options: &TDBOptions, path: impl AsRef) -> Result { + pub fn open( + options: &OptionsPtr, + t_options: &TDBOptions, + path: impl AsRef, + ) -> Result { let_cxx_string!(cname = path.as_ref()); let mut status = BridgeStatus::default(); let ret = match t_options { TDBOptions::Pessimistic(o) => open_tdb_raw(options, o, &cname, &mut status), - TDBOptions::Optimistic(o) => open_odb_raw(options, o, &cname, &mut status) + TDBOptions::Optimistic(o) => open_odb_raw(options, o, &cname, &mut status), }; status.check_err(Self(ret)) } #[inline] - pub fn make_transaction(&self, - options: TransactOptions, - read_ops: ReadOptionsPtr, - raw_read_ops: ReadOptionsPtr, - write_ops: WriteOptionsPtr, - raw_write_ops: WriteOptionsPtr, + pub fn make_transaction( + &self, + options: TransactOptions, + read_ops: ReadOptionsPtr, + raw_read_ops: ReadOptionsPtr, + write_ops: WriteOptionsPtr, + raw_write_ops: WriteOptionsPtr, ) -> TransactionPtr { TransactionPtr(match options { - TransactOptions::Optimistic(o) => { - self.begin_o_transaction( - write_ops.0, - raw_write_ops.0, - read_ops.0, - raw_read_ops.0, - o.0, - ) - } - TransactOptions::Pessimistic(o) => { - self.begin_t_transaction( - write_ops.0, - raw_write_ops.0, - read_ops.0, - raw_read_ops.0, - o.0, - ) - } + TransactOptions::Optimistic(o) => self.begin_o_transaction( + write_ops.0, + raw_write_ops.0, + read_ops.0, + raw_read_ops.0, + o.0, + ), + TransactOptions::Pessimistic(o) => self.begin_t_transaction( + write_ops.0, + raw_write_ops.0, + read_ops.0, + raw_read_ops.0, + o.0, + ), }) } #[inline] @@ -675,7 +704,11 @@ impl DBPtr { self.get_default_cf_handle_raw() } #[inline] - pub fn create_cf(&self, options: &OptionsPtr, name: impl AsRef) -> Result> { + pub fn create_cf( + &self, + options: &OptionsPtr, + name: impl AsRef, + ) -> Result> { let_cxx_string!(name = name.as_ref()); let mut status = BridgeStatus::default(); let ret = self.create_column_family_raw(options, &name, &mut status); @@ -690,7 +723,10 @@ impl DBPtr { } #[inline] pub fn cf_names(&self) -> Vec { - self.get_column_family_names_raw().iter().map(|v| v.to_string_lossy().to_string()).collect() + self.get_column_family_names_raw() + .iter() + .map(|v| v.to_string_lossy().to_string()) + .collect() } pub fn drop_non_default_cfs(&self) { for name in self.cf_names() { @@ -699,4 +735,4 @@ impl DBPtr { } } } -} \ No newline at end of file +} diff --git a/src/db.rs b/src/db.rs index 68de35a6..1c159322 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,10 +1,10 @@ +pub mod cnf_transform; +pub mod ddl; pub mod engine; +pub mod env; pub mod eval; -pub mod query; +pub mod iterator; pub mod mutation; -pub mod table; pub mod plan; -pub mod ddl; -pub mod env; -pub mod cnf_transform; -pub mod iterator; +pub mod query; +pub mod table; diff --git a/src/db/cnf_transform.rs b/src/db/cnf_transform.rs index b337cf8c..2fa651d7 100644 --- a/src/db/cnf_transform.rs +++ b/src/db/cnf_transform.rs @@ -1,7 +1,7 @@ -use std::collections::{BTreeSet}; use crate::db::table::TableId; use crate::relation::value; use crate::relation::value::Value; +use std::collections::BTreeSet; pub fn extract_tables(val: &Value) -> BTreeSet { let mut coll = BTreeSet::new(); @@ -11,12 +11,12 @@ pub fn extract_tables(val: &Value) -> BTreeSet { fn do_extract_tables(val: &Value, coll: &mut BTreeSet) { match val { - Value::Null | - Value::Bool(_) | - Value::Int(_) | - Value::Float(_) | - Value::Uuid(_) | - Value::Text(_) => {} + Value::Null + | Value::Bool(_) + | Value::Int(_) + | Value::Float(_) + | Value::Uuid(_) + | Value::Text(_) => {} Value::List(l) => { for v in l { do_extract_tables(v, coll); @@ -59,7 +59,7 @@ fn do_cnf_transform(val: Value) -> (bool, Value) { value::OP_OR => cnf_transform_or(args), value::OP_AND => cnf_transform_and(args), value::OP_NEGATE => cnf_transform_negate(args.into_iter().next().unwrap()), - _ => (false, Value::Apply(op, args)) + _ => (false, Value::Apply(op, args)), } } else { (false, val) @@ -87,18 +87,21 @@ fn cnf_transform_or(args: Vec) -> (bool, Value) { collected.push(Value::Apply(op, args)) } } - _ => collected.push(Value::Apply(op, args)) + _ => collected.push(Value::Apply(op, args)), } } else { collected.push(v); } } if let Some(to_and) = to_and { - let args = to_and.into_iter().map(|v| { - let mut to_or = collected.clone(); - to_or.push(v); - Value::Apply(value::OP_OR.into(), to_or) - }).collect(); + let args = to_and + .into_iter() + .map(|v| { + let mut to_or = collected.clone(); + to_or.push(v); + Value::Apply(value::OP_OR.into(), to_or) + }) + .collect(); (true, Value::Apply(value::OP_AND.into(), args)) } else if collected.is_empty() { (true, true.into()) @@ -151,35 +154,66 @@ fn cnf_transform_negate(arg: Value) -> (bool, Value) { new_args.push(v); } match op.as_ref() { - value::OP_OR => (true, Value::Apply(value::OP_AND.into(), new_args.into_iter().map(|v| { - let (_, v) = do_cnf_transform(v); - Value::Apply(value::OP_NEGATE.into(), vec![v]) - }).collect())), - value::OP_AND => (true, Value::Apply(value::OP_OR.into(), new_args.into_iter().map(|v| { - let (_, v) = do_cnf_transform(v); - Value::Apply(value::OP_NEGATE.into(), vec![v]) - }).collect())), - value::OP_NEGATE => { - (true, new_args.into_iter().next().unwrap()) - } - _ => (changed, Value::Apply(value::OP_NEGATE.into(), vec![Value::Apply(op, new_args)])) + value::OP_OR => ( + true, + Value::Apply( + value::OP_AND.into(), + new_args + .into_iter() + .map(|v| { + let (_, v) = do_cnf_transform(v); + Value::Apply(value::OP_NEGATE.into(), vec![v]) + }) + .collect(), + ), + ), + value::OP_AND => ( + true, + Value::Apply( + value::OP_OR.into(), + new_args + .into_iter() + .map(|v| { + let (_, v) = do_cnf_transform(v); + Value::Apply(value::OP_NEGATE.into(), vec![v]) + }) + .collect(), + ), + ), + value::OP_NEGATE => (true, new_args.into_iter().next().unwrap()), + _ => ( + changed, + Value::Apply(value::OP_NEGATE.into(), vec![Value::Apply(op, new_args)]), + ), } } else { (false, Value::Apply(value::OP_NEGATE.into(), vec![arg])) } } - #[cfg(test)] mod tests { use crate::db::cnf_transform::cnf_transform; - use crate::relation::value::Value; use crate::error::Result; + use crate::relation::value::Value; #[test] fn test_cnf() -> Result<()> { - for s in ["a", "!a", "!!a", "!!!a", "!(b || c)", "a && (b && c)", "a && b || c", "a || b && c && d", - "a && (b || d && e)", "a && !b || c && !!d || !!!e && f", "(a || !b || !c) && (!d || e || f)", "(a || b) && c", "a || b"] { + for s in [ + "a", + "!a", + "!!a", + "!!!a", + "!(b || c)", + "a && (b && c)", + "a && b || c", + "a || b && c && d", + "a && (b || d && e)", + "a && !b || c && !!d || !!!e && f", + "(a || !b || !c) && (!d || e || f)", + "(a || b) && c", + "a || b", + ] { let v = Value::parse_str(s)?; println!("{}", v); let v2 = cnf_transform(v); @@ -188,4 +222,4 @@ mod tests { Ok(()) } -} \ No newline at end of file +} diff --git a/src/db/ddl.rs b/src/db/ddl.rs index 8e8cd782..4c34d6eb 100644 --- a/src/db/ddl.rs +++ b/src/db/ddl.rs @@ -1,76 +1,109 @@ -use std::collections::HashSet; -use pest::iterators::{Pair, Pairs}; use crate::db::engine::Session; use crate::db::table::TableId; -use crate::relation::tuple::{OwnTuple, SliceTuple, Tuple}; -use crate::relation::typing::Typing; -use crate::parser::Rule; use crate::error::{CozoError, Result}; use crate::parser::text_identifier::build_name_in_def; +use crate::parser::Rule; use crate::relation::data::DataKind; +use crate::relation::tuple::{OwnTuple, SliceTuple, Tuple}; +use crate::relation::typing::Typing; use crate::relation::value::Value; +use pest::iterators::{Pair, Pairs}; +use std::collections::HashSet; const STORAGE_ID_START: i64 = 10000; impl<'s> Session<'s> { pub fn encode_definable_key(&self, name: &str, in_root: bool) -> OwnTuple { - let depth_code = if in_root { 0 } else { self.get_stack_depth() as i64 }; + let depth_code = if in_root { + 0 + } else { + self.get_stack_depth() as i64 + }; let mut tuple = Tuple::with_null_prefix(); tuple.push_str(name); tuple.push_int(depth_code); tuple } fn parse_cols(&self, pair: Pair) -> Result<(Typing, Typing)> { - let col_res = pair.into_inner().map(|p| { - let mut ps = p.into_inner(); - let mut name_ps = ps.next().unwrap().into_inner(); - let is_key; - let mut name_p = name_ps.next().unwrap(); - match name_p.as_rule() { - Rule::key_marker => { - is_key = true; - name_p = name_ps.next().unwrap(); + let col_res = pair + .into_inner() + .map(|p| { + let mut ps = p.into_inner(); + let mut name_ps = ps.next().unwrap().into_inner(); + let is_key; + let mut name_p = name_ps.next().unwrap(); + match name_p.as_rule() { + Rule::key_marker => { + is_key = true; + name_p = name_ps.next().unwrap(); + } + _ => is_key = false, } - _ => { is_key = false } - } - let name = build_name_in_def(name_p, true)?; - let type_p = Typing::from_pair(ps.next().unwrap(), Some(self))?; - Ok((is_key, name, type_p)) - }).collect::>>()?; + let name = build_name_in_def(name_p, true)?; + let type_p = Typing::from_pair(ps.next().unwrap(), Some(self))?; + Ok((is_key, name, type_p)) + }) + .collect::>>()?; let all_names = col_res.iter().map(|(_, n, _)| n).collect::>(); if all_names.len() != col_res.len() { - return Err(CozoError::DuplicateNames(col_res.iter().map(|(_, n, _)| n.to_string()).collect::>())); + return Err(CozoError::DuplicateNames( + col_res + .iter() + .map(|(_, n, _)| n.to_string()) + .collect::>(), + )); } let (keys, cols): (Vec<_>, Vec<_>) = col_res.iter().partition(|(is_key, _, _)| *is_key); - let keys_typing = Typing::NamedTuple(keys.iter().map(|(_, n, t)| (n.to_string(), t.clone())).collect()); - let vals_typing = Typing::NamedTuple(cols.iter().map(|(_, n, t)| (n.to_string(), t.clone())).collect()); + let keys_typing = Typing::NamedTuple( + keys.iter() + .map(|(_, n, t)| (n.to_string(), t.clone())) + .collect(), + ); + let vals_typing = Typing::NamedTuple( + cols.iter() + .map(|(_, n, t)| (n.to_string(), t.clone())) + .collect(), + ); Ok((keys_typing, vals_typing)) } - fn parse_definition(&self, pair: Pair, in_root: bool) -> Result<(bool, (String, OwnTuple, Vec))> { + #[allow(clippy::type_complexity)] + fn parse_definition( + &self, + pair: Pair, + in_root: bool, + ) -> Result<(bool, (String, OwnTuple, Vec))> { Ok(match pair.as_rule() { Rule::node_def => (true, self.parse_node_def(pair.into_inner(), in_root)?), Rule::edge_def => (true, self.parse_edge_def(pair.into_inner(), in_root)?), Rule::associate_def => (true, self.parse_assoc_def(pair.into_inner(), in_root)?), Rule::index_def => todo!(), Rule::type_def => (false, self.parse_type_def(pair.into_inner(), in_root)?), - _ => unreachable!() + _ => unreachable!(), }) } - fn parse_assoc_def(&self, mut pairs: Pairs, in_root: bool) -> Result<(String, OwnTuple, Vec)> { + fn parse_assoc_def( + &self, + mut pairs: Pairs, + in_root: bool, + ) -> Result<(String, OwnTuple, Vec)> { let name = build_name_in_def(pairs.next().unwrap(), true)?; let src_name = build_name_in_def(pairs.next().unwrap(), true)?; let src_tbl = match self.resolve(&src_name)? { Some(res) => res, - None => return Err(CozoError::UndefinedType(src_name)) + None => return Err(CozoError::UndefinedType(src_name)), }; let (_kind, src_global, src_id) = Self::extract_table_id(src_tbl)?; if in_root && !src_global { - return Err(CozoError::LogicError("Cannot have global edge with local nodes".to_string())); + return Err(CozoError::LogicError( + "Cannot have global edge with local nodes".to_string(), + )); } let (keys_typing, vals_typing) = self.parse_cols(pairs.next().unwrap())?; if keys_typing.to_string() != "{}" { - return Err(CozoError::LogicError("Cannot have keys in assoc".to_string())); + return Err(CozoError::LogicError( + "Cannot have keys in assoc".to_string(), + )); } let mut tuple = Tuple::with_data_prefix(DataKind::Assoc); @@ -81,20 +114,32 @@ impl<'s> Session<'s> { let mut for_src = Tuple::with_prefix(0); for_src.push_null(); for_src.push_str(&src_name); - for_src.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 }); + for_src.push_int(if in_root { + 0 + } else { + self.get_stack_depth() as i64 + }); for_src.push_int(DataKind::Assoc as i64); for_src.push_str(&name); let mut for_src_i = Tuple::with_prefix(0); for_src_i.push_null(); - for_src_i.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 }); + for_src_i.push_int(if in_root { + 0 + } else { + self.get_stack_depth() as i64 + }); for_src_i.push_str(&src_name); for_src_i.push_int(DataKind::Assoc as i64); for_src_i.push_str(&name); Ok((name, tuple, vec![for_src, for_src_i])) } - fn parse_type_def(&self, mut pairs: Pairs, _in_root: bool) -> Result<(String, OwnTuple, Vec)> { + fn parse_type_def( + &self, + mut pairs: Pairs, + _in_root: bool, + ) -> Result<(String, OwnTuple, Vec)> { let name = build_name_in_def(pairs.next().unwrap(), true)?; let typ = Typing::from_pair(pairs.next().unwrap(), Some(self))?; let mut data = Tuple::with_data_prefix(DataKind::Type); @@ -102,15 +147,21 @@ impl<'s> Session<'s> { Ok((name, data, vec![])) } - fn parse_edge_def(&self, mut pairs: Pairs, in_root: bool) -> Result<(String, OwnTuple, Vec)> { + fn parse_edge_def( + &self, + mut pairs: Pairs, + in_root: bool, + ) -> Result<(String, OwnTuple, Vec)> { let src_name = build_name_in_def(pairs.next().unwrap(), true)?; let src_tbl = match self.resolve(&src_name)? { Some(res) => res, - None => return Err(CozoError::UndefinedType(src_name)) + None => return Err(CozoError::UndefinedType(src_name)), }; let (kind, src_global, src_id) = Self::extract_table_id(src_tbl)?; if in_root && !src_global { - return Err(CozoError::LogicError("Cannot have global edge with local nodes".to_string())); + return Err(CozoError::LogicError( + "Cannot have global edge with local nodes".to_string(), + )); } if kind != DataKind::Node { return Err(CozoError::UnexpectedDataKind(kind)); @@ -119,18 +170,20 @@ impl<'s> Session<'s> { let dst_name = build_name_in_def(pairs.next().unwrap(), true)?; let dst_tbl = match self.resolve(&dst_name)? { Some(res) => res, - None => return Err(CozoError::UndefinedType(dst_name)) + None => return Err(CozoError::UndefinedType(dst_name)), }; let (kind, dst_global, dst_id) = Self::extract_table_id(dst_tbl)?; if in_root && !dst_global { - return Err(CozoError::LogicError("Cannot have global edge with local nodes".to_string())); + return Err(CozoError::LogicError( + "Cannot have global edge with local nodes".to_string(), + )); } if kind != DataKind::Node { return Err(CozoError::UnexpectedDataKind(kind)); } let (keys_typing, vals_typing) = match pairs.next() { Some(p) => self.parse_cols(p)?, - None => (Typing::NamedTuple(vec![]), Typing::NamedTuple(vec![])) + None => (Typing::NamedTuple(vec![]), Typing::NamedTuple(vec![])), }; let mut tuple = Tuple::with_data_prefix(DataKind::Edge); @@ -148,7 +201,11 @@ impl<'s> Session<'s> { let mut for_src = Tuple::with_prefix(0); for_src.push_null(); for_src.push_str(&src_name); - for_src.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 }); + for_src.push_int(if in_root { + 0 + } else { + self.get_stack_depth() as i64 + }); for_src.push_int(DataKind::Edge as i64); for_src.push_str(&name); @@ -156,7 +213,11 @@ impl<'s> Session<'s> { let mut for_src_i = Tuple::with_prefix(0); for_src_i.push_null(); - for_src_i.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 }); + for_src_i.push_int(if in_root { + 0 + } else { + self.get_stack_depth() as i64 + }); for_src_i.push_str(&src_name); for_src_i.push_int(DataKind::Edge as i64); for_src_i.push_str(&name); @@ -167,7 +228,11 @@ impl<'s> Session<'s> { let mut for_dst = Tuple::with_prefix(0); for_dst.push_null(); for_dst.push_str(&dst_name); - for_dst.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 }); + for_dst.push_int(if in_root { + 0 + } else { + self.get_stack_depth() as i64 + }); for_dst.push_int(DataKind::Edge as i64); for_dst.push_str(&name); @@ -175,7 +240,11 @@ impl<'s> Session<'s> { let mut for_dst_i = Tuple::with_prefix(0); for_dst_i.push_null(); - for_dst_i.push_int(if in_root { 0 } else { self.get_stack_depth() as i64 }); + for_dst_i.push_int(if in_root { + 0 + } else { + self.get_stack_depth() as i64 + }); for_dst_i.push_str(&dst_name); for_dst_i.push_int(DataKind::Edge as i64); for_dst_i.push_str(&name); @@ -189,14 +258,20 @@ impl<'s> Session<'s> { fn extract_table_id>(src_tbl: Tuple) -> Result<(DataKind, bool, i64)> { let kind = src_tbl.data_kind()?; match kind { - DataKind::Data | DataKind::Val | DataKind::Type => return Err(CozoError::UnexpectedDataKind(kind)), + DataKind::Data | DataKind::Val | DataKind::Type => { + return Err(CozoError::UnexpectedDataKind(kind)) + } _ => {} }; let is_global = src_tbl.get_bool(0).expect("Data corrupt"); let table_id = src_tbl.get_int(1).expect("Data corrupt"); Ok((kind, is_global, table_id)) } - fn parse_node_def(&self, mut pairs: Pairs, _in_root: bool) -> Result<(String, OwnTuple, Vec)> { + fn parse_node_def( + &self, + mut pairs: Pairs, + _in_root: bool, + ) -> Result<(String, OwnTuple, Vec)> { let name = build_name_in_def(pairs.next().unwrap(), true)?; let col_pair = pairs.next().unwrap(); let (keys_typing, vals_typing) = self.parse_cols(col_pair)?; @@ -211,16 +286,14 @@ impl<'s> Session<'s> { let in_root = match pair.as_rule() { Rule::global_def => true, Rule::local_def => false, - r => panic!("Encountered definition with rule {:?}", r) + r => panic!("Encountered definition with rule {:?}", r), }; - let (need_id, (name, mut tuple, assoc_defs)) = self.parse_definition( - pair.into_inner().next().unwrap(), in_root, - )?; + let (need_id, (name, mut tuple, assoc_defs)) = + self.parse_definition(pair.into_inner().next().unwrap(), in_root)?; if need_id { let id = self.get_next_storage_id(in_root)?; - tuple = tuple.insert_values_at(0, &[in_root.into(), - id.into()]); + tuple = tuple.insert_values_at(0, &[in_root.into(), id.into()]); let mut id_key = Tuple::with_null_prefix(); id_key.push_bool(true); id_key.push_int(id); @@ -232,7 +305,6 @@ impl<'s> Session<'s> { self.define_data(&name, tuple, in_root) } - fn get_next_storage_id(&self, in_root: bool) -> Result { let mut key_entry = Tuple::with_null_prefix(); key_entry.push_null(); @@ -247,7 +319,9 @@ impl<'s> Session<'s> { } else { panic!("Unexpected value in storage id"); } - } else { STORAGE_ID_START }; + } else { + STORAGE_ID_START + }; let mut new_data = Tuple::with_null_prefix(); new_data.push_int(u + 1); if in_root { @@ -290,7 +364,9 @@ impl<'s> Session<'s> { if !cur.starts_with(&prefix) { break; } - let name = cur.get_text(4).ok_or_else(|| CozoError::LogicError("Bad data".to_string()))?; + let name = cur + .get_text(4) + .ok_or_else(|| CozoError::LogicError("Bad data".to_string()))?; if let Some(data) = self.resolve(&name)? { if data.data_kind()? == DataKind::Assoc { assocs.push((name.to_string(), data)); @@ -306,7 +382,9 @@ impl<'s> Session<'s> { if !cur.starts_with(&prefix) { break; } - let name = cur.get_text(4).ok_or_else(|| CozoError::LogicError("Bad data".to_string()))?; + let name = cur + .get_text(4) + .ok_or_else(|| CozoError::LogicError("Bad data".to_string()))?; if let Some(data) = self.resolve(&name)? { if data.data_kind()? == DataKind::Assoc { assocs.push((name.to_string(), data)); @@ -340,4 +418,4 @@ impl<'s> Session<'s> { Ok(()) } -} \ No newline at end of file +} diff --git a/src/db/engine.rs b/src/db/engine.rs index ca7300f0..11e215fe 100644 --- a/src/db/engine.rs +++ b/src/db/engine.rs @@ -1,16 +1,15 @@ // single engine per db storage // will be shared among threads - +use crate::error::CozoError::{Poisoned, SessionErr}; +use crate::error::{CozoError, Result}; +use crate::relation::tuple::{Tuple, PREFIX_LEN}; use cozorocks::*; +use rand::Rng; use std::sync::{Arc, Mutex, RwLock}; use std::time::{SystemTime, UNIX_EPOCH}; -use uuid::Uuid; use uuid::v1::{Context, Timestamp}; -use rand::Rng; -use crate::error::{CozoError, Result}; -use crate::error::CozoError::{Poisoned, SessionErr}; -use crate::relation::tuple::{PREFIX_LEN, Tuple}; +use uuid::Uuid; pub struct EngineOptions { cmp: RustComparatorPtr, @@ -37,10 +36,7 @@ impl Engine { } else { TDBOptions::Pessimistic(PTxnDBOptionsPtr::default()) }; - let cmp = RustComparatorPtr::new( - "cozo_cmp_v1", - crate::relation::key_order::compare, - false); + let cmp = RustComparatorPtr::new("cozo_cmp_v1", crate::relation::key_order::compare, false); let mut options = OptionsPtr::default(); options .set_comparator(&cmp) @@ -71,13 +67,17 @@ impl Engine { pub fn session(&self) -> Result { // find a handle if there is one available // otherwise create a new one - let mut guard = self.session_handles.lock().map_err(|_| CozoError::Poisoned)?; - let old_handle = guard.iter().find(|v| { - match v.read() { + let mut guard = self + .session_handles + .lock() + .map_err(|_| CozoError::Poisoned)?; + let old_handle = guard + .iter() + .find(|v| match v.read() { Ok(content) => content.status == SessionStatus::Completed, - Err(_) => false - } - }).cloned(); + Err(_) => false, + }) + .cloned(); let handle = match old_handle { None => { let now = SystemTime::now(); @@ -88,7 +88,17 @@ impl Engine { since_epoch.subsec_nanos(), ); let mut rng = rand::thread_rng(); - let id = Uuid::new_v1(ts, &[rng.gen(), rng.gen(), rng.gen(), rng.gen(), rng.gen(), rng.gen()])?; + let id = Uuid::new_v1( + ts, + &[ + rng.gen(), + rng.gen(), + rng.gen(), + rng.gen(), + rng.gen(), + rng.gen(), + ], + )?; let cf_ident = id.to_string(); self.db.create_cf(&self.options_store.options, &cf_ident)?; @@ -99,7 +109,7 @@ impl Engine { guard.push(ret.clone()); ret } - Some(h) => h + Some(h) => h, }; let mut sess = Session { @@ -133,12 +143,14 @@ impl<'a> Session<'a> { fn start_with_total_seek(&mut self, total_seek: bool) -> Result<()> { self.perm_cf = self.engine.db.default_cf(); assert!(!self.perm_cf.is_null()); - self.temp_cf = self.engine.db.get_cf(&self.handle.read().map_err(|_| Poisoned)?.cf_ident).ok_or(SessionErr)?; + self.temp_cf = self + .engine + .db + .get_cf(&self.handle.read().map_err(|_| Poisoned)?.cf_ident) + .ok_or(SessionErr)?; assert!(!self.temp_cf.is_null()); let t_options = match self.engine.options_store.t_options { - TDBOptions::Pessimistic(_) => { - TransactOptions::Pessimistic(PTxnOptionsPtr::default()) - } + TDBOptions::Pessimistic(_) => TransactOptions::Pessimistic(PTxnOptionsPtr::default()), TDBOptions::Optimistic(_) => { TransactOptions::Optimistic(OTxnOptionsPtr::new(&self.engine.options_store.cmp)) } @@ -167,7 +179,10 @@ impl<'a> Session<'a> { let w_opts = WriteOptionsPtr::default(); let mut wx_opts = WriteOptionsPtr::default(); wx_opts.set_disable_wal(true); - self.txn = self.engine.db.make_transaction(t_options, r_opts, rx_opts, w_opts, wx_opts); + self.txn = self + .engine + .db + .make_transaction(t_options, r_opts, rx_opts, w_opts, wx_opts); if self.txn.is_null() { panic!("Starting session failed as opening transaction failed"); } @@ -183,7 +198,8 @@ impl<'a> Session<'a> { Ok(()) } pub fn finish_work(&mut self) -> Result<()> { - self.txn.del_range(&self.temp_cf, Tuple::with_null_prefix(), Tuple::max_tuple())?; + self.txn + .del_range(&self.temp_cf, Tuple::with_null_prefix(), Tuple::max_tuple())?; self.txn.compact_all(&self.temp_cf)?; // let mut options = FlushOptionsPtr::default(); // options.set_allow_write_stall(true).set_flush_wait(true); @@ -220,9 +236,9 @@ pub enum SessionStatus { #[cfg(test)] mod tests { - use std::{fs, thread}; - use crate::relation::tuple::Tuple; use super::*; + use crate::relation::tuple::Tuple; + use std::{fs, thread}; #[test] fn push_get() { @@ -328,18 +344,23 @@ mod tests { })) } - for t in thread_handles { t.join().unwrap(); } println!("All OK"); { let handles = engine2.session_handles.lock().unwrap(); - println!("got handles {:#?}", handles.iter().map(|h| h.read().unwrap().cf_ident.to_string()).collect::>()); + println!( + "got handles {:#?}", + handles + .iter() + .map(|h| h.read().unwrap().cf_ident.to_string()) + .collect::>() + ); } } let _ = fs::remove_dir_all(p1); let _ = fs::remove_dir_all(p2); let _ = fs::remove_dir_all(p3); } -} \ No newline at end of file +} diff --git a/src/db/env.rs b/src/db/env.rs index c501680e..5b850fa7 100644 --- a/src/db/env.rs +++ b/src/db/env.rs @@ -1,8 +1,8 @@ use crate::db::engine::Session; -use crate::relation::value::Value; use crate::error::{CozoError, Result}; use crate::relation::data::{DataKind, EMPTY_DATA}; use crate::relation::tuple::{OwnTuple, SliceTuple, Tuple}; +use crate::relation::value::Value; /// # layouts for sector 0 /// @@ -13,7 +13,6 @@ use crate::relation::tuple::{OwnTuple, SliceTuple, Tuple}; /// `[Null, Int, Text, Int, Text]` inverted index for related tables /// `[True, Int]` table info, value is key - impl<'s> Session<'s> { pub fn define_variable(&mut self, name: &str, val: &Value, in_root: bool) -> Result<()> { let mut data = Tuple::with_data_prefix(DataKind::Val); @@ -36,16 +35,37 @@ impl<'s> Session<'s> { } pub fn key_exists(&self, key: &OwnTuple, in_root: bool) -> Result { - let res = self.txn.get(in_root, if in_root { &self.perm_cf } else { &self.temp_cf }, key)?; + let res = self.txn.get( + in_root, + if in_root { + &self.perm_cf + } else { + &self.temp_cf + }, + key, + )?; Ok(res.is_some()) } pub fn del_key(&self, key: &OwnTuple, in_root: bool) -> Result<()> { - self.txn.del(in_root, if in_root { &self.perm_cf } else { &self.temp_cf }, key)?; + self.txn.del( + in_root, + if in_root { + &self.perm_cf + } else { + &self.temp_cf + }, + key, + )?; Ok(()) } - pub fn define_raw_key(&self, key: &OwnTuple, value: Option<&OwnTuple>, in_root: bool) -> Result<()> { + pub fn define_raw_key( + &self, + key: &OwnTuple, + value: Option<&OwnTuple>, + in_root: bool, + ) -> Result<()> { if in_root { match value { None => { @@ -71,14 +91,14 @@ impl<'s> Session<'s> { pub fn resolve_value(&self, name: &str) -> Result> { match self.resolve(name)? { None => Ok(None), - Some(t) => { - match t.data_kind()? { - DataKind::Val => Ok(Some(t.get(0) + Some(t) => match t.data_kind()? { + DataKind::Val => Ok(Some( + t.get(0) .ok_or_else(|| CozoError::LogicError("Corrupt".to_string()))? - .to_static())), - k => Err(CozoError::UnexpectedDataKind(k)) - } - } + .to_static(), + )), + k => Err(CozoError::UnexpectedDataKind(k)), + }, } } pub fn get_stack_depth(&self) -> i32 { @@ -108,15 +128,16 @@ impl<'s> Session<'s> { ikey.push_value(&name); ikey.push_int(self.stack_depth as i64); - let data = self.txn.get(false, &self.temp_cf, &ikey)? + let data = self + .txn + .get(false, &self.temp_cf, &ikey)? .ok_or_else(|| CozoError::LogicError("Bad format for ikey".to_string()))?; let data = Tuple::new(data); match data.data_kind()? { - DataKind::Node | - DataKind::Edge | - DataKind::Assoc | - DataKind::Index => { - let id = data.get_int(1).ok_or_else(|| CozoError::LogicError("Bad table index".to_string()))?; + DataKind::Node | DataKind::Edge | DataKind::Assoc | DataKind::Index => { + let id = data.get_int(1).ok_or_else(|| { + CozoError::LogicError("Bad table index".to_string()) + })?; let mut rkey = Tuple::with_null_prefix(); rkey.push_bool(true); rkey.push_int(id); @@ -184,7 +205,10 @@ impl<'s> Session<'s> { } } let root_key = self.encode_definable_key(name, true); - let res = self.txn.get(true, &self.perm_cf, root_key).map(|v| v.map(Tuple::new))?; + let res = self + .txn + .get(true, &self.perm_cf, root_key) + .map(|v| v.map(Tuple::new))?; Ok(res) } -} \ No newline at end of file +} diff --git a/src/db/eval.rs b/src/db/eval.rs index a9696614..8855fd4f 100644 --- a/src/db/eval.rs +++ b/src/db/eval.rs @@ -1,40 +1,49 @@ -use std::borrow::Cow; -use std::cmp::{max, min, Ordering}; -use std::collections::{BTreeMap, BTreeSet}; use crate::db::cnf_transform::{cnf_transform, extract_tables}; -use crate::db::engine::{Session}; +use crate::db::engine::Session; use crate::db::plan::AccessorMap; use crate::db::table::{ColId, TableId}; -use crate::relation::value::{Value}; -use crate::error::{CozoError, Result}; use crate::error::CozoError::{InvalidArgument, LogicError}; +use crate::error::{CozoError, Result}; use crate::relation::data::DataKind; use crate::relation::table::MegaTuple; use crate::relation::value; +use crate::relation::value::Value; +use std::borrow::Cow; +use std::cmp::{max, min, Ordering}; +use std::collections::{BTreeMap, BTreeSet}; - -pub fn extract_table_ref<'a>(tuples: &'a MegaTuple, tid: &TableId, cid: &ColId) -> Result> { - let targets = if cid.is_key { &tuples.keys } else { &tuples.vals }; - let target = targets.get(tid.id as usize).ok_or_else(|| { - LogicError("Tuple ref out of bound".to_string()) - })?; +pub fn extract_table_ref<'a>( + tuples: &'a MegaTuple, + tid: &TableId, + cid: &ColId, +) -> Result> { + let targets = if cid.is_key { + &tuples.keys + } else { + &tuples.vals + }; + let target = targets + .get(tid.id as usize) + .ok_or_else(|| LogicError("Tuple ref out of bound".to_string()))?; if matches!(target.data_kind(), Ok(DataKind::Empty)) { Ok(Value::Null) } else { - target.get(cid.id as usize) + target + .get(cid.id as usize) .ok_or_else(|| LogicError("Tuple ref out of bound".to_string())) } } pub fn compare_tuple_by_keys<'a>( left: (&'a MegaTuple, &'a [(TableId, ColId)]), - right: (&'a MegaTuple, &'a [(TableId, ColId)])) -> Result { + right: (&'a MegaTuple, &'a [(TableId, ColId)]), +) -> Result { for ((l_tid, l_cid), (r_tid, r_cid)) in left.1.iter().zip(right.1) { let left_val = extract_table_ref(left.0, l_tid, l_cid)?; let right_val = extract_table_ref(right.0, r_tid, r_cid)?; match left_val.cmp(&right_val) { Ordering::Equal => {} - v => return Ok(v) + v => return Ok(v), } } Ok(Ordering::Equal) @@ -42,20 +51,23 @@ pub fn compare_tuple_by_keys<'a>( pub fn tuple_eval<'a>(value: &'a Value<'a>, tuples: &'a MegaTuple) -> Result> { let res: Value = match value { - v @ (Value::Null | - Value::Bool(_) | - Value::Int(_) | - Value::Float(_) | - Value::Uuid(_) | - Value::Text(_)) => v.clone(), + v @ (Value::Null + | Value::Bool(_) + | Value::Int(_) + | Value::Float(_) + | Value::Uuid(_) + | Value::Text(_)) => v.clone(), Value::List(l) => { - let l = l.into_iter().map(|v| tuple_eval(v, tuples)).collect::>>()?; + let l = l + .iter() + .map(|v| tuple_eval(v, tuples)) + .collect::>>()?; Value::List(l) } Value::Dict(d) => { - let d = d.into_iter() - .map(|(k, v)| - tuple_eval(v, tuples).map(|v| (k.clone(), v))) + let d = d + .iter() + .map(|(k, v)| tuple_eval(v, tuples).map(|v| (k.clone(), v))) .collect::>>()?; Value::Dict(d) } @@ -75,40 +87,38 @@ pub fn tuple_eval<'a>(value: &'a Value<'a>, tuples: &'a MegaTuple) -> Result { - match op.as_ref() { - value::OP_STR_CAT => str_cat_values(args, tuples)?, - value::OP_ADD => add_values(args, tuples)?, - value::OP_SUB => sub_values(args, tuples)?, - value::OP_MUL => mul_values(args, tuples)?, - value::OP_DIV => div_values(args, tuples)?, - value::OP_EQ => eq_values(args, tuples)?, - value::OP_NE => ne_values(args, tuples)?, - value::OP_OR => or_values(args, tuples)?, - value::OP_AND => and_values(args, tuples)?, - value::OP_MOD => mod_values(args, tuples)?, - value::OP_GT => gt_values(args, tuples)?, - value::OP_GE => ge_values(args, tuples)?, - value::OP_LT => lt_values(args, tuples)?, - value::OP_LE => le_values(args, tuples)?, - value::OP_POW => pow_values(args, tuples)?, - value::OP_COALESCE => coalesce_values(args, tuples)?, - value::OP_NEGATE => negate_values(args, tuples)?, - value::OP_MINUS => minus_values(args, tuples)?, - value::METHOD_IS_NULL => is_null_values(args, tuples)?, - value::METHOD_NOT_NULL => not_null_values(args, tuples)?, - value::METHOD_CONCAT => concat_values(args, tuples)?, - value::METHOD_MERGE => merge_values(args, tuples)?, - _ => { todo!() } + Value::Apply(op, args) => match op.as_ref() { + value::OP_STR_CAT => str_cat_values(args, tuples)?, + value::OP_ADD => add_values(args, tuples)?, + value::OP_SUB => sub_values(args, tuples)?, + value::OP_MUL => mul_values(args, tuples)?, + value::OP_DIV => div_values(args, tuples)?, + value::OP_EQ => eq_values(args, tuples)?, + value::OP_NE => ne_values(args, tuples)?, + value::OP_OR => or_values(args, tuples)?, + value::OP_AND => and_values(args, tuples)?, + value::OP_MOD => mod_values(args, tuples)?, + value::OP_GT => gt_values(args, tuples)?, + value::OP_GE => ge_values(args, tuples)?, + value::OP_LT => lt_values(args, tuples)?, + value::OP_LE => le_values(args, tuples)?, + value::OP_POW => pow_values(args, tuples)?, + value::OP_COALESCE => coalesce_values(args, tuples)?, + value::OP_NEGATE => negate_values(args, tuples)?, + value::OP_MINUS => minus_values(args, tuples)?, + value::METHOD_IS_NULL => is_null_values(args, tuples)?, + value::METHOD_NOT_NULL => not_null_values(args, tuples)?, + value::METHOD_CONCAT => concat_values(args, tuples)?, + value::METHOD_MERGE => merge_values(args, tuples)?, + _ => { + todo!() } - } + }, Value::FieldAccess(field, arg) => { let arg = tuple_eval(arg, tuples)?; match arg { - Value::Dict(mut d) => { - d.remove(field.as_ref()).unwrap_or(Value::Null) - } - _ => return Err(LogicError("Field access failed".to_string())) + Value::Dict(mut d) => d.remove(field.as_ref()).unwrap_or(Value::Null), + _ => return Err(LogicError("Field access failed".to_string())), } } Value::IdxAccess(idx, arg) => { @@ -121,7 +131,7 @@ pub fn tuple_eval<'a>(value: &'a Value<'a>, tuples: &'a MegaTuple) -> Result return Err(LogicError("Idx access failed".to_string())) + _ => return Err(LogicError("Idx access failed".to_string())), } } Value::EndSentinel => { @@ -135,13 +145,12 @@ fn coalesce_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result {} - v => return Ok(v) + v => return Ok(v), } } Ok(Value::Null) } - fn str_cat_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { let mut ret = String::new(); for v in args { @@ -149,14 +158,14 @@ fn str_cat_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result return Ok(Value::Null), Value::Text(s) => ret += s.as_ref(), - _ => return Err(InvalidArgument) + _ => return Err(InvalidArgument), } - }; + } Ok(ret.into()) } fn add_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -170,12 +179,12 @@ fn add_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result (l + (r as f64)).into(), (Value::Int(l), Value::Float(r)) => ((l as f64) + r.into_inner()).into(), (Value::Float(l), Value::Float(r)) => (l.into_inner() + r.into_inner()).into(), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } fn sub_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -189,7 +198,7 @@ fn sub_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result (l - (r as f64)).into(), (Value::Int(l), Value::Float(r)) => ((l as f64) - r.into_inner()).into(), (Value::Float(l), Value::Float(r)) => (l.into_inner() - r.into_inner()).into(), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } @@ -198,7 +207,7 @@ fn minus_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result (-l).into(), Value::Float(l) => (-l).into(), - _ => return Err(CozoError::InvalidArgument) + _ => return Err(CozoError::InvalidArgument), }) } @@ -206,7 +215,7 @@ fn negate_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result (!l).into(), - _ => return Err(CozoError::InvalidArgument) + _ => return Err(CozoError::InvalidArgument), }) } @@ -221,7 +230,7 @@ fn not_null_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -235,12 +244,12 @@ fn pow_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result ((l.into_inner()).powf(r as f64)).into(), (Value::Int(l), Value::Float(r)) => ((l as f64).powf(r.into_inner())).into(), (Value::Float(l), Value::Float(r)) => ((l.into_inner()).powf(r.into_inner())).into(), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } fn gt_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -254,12 +263,12 @@ fn gt_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result (l > (r as f64).into()).into(), (Value::Int(l), Value::Float(r)) => ((l as f64) > r.into_inner()).into(), (Value::Float(l), Value::Float(r)) => (l > r).into(), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } fn lt_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -273,12 +282,12 @@ fn lt_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result (l < (r as f64).into()).into(), (Value::Int(l), Value::Float(r)) => ((l as f64) < r.into_inner()).into(), (Value::Float(l), Value::Float(r)) => (l < r).into(), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } fn ge_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -292,12 +301,12 @@ fn ge_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result (l >= (r as f64).into()).into(), (Value::Int(l), Value::Float(r)) => ((l as f64) >= r.into_inner()).into(), (Value::Float(l), Value::Float(r)) => (l >= r).into(), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } fn le_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -311,12 +320,12 @@ fn le_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result (l <= (r as f64).into()).into(), (Value::Int(l), Value::Float(r)) => ((l as f64) <= r.into_inner()).into(), (Value::Float(l), Value::Float(r)) => (l <= r).into(), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } fn mod_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -327,12 +336,12 @@ fn mod_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result (l % r).into(), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } fn mul_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -346,12 +355,12 @@ fn mul_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result (l * (r as f64)).into(), (Value::Int(l), Value::Float(r)) => ((l as f64) * r.into_inner()).into(), (Value::Float(l), Value::Float(r)) => (l.into_inner() * r.into_inner()).into(), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } fn div_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -365,12 +374,12 @@ fn div_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result (l / (r as f64)).into(), (Value::Int(l), Value::Float(r)) => ((l as f64) / r.into_inner()).into(), (Value::Float(l), Value::Float(r)) => (l.into_inner() / r.into_inner()).into(), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } fn eq_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -383,7 +392,7 @@ fn eq_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); + let mut args = args.iter(); let left = tuple_eval(args.next().unwrap(), tuples)?; if left == Value::Null { return Ok(Value::Null); @@ -397,30 +406,30 @@ fn ne_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { let mut accum = -1; - for v in args.into_iter() { + for v in args.iter() { let v = tuple_eval(v, tuples)?; match v { Value::Null => accum = max(accum, 0), Value::Bool(false) => {} Value::Bool(true) => return Ok(true.into()), - _ => return Err(CozoError::InvalidArgument) + _ => return Err(CozoError::InvalidArgument), } } Ok(match accum { -1 => false.into(), 0 => Value::Null, - _ => unreachable!() + _ => unreachable!(), }) } fn concat_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { let mut coll = vec![]; - for v in args.into_iter() { + for v in args.iter() { let v = tuple_eval(v, tuples)?; match v { Value::Null => {} Value::List(l) => coll.extend(l), - _ => return Err(CozoError::InvalidArgument) + _ => return Err(CozoError::InvalidArgument), } } Ok(coll.into()) @@ -428,12 +437,12 @@ fn concat_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { let mut coll = BTreeMap::new(); - for v in args.into_iter() { + for v in args.iter() { let v = tuple_eval(v, tuples)?; match v { Value::Null => {} Value::Dict(d) => coll.extend(d), - _ => return Err(CozoError::InvalidArgument) + _ => return Err(CozoError::InvalidArgument), } } Ok(coll.into()) @@ -441,25 +450,29 @@ fn merge_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { let mut accum = 1; - for v in args.into_iter() { + for v in args.iter() { let v = tuple_eval(v, tuples)?; match v { Value::Null => accum = min(accum, 0), Value::Bool(true) => {} Value::Bool(false) => return Ok(false.into()), - _ => return Err(CozoError::InvalidArgument) + _ => return Err(CozoError::InvalidArgument), } } Ok(match accum { 1 => true.into(), 0 => Value::Null, - _ => unreachable!() + _ => unreachable!(), }) } impl<'s> Session<'s> { - pub fn partial_cnf_eval<'a>(&self, mut value: Value<'a>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + pub fn partial_cnf_eval<'a>( + &self, + mut value: Value<'a>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { loop { let (ev, new_v) = self.partial_eval(value.clone(), params, table_bindings)?; let new_v = cnf_transform(new_v.clone()); @@ -471,9 +484,12 @@ impl<'s> Session<'s> { } } - pub fn cnf_with_table_refs<'a>(&self, value: Value<'a>, params: &BTreeMap>, - table_bindings: &AccessorMap) - -> Result, Value<'a>>> { + pub fn cnf_with_table_refs<'a>( + &self, + value: Value<'a>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result, Value<'a>>> { let (_, value) = self.partial_cnf_eval(value, params, table_bindings)?; let conjunctives; if let Value::Apply(op, args) = value { @@ -485,51 +501,63 @@ impl<'s> Session<'s> { } else { conjunctives = vec![value] } - let grouped = conjunctives.into_iter().fold(BTreeMap::new(), |mut coll, v| { - let tids = extract_tables(&v); - let ent = coll.entry(tids).or_insert(vec![]); - ent.push(v); - coll - }).into_iter().map(|(k, mut v)| { - let v = match v.len() { - 0 => Value::Bool(true), - 1 => v.pop().unwrap(), - _ => Value::Apply(value::OP_AND.into(), v) - }; - (k, v) - }).collect::>(); + let grouped = conjunctives + .into_iter() + .fold(BTreeMap::new(), |mut coll, v| { + let tids = extract_tables(&v); + let ent = coll.entry(tids).or_insert(vec![]); + ent.push(v); + coll + }) + .into_iter() + .map(|(k, mut v)| { + let v = match v.len() { + 0 => Value::Bool(true), + 1 => v.pop().unwrap(), + _ => Value::Apply(value::OP_AND.into(), v), + }; + (k, v) + }) + .collect::>(); Ok(grouped) } - pub fn partial_eval<'a>(&self, value: Value<'a>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + pub fn partial_eval<'a>( + &self, + value: Value<'a>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { match value { - v @ (Value::Null | - Value::Bool(_) | - Value::Int(_) | - Value::Float(_) | - Value::Uuid(_) | - Value::Text(_) | - Value::EndSentinel) => Ok((true, v)), + v @ (Value::Null + | Value::Bool(_) + | Value::Int(_) + | Value::Float(_) + | Value::Uuid(_) + | Value::Text(_) + | Value::EndSentinel) => Ok((true, v)), v @ Value::TupleRef(_, _) => Ok((false, v)), Value::List(l) => { let init_vec = Vec::with_capacity(l.len()); - let res: Result<(bool, Vec)> = l.into_iter() - .try_fold((true, init_vec), |(is_evaluated, mut accum), val| { - let (ev, new_val) = self.partial_eval(val, params, table_bindings)?; - accum.push(new_val); - Ok((ev && is_evaluated, accum)) - }); + let res: Result<(bool, Vec)> = + l.into_iter() + .try_fold((true, init_vec), |(is_evaluated, mut accum), val| { + let (ev, new_val) = self.partial_eval(val, params, table_bindings)?; + accum.push(new_val); + Ok((ev && is_evaluated, accum)) + }); let (is_ev, v) = res?; Ok((is_ev, v.into())) } Value::Dict(d) => { - let res: Result<(bool, BTreeMap, Value>)> = d.into_iter() - .try_fold((true, BTreeMap::new()), |(is_evaluated, mut accum), (k, v)| { + let res: Result<(bool, BTreeMap, Value>)> = d.into_iter().try_fold( + (true, BTreeMap::new()), + |(is_evaluated, mut accum), (k, v)| { let (ev, new_val) = self.partial_eval(v, params, table_bindings)?; accum.insert(k, new_val); Ok((ev && is_evaluated, accum)) - }); + }, + ); let (is_ev, v) = res?; Ok((is_ev, v.into())) } @@ -543,9 +571,7 @@ impl<'s> Session<'s> { } else { Ok(match self.resolve_value(&v)? { None => (false, Value::Variable(v)), - Some(rs) => { - (rs.is_evaluated(), rs.to_static()) - } + Some(rs) => (rs.is_evaluated(), rs.to_static()), }) } } @@ -554,12 +580,10 @@ impl<'s> Session<'s> { if let Value::Variable(v) = &*arg { if let Some(sub_dict) = table_bindings.get(v.as_ref()) { return match sub_dict.get(field.as_ref()) { - None => { - Err(LogicError("Cannot resolve field in bound table".to_string())) - } - Some(d) => { - Ok((false, Value::TupleRef(d.0, d.1))) - } + None => Err(LogicError( + "Cannot resolve field in bound table".to_string(), + )), + Some(d) => Ok((false, Value::TupleRef(d.0, d.1))), }; } } @@ -567,25 +591,24 @@ impl<'s> Session<'s> { // normal evaluation flow let (_is_ev, arg) = self.partial_eval(*arg, params, table_bindings)?; match arg { - v @ (Value::Variable(_) | - Value::IdxAccess(_, _) | - Value::FieldAccess(_, _) | - Value::Apply(_, _)) => Ok((false, Value::FieldAccess(field, v.into()))), - Value::Dict(mut d) => { - Ok(d.remove(field.as_ref()) - .map(|v| (v.is_evaluated(), v)) - .unwrap_or((true, Value::Null))) - } - _ => Err(LogicError("Field access failed".to_string())) + v @ (Value::Variable(_) + | Value::IdxAccess(_, _) + | Value::FieldAccess(_, _) + | Value::Apply(_, _)) => Ok((false, Value::FieldAccess(field, v.into()))), + Value::Dict(mut d) => Ok(d + .remove(field.as_ref()) + .map(|v| (v.is_evaluated(), v)) + .unwrap_or((true, Value::Null))), + _ => Err(LogicError("Field access failed".to_string())), } } Value::IdxAccess(idx, arg) => { let (_is_ev, arg) = self.partial_eval(*arg, params, table_bindings)?; match arg { - v @ (Value::Variable(_) | - Value::IdxAccess(_, _) | - Value::FieldAccess(_, _) | - Value::Apply(_, _)) => Ok((false, Value::IdxAccess(idx, v.into()))), + v @ (Value::Variable(_) + | Value::IdxAccess(_, _) + | Value::FieldAccess(_, _) + | Value::Apply(_, _)) => Ok((false, Value::IdxAccess(idx, v.into()))), Value::List(mut l) => { if idx >= l.len() { Ok((true, Value::Null)) @@ -594,46 +617,54 @@ impl<'s> Session<'s> { Ok((v.is_evaluated(), v)) } } - _ => Err(LogicError("Idx access failed".to_string())) + _ => Err(LogicError("Idx access failed".to_string())), } } - Value::Apply(op, args) => { - Ok(match op.as_ref() { - value::OP_STR_CAT => self.str_cat_values_partial(args, params, table_bindings)?, - value::OP_ADD => self.add_values_partial(args, params, table_bindings)?, - value::OP_SUB => self.sub_values_partial(args, params, table_bindings)?, - value::OP_MUL => self.mul_values_partial(args, params, table_bindings)?, - value::OP_DIV => self.div_values_partial(args, params, table_bindings)?, - value::OP_EQ => self.eq_values_partial(args, params, table_bindings)?, - value::OP_NE => self.ne_values_partial(args, params, table_bindings)?, - value::OP_OR => self.or_values_partial(args, params, table_bindings)?, - value::OP_AND => self.and_values_partial(args, params, table_bindings)?, - value::OP_MOD => self.mod_values_partial(args, params, table_bindings)?, - value::OP_GT => self.gt_values_partial(args, params, table_bindings)?, - value::OP_GE => self.ge_values_partial(args, params, table_bindings)?, - value::OP_LT => self.lt_values_partial(args, params, table_bindings)?, - value::OP_LE => self.le_values_partial(args, params, table_bindings)?, - value::OP_POW => self.pow_values_partial(args, params, table_bindings)?, - value::OP_COALESCE => self.coalesce_values_partial(args, params, table_bindings)?, - value::OP_NEGATE => self.negate_values_partial(args, params, table_bindings)?, - value::OP_MINUS => self.minus_values_partial(args, params, table_bindings)?, - value::METHOD_IS_NULL => self.is_null_values_partial(args, params, table_bindings)?, - value::METHOD_NOT_NULL => self.not_null_values_partial(args, params, table_bindings)?, - value::METHOD_CONCAT => self.concat_values_partial(args, params, table_bindings)?, - value::METHOD_MERGE => self.merge_values_partial(args, params, table_bindings)?, - _ => { todo!() } - }) - } + Value::Apply(op, args) => Ok(match op.as_ref() { + value::OP_STR_CAT => self.str_cat_values_partial(args, params, table_bindings)?, + value::OP_ADD => self.add_values_partial(args, params, table_bindings)?, + value::OP_SUB => self.sub_values_partial(args, params, table_bindings)?, + value::OP_MUL => self.mul_values_partial(args, params, table_bindings)?, + value::OP_DIV => self.div_values_partial(args, params, table_bindings)?, + value::OP_EQ => self.eq_values_partial(args, params, table_bindings)?, + value::OP_NE => self.ne_values_partial(args, params, table_bindings)?, + value::OP_OR => self.or_values_partial(args, params, table_bindings)?, + value::OP_AND => self.and_values_partial(args, params, table_bindings)?, + value::OP_MOD => self.mod_values_partial(args, params, table_bindings)?, + value::OP_GT => self.gt_values_partial(args, params, table_bindings)?, + value::OP_GE => self.ge_values_partial(args, params, table_bindings)?, + value::OP_LT => self.lt_values_partial(args, params, table_bindings)?, + value::OP_LE => self.le_values_partial(args, params, table_bindings)?, + value::OP_POW => self.pow_values_partial(args, params, table_bindings)?, + value::OP_COALESCE => self.coalesce_values_partial(args, params, table_bindings)?, + value::OP_NEGATE => self.negate_values_partial(args, params, table_bindings)?, + value::OP_MINUS => self.minus_values_partial(args, params, table_bindings)?, + value::METHOD_IS_NULL => { + self.is_null_values_partial(args, params, table_bindings)? + } + value::METHOD_NOT_NULL => { + self.not_null_values_partial(args, params, table_bindings)? + } + value::METHOD_CONCAT => self.concat_values_partial(args, params, table_bindings)?, + value::METHOD_MERGE => self.merge_values_partial(args, params, table_bindings)?, + _ => { + todo!() + } + }), } } } impl<'s> Session<'s> { - fn coalesce_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn coalesce_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let res = args.into_iter().try_fold(vec![], |mut accum, cur| { match self.partial_eval(cur, params, table_bindings) { - Ok((ev, cur)) => + Ok((ev, cur)) => { if ev { if cur == Value::Null { Ok(accum) @@ -644,27 +675,32 @@ impl<'s> Session<'s> { } else { accum.push(cur); Ok(accum) - }, - Err(e) => Err(Err(e)) + } + } + Err(e) => Err(Err(e)), } }); match res { Ok(accum) => match accum.len() { 0 => Ok((true, Value::Null)), 1 => Ok((false, accum.into_iter().next().unwrap())), - _ => Ok((false, Value::Apply(value::OP_COALESCE.into(), accum))) - } + _ => Ok((false, Value::Apply(value::OP_COALESCE.into(), accum))), + }, Err(Ok(accum)) => match accum.len() { 0 => Ok((true, Value::Null)), 1 => Ok((true, accum.into_iter().next().unwrap())), - _ => Ok((false, Value::Apply(value::OP_COALESCE.into(), accum))) + _ => Ok((false, Value::Apply(value::OP_COALESCE.into(), accum))), }, - Err(Err(e)) => Err(e) + Err(Err(e)) => Err(e), } } - fn str_cat_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn str_cat_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -672,16 +708,23 @@ impl<'s> Session<'s> { return Ok((true, Value::Null)); } if !le || !re { - return Ok((false, Value::Apply(value::OP_STR_CAT.into(), vec![left, right]))); + return Ok(( + false, + Value::Apply(value::OP_STR_CAT.into(), vec![left, right]), + )); } Ok(match (left, right) { (Value::Text(l), Value::Text(r)) => (true, (l.to_string() + r.as_ref()).into()), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } - fn add_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn add_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -696,12 +739,16 @@ impl<'s> Session<'s> { (Value::Float(l), Value::Int(r)) => (true, (l + (r as f64)).into()), (Value::Int(l), Value::Float(r)) => (true, ((l as f64) + r.into_inner()).into()), (Value::Float(l), Value::Float(r)) => (true, (l.into_inner() + r.into_inner()).into()), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } - fn sub_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn sub_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -716,12 +763,16 @@ impl<'s> Session<'s> { (Value::Float(l), Value::Int(r)) => (true, (l - (r as f64)).into()), (Value::Int(l), Value::Float(r)) => (true, ((l as f64) - r.into_inner()).into()), (Value::Float(l), Value::Float(r)) => (true, (l.into_inner() - r.into_inner()).into()), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } - fn minus_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn minus_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; if left == Value::Null { @@ -733,12 +784,16 @@ impl<'s> Session<'s> { Ok(match left { Value::Int(l) => (true, (-l).into()), Value::Float(l) => (true, (-l).into()), - _ => return Err(CozoError::InvalidArgument) + _ => return Err(CozoError::InvalidArgument), }) } - fn negate_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn negate_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; if left == Value::Null { @@ -749,38 +804,56 @@ impl<'s> Session<'s> { } Ok(match left { Value::Bool(l) => (true, (!l).into()), - _ => return Err(CozoError::InvalidArgument) + _ => return Err(CozoError::InvalidArgument), }) } - fn is_null_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn is_null_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; if left == Value::Null { return Ok((true, true.into())); } if !le { - return Ok((false, Value::Apply(value::METHOD_IS_NULL.into(), vec![left]))); + return Ok(( + false, + Value::Apply(value::METHOD_IS_NULL.into(), vec![left]), + )); } Ok((true, false.into())) } - fn not_null_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn not_null_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; if left == Value::Null { return Ok((true, false.into())); } if !le { - return Ok((false, Value::Apply(value::METHOD_NOT_NULL.into(), vec![left]))); + return Ok(( + false, + Value::Apply(value::METHOD_NOT_NULL.into(), vec![left]), + )); } Ok((true, true.into())) } - fn pow_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn pow_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -794,13 +867,19 @@ impl<'s> Session<'s> { (Value::Int(l), Value::Int(r)) => (true, ((l as f64).powf(r as f64)).into()), (Value::Float(l), Value::Int(r)) => (true, ((l.into_inner()).powf(r as f64)).into()), (Value::Int(l), Value::Float(r)) => (true, ((l as f64).powf(r.into_inner())).into()), - (Value::Float(l), Value::Float(r)) => (true, ((l.into_inner()).powf(r.into_inner())).into()), - (_, _) => return Err(CozoError::InvalidArgument) + (Value::Float(l), Value::Float(r)) => { + (true, ((l.into_inner()).powf(r.into_inner())).into()) + } + (_, _) => return Err(CozoError::InvalidArgument), }) } - fn gt_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn gt_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -815,12 +894,16 @@ impl<'s> Session<'s> { (Value::Float(l), Value::Int(r)) => (true, (l > (r as f64).into()).into()), (Value::Int(l), Value::Float(r)) => (true, ((l as f64) > r.into_inner()).into()), (Value::Float(l), Value::Float(r)) => (true, (l > r).into()), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } - fn lt_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn lt_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -835,12 +918,16 @@ impl<'s> Session<'s> { (Value::Float(l), Value::Int(r)) => (true, (l < (r as f64).into()).into()), (Value::Int(l), Value::Float(r)) => (true, ((l as f64) < r.into_inner()).into()), (Value::Float(l), Value::Float(r)) => (true, (l < r).into()), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } - fn ge_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn ge_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -855,12 +942,16 @@ impl<'s> Session<'s> { (Value::Float(l), Value::Int(r)) => (true, (l >= (r as f64).into()).into()), (Value::Int(l), Value::Float(r)) => (true, ((l as f64) >= r.into_inner()).into()), (Value::Float(l), Value::Float(r)) => (true, (l >= r).into()), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } - fn le_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn le_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -875,12 +966,16 @@ impl<'s> Session<'s> { (Value::Float(l), Value::Int(r)) => (true, (l <= (r as f64).into()).into()), (Value::Int(l), Value::Float(r)) => (true, ((l as f64) <= r.into_inner()).into()), (Value::Float(l), Value::Float(r)) => (true, (l <= r).into()), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } - fn mod_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn mod_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -892,12 +987,16 @@ impl<'s> Session<'s> { } Ok(match (left, right) { (Value::Int(l), Value::Int(r)) => (true, (l % r).into()), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } - fn mul_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn mul_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -912,12 +1011,16 @@ impl<'s> Session<'s> { (Value::Float(l), Value::Int(r)) => (true, (l * (r as f64)).into()), (Value::Int(l), Value::Float(r)) => (true, ((l as f64) * r.into_inner()).into()), (Value::Float(l), Value::Float(r)) => (true, (l.into_inner() * r.into_inner()).into()), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } - fn div_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn div_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -932,12 +1035,16 @@ impl<'s> Session<'s> { (Value::Float(l), Value::Int(r)) => (true, (l / (r as f64)).into()), (Value::Int(l), Value::Float(r)) => (true, ((l as f64) / r.into_inner()).into()), (Value::Float(l), Value::Float(r)) => (true, (l.into_inner() / r.into_inner()).into()), - (_, _) => return Err(CozoError::InvalidArgument) + (_, _) => return Err(CozoError::InvalidArgument), }) } - fn eq_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn eq_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -950,8 +1057,12 @@ impl<'s> Session<'s> { Ok((true, (left == right).into())) } - fn ne_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn ne_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); let (le, left) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; let (re, right) = self.partial_eval(args.next().unwrap(), params, table_bindings)?; @@ -964,9 +1075,15 @@ impl<'s> Session<'s> { Ok((true, (left != right).into())) } - fn or_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { - let res = args.into_iter().map(|v| self.partial_eval(v, params, table_bindings)) + fn or_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { + let res = args + .into_iter() + .map(|v| self.partial_eval(v, params, table_bindings)) .try_fold( (true, false, vec![]), |(is_evaluated, has_null, mut collected), x| { @@ -974,31 +1091,32 @@ impl<'s> Session<'s> { Ok((cur_eval, cur_val)) => { if cur_eval { match cur_val { - Value::Null => { - Ok((is_evaluated, true, collected)) + Value::Null => Ok((is_evaluated, true, collected)), + Value::Bool(b) => { + if b { + Err(Ok((true, Value::Bool(true)))) // Early return on true + } else { + Ok((is_evaluated, has_null, collected)) + } } - Value::Bool(b) => if b { - Err(Ok((true, Value::Bool(true)))) // Early return on true - } else { - Ok((is_evaluated, has_null, collected)) - }, - _ => Err(Err(CozoError::InvalidArgument)) + _ => Err(Err(CozoError::InvalidArgument)), } } else { match cur_val { - Value::Null | - Value::Bool(_) | - Value::Int(_) | - Value::Float(_) | - Value::Uuid(_) | - Value::EndSentinel | - Value::Text(_) => unreachable!(), - Value::List(_) | - Value::Dict(_) => Err(Err(CozoError::InvalidArgument)), - cur_val @ (Value::Variable(_) | - Value::IdxAccess(_, _) | - Value::FieldAccess(_, _) | - Value::Apply(_, _)) => { + Value::Null + | Value::Bool(_) + | Value::Int(_) + | Value::Float(_) + | Value::Uuid(_) + | Value::EndSentinel + | Value::Text(_) => unreachable!(), + Value::List(_) | Value::Dict(_) => { + Err(Err(CozoError::InvalidArgument)) + } + cur_val @ (Value::Variable(_) + | Value::IdxAccess(_, _) + | Value::FieldAccess(_, _) + | Value::Apply(_, _)) => { collected.push(cur_val); Ok((false, has_null, collected)) } @@ -1008,9 +1126,10 @@ impl<'s> Session<'s> { } } } - Err(e) => Err(Err(e)) + Err(e) => Err(Err(e)), } - }); + }, + ); match res { Ok((is_evaluated, has_null, mut unevaluated)) => { if is_evaluated { @@ -1027,12 +1146,16 @@ impl<'s> Session<'s> { } } Err(Ok(res)) => Ok(res), - Err(Err(e)) => Err(e) + Err(Err(e)) => Err(e), } } - fn concat_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn concat_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut total_ret = vec![]; let mut cur_ret = vec![]; let mut evaluated = true; @@ -1048,10 +1171,10 @@ impl<'s> Session<'s> { cur_ret.extend(l); } } - v @ (Value::Variable(_) | - Value::Apply(_, _) | - Value::FieldAccess(_, _) | - Value::IdxAccess(_, _)) => { + v @ (Value::Variable(_) + | Value::Apply(_, _) + | Value::FieldAccess(_, _) + | Value::IdxAccess(_, _)) => { if !cur_ret.is_empty() { total_ret.push(Value::List(cur_ret)); cur_ret = vec![]; @@ -1073,8 +1196,12 @@ impl<'s> Session<'s> { } } - fn merge_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { + fn merge_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { let mut total_ret = vec![]; let mut cur_ret = BTreeMap::new(); let mut evaluated = true; @@ -1090,10 +1217,10 @@ impl<'s> Session<'s> { cur_ret.extend(d); } } - v @ (Value::Variable(_) | - Value::Apply(_, _) | - Value::FieldAccess(_, _) | - Value::IdxAccess(_, _)) => { + v @ (Value::Variable(_) + | Value::Apply(_, _) + | Value::FieldAccess(_, _) + | Value::IdxAccess(_, _)) => { if !cur_ret.is_empty() { total_ret.push(Value::Dict(cur_ret)); cur_ret = BTreeMap::new(); @@ -1115,9 +1242,15 @@ impl<'s> Session<'s> { } } - fn and_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, - table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { - let res = args.into_iter().map(|v| self.partial_eval(v, params, table_bindings)) + fn and_values_partial<'a>( + &self, + args: Vec>, + params: &BTreeMap>, + table_bindings: &AccessorMap, + ) -> Result<(bool, Value<'a>)> { + let res = args + .into_iter() + .map(|v| self.partial_eval(v, params, table_bindings)) .try_fold( (true, false, vec![]), |(is_evaluated, has_null, mut collected), x| { @@ -1125,31 +1258,32 @@ impl<'s> Session<'s> { Ok((cur_eval, cur_val)) => { if cur_eval { match cur_val { - Value::Null => { - Ok((is_evaluated, true, collected)) + Value::Null => Ok((is_evaluated, true, collected)), + Value::Bool(b) => { + if b { + Ok((is_evaluated, has_null, collected)) + } else { + Err(Ok((true, Value::Bool(false)))) // Early return on true + } } - Value::Bool(b) => if b { - Ok((is_evaluated, has_null, collected)) - } else { - Err(Ok((true, Value::Bool(false)))) // Early return on true - }, - _ => Err(Err(CozoError::InvalidArgument)) + _ => Err(Err(CozoError::InvalidArgument)), } } else { match cur_val { - Value::Null | - Value::Bool(_) | - Value::Int(_) | - Value::Float(_) | - Value::Uuid(_) | - Value::EndSentinel | - Value::Text(_) => unreachable!(), - Value::List(_) | - Value::Dict(_) => Err(Err(CozoError::InvalidArgument)), - cur_val @ (Value::Variable(_) | - Value::IdxAccess(_, _) | - Value::FieldAccess(_, _) | - Value::Apply(_, _)) => { + Value::Null + | Value::Bool(_) + | Value::Int(_) + | Value::Float(_) + | Value::Uuid(_) + | Value::EndSentinel + | Value::Text(_) => unreachable!(), + Value::List(_) | Value::Dict(_) => { + Err(Err(CozoError::InvalidArgument)) + } + cur_val @ (Value::Variable(_) + | Value::IdxAccess(_, _) + | Value::FieldAccess(_, _) + | Value::Apply(_, _)) => { collected.push(cur_val); Ok((false, has_null, collected)) } @@ -1159,9 +1293,10 @@ impl<'s> Session<'s> { } } } - Err(e) => Err(Err(e)) + Err(e) => Err(Err(e)), } - }); + }, + ); match res { Ok((is_evaluated, has_null, mut unevaluated)) => { if is_evaluated { @@ -1178,20 +1313,19 @@ impl<'s> Session<'s> { } } Err(Ok(res)) => Ok(res), - Err(Err(e)) => Err(e) + Err(Err(e)) => Err(e), } } } - #[cfg(test)] mod tests { - use std::fs; use super::*; - use crate::parser::{Parser, Rule}; - use pest::Parser as PestParser; use crate::db::engine::Engine; + use crate::parser::{Parser, Rule}; use crate::relation::tuple::Tuple; + use pest::Parser as PestParser; + use std::fs; #[test] fn node() { @@ -1262,18 +1396,37 @@ mod tests { let sess = engine.session().unwrap(); let parse_expr_from_str = |s: &str| -> (bool, Value) { - let (b, v) = sess.partial_eval( - Value::from_pair(Parser::parse(Rule::expr, s) - .unwrap().next().unwrap()).unwrap(), - &Default::default(), &Default::default()).unwrap(); + let (b, v) = sess + .partial_eval( + Value::from_pair(Parser::parse(Rule::expr, s).unwrap().next().unwrap()) + .unwrap(), + &Default::default(), + &Default::default(), + ) + .unwrap(); (b, v.to_static()) }; - assert_eq!((true, Value::from(1024.1)), parse_expr_from_str("1/10+(-2+3)*4^5")); - assert_eq!((true, Value::from(false)), parse_expr_from_str("true && false")); - assert_eq!((true, Value::from(true)), parse_expr_from_str("true || false")); - assert_eq!((true, Value::from(true)), parse_expr_from_str("true || null")); - assert_eq!((true, Value::from(true)), parse_expr_from_str("null || true")); + assert_eq!( + (true, Value::from(1024.1)), + parse_expr_from_str("1/10+(-2+3)*4^5") + ); + assert_eq!( + (true, Value::from(false)), + parse_expr_from_str("true && false") + ); + assert_eq!( + (true, Value::from(true)), + parse_expr_from_str("true || false") + ); + assert_eq!( + (true, Value::from(true)), + parse_expr_from_str("true || null") + ); + assert_eq!( + (true, Value::from(true)), + parse_expr_from_str("null || true") + ); assert_eq!((true, Value::Null), parse_expr_from_str("true && null")); let ex = parse_expr_from_str("a + b - 1*2*3*100*c * d"); println!("{:?} {}", ex.0, ex.1); diff --git a/src/db/iterator.rs b/src/db/iterator.rs index 8ab701e5..60fbf48f 100644 --- a/src/db/iterator.rs +++ b/src/db/iterator.rs @@ -1,16 +1,15 @@ -use std::cmp::Ordering; -use std::{iter, mem}; -use std::fmt::{Debug, Formatter}; -use cozorocks::IteratorPtr; use crate::db::eval::{compare_tuple_by_keys, tuple_eval}; use crate::db::table::{ColId, TableId}; use crate::error::CozoError::LogicError; -use crate::error::{Result}; +use crate::error::Result; use crate::relation::data::{DataKind, EMPTY_DATA}; use crate::relation::table::MegaTuple; use crate::relation::tuple::{CowSlice, CowTuple, OwnTuple, Tuple}; use crate::relation::value::Value; - +use cozorocks::IteratorPtr; +use std::cmp::Ordering; +use std::fmt::{Debug, Formatter}; +use std::{iter, mem}; pub enum IteratorSlot<'a> { Dummy, @@ -21,7 +20,7 @@ impl<'a> Debug for IteratorSlot<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { IteratorSlot::Dummy => write!(f, "DummyIterator"), - IteratorSlot::Reified(_) => write!(f, "BaseIterator") + IteratorSlot::Reified(_) => write!(f, "BaseIterator"), } } } @@ -36,7 +35,7 @@ impl<'a> IteratorSlot<'a> { pub fn try_get(&self) -> Result<&IteratorPtr<'a>> { match self { IteratorSlot::Dummy => Err(LogicError("Cannot iter over dummy".to_string())), - IteratorSlot::Reified(r) => Ok(r) + IteratorSlot::Reified(r) => Ok(r), } } } @@ -100,7 +99,7 @@ pub enum ExecPlan<'a> { out_prefix: u32, }, BagsUnionIt { - bags: Vec> + bags: Vec>, }, } @@ -126,120 +125,109 @@ impl<'a> ExecPlan<'a> { let prefix_tuple = OwnTuple::with_prefix(*tid); it.seek(prefix_tuple); - Ok(Box::new(NodeIterator { - it, - started: false, - })) + Ok(Box::new(NodeIterator { it, started: false })) } ExecPlan::EdgeIt { it, tid } => { let it = it.try_get()?; let prefix_tuple = OwnTuple::with_prefix(*tid); it.seek(prefix_tuple); - Ok(Box::new(EdgeIterator { - it, - started: false, - })) + Ok(Box::new(EdgeIterator { it, started: false })) } ExecPlan::EdgeKeyOnlyBwdIt { it, tid } => { let it = it.try_get()?; let prefix_tuple = OwnTuple::with_prefix(*tid); it.seek(prefix_tuple); - Ok(Box::new(EdgeKeyOnlyBwdIterator { - it, - started: false, - })) + Ok(Box::new(EdgeKeyOnlyBwdIterator { it, started: false })) } ExecPlan::KeySortedWithAssocIt { main, associates } => { let buffer = iter::repeat_with(|| None).take(associates.len()).collect(); - let associates = associates.into_iter().map(|(tid, it)| { - it.try_get().map(|it| { - let prefix_tuple = OwnTuple::with_prefix(*tid); - it.seek(prefix_tuple); - - NodeIterator { - it, - started: false, - } + let associates = associates + .iter() + .map(|(tid, it)| { + it.try_get().map(|it| { + let prefix_tuple = OwnTuple::with_prefix(*tid); + it.seek(prefix_tuple); + + NodeIterator { it, started: false } + }) }) - }).collect::>>()?; + .collect::>>()?; Ok(Box::new(KeySortedWithAssocIterator { main: main.iter()?, associates, buffer, })) } - ExecPlan::CartesianProdIt { left, right } => { - Ok(Box::new(CartesianProdIterator { - left: left.iter()?, - left_cache: MegaTuple::empty_tuple(), - right_source: right.as_ref(), - right: right.as_ref().iter()?, - })) - } - ExecPlan::FilterIt { it, filter } => { - Ok(Box::new(FilterIterator { - it: it.iter()?, - filter, - })) - } - ExecPlan::EvalIt { it, keys, vals, out_prefix: prefix } => { - Ok(Box::new(EvalIterator { - it: it.iter()?, - keys, - vals, - prefix: *prefix, - })) - } - ExecPlan::MergeJoinIt { left, right, left_keys, right_keys } => { - Ok(Box::new(MergeJoinIterator { - left: left.iter()?, - right: right.iter()?, - left_keys, - right_keys, - })) - } + ExecPlan::CartesianProdIt { left, right } => Ok(Box::new(CartesianProdIterator { + left: left.iter()?, + left_cache: MegaTuple::empty_tuple(), + right_source: right.as_ref(), + right: right.as_ref().iter()?, + })), + ExecPlan::FilterIt { it, filter } => Ok(Box::new(FilterIterator { + it: it.iter()?, + filter, + })), + ExecPlan::EvalIt { + it, + keys, + vals, + out_prefix: prefix, + } => Ok(Box::new(EvalIterator { + it: it.iter()?, + keys, + vals, + prefix: *prefix, + })), + ExecPlan::MergeJoinIt { + left, + right, + left_keys, + right_keys, + } => Ok(Box::new(MergeJoinIterator { + left: left.iter()?, + right: right.iter()?, + left_keys, + right_keys, + })), ExecPlan::OuterMergeJoinIt { - left, right, - left_keys, right_keys, left_outer, right_outer, - left_len, right_len - } => { - Ok(Box::new(OuterMergeJoinIterator { - left: left.iter()?, - right: right.iter()?, - left_outer: *left_outer, - right_outer: *right_outer, - left_keys, - right_keys, - left_len: *left_len, - right_len: *right_len, - left_cache: None, - right_cache: None, - pull_left: true, - pull_right: true, - })) - } - ExecPlan::KeyedUnionIt { left, right } => { - Ok(Box::new(KeyedUnionIterator { - left: left.iter()?, - right: right.iter()?, - })) - } - ExecPlan::KeyedDifferenceIt { left, right } => { - Ok(Box::new(KeyedDifferenceIterator { - left: left.iter()?, - right: right.iter()?, - right_cache: None, - started: false, - })) - } + left, + right, + left_keys, + right_keys, + left_outer, + right_outer, + left_len, + right_len, + } => Ok(Box::new(OuterMergeJoinIterator { + left: left.iter()?, + right: right.iter()?, + left_outer: *left_outer, + right_outer: *right_outer, + left_keys, + right_keys, + left_len: *left_len, + right_len: *right_len, + left_cache: None, + right_cache: None, + pull_left: true, + pull_right: true, + })), + ExecPlan::KeyedUnionIt { left, right } => Ok(Box::new(KeyedUnionIterator { + left: left.iter()?, + right: right.iter()?, + })), + ExecPlan::KeyedDifferenceIt { left, right } => Ok(Box::new(KeyedDifferenceIterator { + left: left.iter()?, + right: right.iter()?, + right_cache: None, + started: false, + })), ExecPlan::BagsUnionIt { bags } => { let bags = bags.iter().map(|i| i.iter()).collect::>>()?; - Ok(Box::new(BagsUnionIterator { - bags, - current: 0, - })) + Ok(Box::new(BagsUnionIterator { bags, current: 0 })) } } } @@ -257,13 +245,13 @@ impl<'a> Iterator for KeyedUnionIterator<'a> { let mut left_cache = match self.left.next() { None => return None, Some(Err(e)) => return Some(Err(e)), - Some(Ok(t)) => t + Some(Ok(t)) => t, }; let mut right_cache = match self.right.next() { None => return None, Some(Err(e)) => return Some(Err(e)), - Some(Ok(t)) => t + Some(Ok(t)) => t, }; loop { @@ -312,7 +300,7 @@ impl<'a> Iterator for KeyedDifferenceIterator<'a> { self.right_cache = match self.right.next() { None => None, Some(Err(e)) => return Some(Err(e)), - Some(Ok(t)) => Some(t) + Some(Ok(t)) => Some(t), }; self.started = true; @@ -321,17 +309,16 @@ impl<'a> Iterator for KeyedDifferenceIterator<'a> { let mut left_cache = match self.left.next() { None => return None, Some(Err(e)) => return Some(Err(e)), - Some(Ok(t)) => t + Some(Ok(t)) => t, }; - loop { let right = match &self.right_cache { None => { // right is exhausted, so all left ones can be returned return Some(Ok(left_cache)); } - Some(r) => r + Some(r) => r, }; let cmp_res = left_cache.all_keys_cmp(right); match cmp_res { @@ -340,12 +327,12 @@ impl<'a> Iterator for KeyedDifferenceIterator<'a> { left_cache = match self.left.next() { None => return None, Some(Err(e)) => return Some(Err(e)), - Some(Ok(t)) => t + Some(Ok(t)) => t, }; self.right_cache = match self.right.next() { None => None, Some(Err(e)) => return Some(Err(e)), - Some(Ok(t)) => Some(t) + Some(Ok(t)) => Some(t), }; } Ordering::Less => { @@ -386,7 +373,7 @@ impl<'a> Iterator for BagsUnionIterator<'a> { self.next() } } - v => v + v => v, } } } @@ -494,36 +481,30 @@ impl<'a> Iterator for KeySortedWithAssocIterator<'a> { fn next(&mut self) -> Option { match self.main.next() { None => None, // main exhausted, we are finished - Some(Err(e)) => return Some(Err(e)), + Some(Err(e)) => Some(Err(e)), Some(Ok(MegaTuple { mut keys, mut vals })) => { // extract key from main let k = match keys.pop() { None => return Some(Err(LogicError("Empty keys".to_string()))), - Some(k) => k + Some(k) => k, }; let l = self.associates.len(); // initialize vector for associate values let mut assoc_vals: Vec> = iter::repeat_with(|| None).take(l).collect(); - let l = assoc_vals.len(); + // let l = assoc_vals.len(); + #[allow(clippy::needless_range_loop)] for i in 0..l { // for each associate let cached = self.buffer.get(i).unwrap(); // if no cache, try to get cache filled first if matches!(cached, None) { - let assoc_data = self.associates.get_mut(i).unwrap().next() - .map(|mt| { - mt.map(|mut mt| { - (mt.keys.pop().unwrap(), mt.vals.pop().unwrap()) - }) - }); + let assoc_data = self.associates.get_mut(i).unwrap().next().map(|mt| { + mt.map(|mut mt| (mt.keys.pop().unwrap(), mt.vals.pop().unwrap())) + }); match assoc_data { - None => { - self.buffer[i] = None - } - Some(Ok(data)) => { - self.buffer[i] = Some(data) - } - Some(Err(e)) => return Some(Err(e)) + None => self.buffer[i] = None, + Some(Ok(data)) => self.buffer[i] = Some(data), + Some(Err(e)) => return Some(Err(e)), } } @@ -537,38 +518,31 @@ impl<'a> Iterator for KeySortedWithAssocIterator<'a> { Ordering::Equal => { // target key equals cache key, we put it into collected values let (_, v) = mem::replace(&mut self.buffer[i], None).unwrap(); - assoc_vals[i] = Some(v.into()); + assoc_vals[i] = Some(v); break; } Ordering::Greater => { // target key greater than cache key, meaning that the source has holes (maybe due to filtering) // get a new one into buffer - let assoc_data = self.associates.get_mut(i).unwrap().next() - .map(|mt| { + let assoc_data = + self.associates.get_mut(i).unwrap().next().map(|mt| { mt.map(|mut mt| { (mt.keys.pop().unwrap(), mt.vals.pop().unwrap()) }) }); match assoc_data { - None => { - self.buffer[i] = None - } - Some(Ok(data)) => { - self.buffer[i] = Some(data) - } - Some(Err(e)) => return Some(Err(e)) + None => self.buffer[i] = None, + Some(Ok(data)) => self.buffer[i] = Some(data), + Some(Err(e)) => return Some(Err(e)), } } } } } - vals.extend(assoc_vals.into_iter().map(|v| - match v { - None => { - CowTuple::new(CowSlice::Own(EMPTY_DATA.into())) - } - Some(v) => v - })); + vals.extend(assoc_vals.into_iter().map(|v| match v { + None => CowTuple::new(CowSlice::Own(EMPTY_DATA.into())), + Some(v) => v, + })); Some(Ok(MegaTuple { keys: vec![k], vals, @@ -601,7 +575,7 @@ impl<'a> Iterator for OuterMergeJoinIterator<'a> { self.left_cache = match self.left.next() { None => None, Some(Err(e)) => return Some(Err(e)), - Some(Ok(t)) => Some(t) + Some(Ok(t)) => Some(t), }; self.pull_left = false; } @@ -610,15 +584,23 @@ impl<'a> Iterator for OuterMergeJoinIterator<'a> { self.right_cache = match self.right.next() { None => None, Some(Err(e)) => return Some(Err(e)), - Some(Ok(t)) => Some(t) + Some(Ok(t)) => Some(t), }; self.pull_right = false; } let make_empty_tuple = |is_left: bool| -> MegaTuple { - let lengths = if is_left { self.left_len } else { self.right_len }; - let keys = iter::repeat_with(|| OwnTuple::empty_tuple().into()).take(lengths.0).collect(); - let vals = iter::repeat_with(|| OwnTuple::empty_tuple().into()).take(lengths.1).collect(); + let lengths = if is_left { + self.left_len + } else { + self.right_len + }; + let keys = iter::repeat_with(|| OwnTuple::empty_tuple().into()) + .take(lengths.0) + .collect(); + let vals = iter::repeat_with(|| OwnTuple::empty_tuple().into()) + .take(lengths.1) + .collect(); MegaTuple { keys, vals } }; @@ -640,7 +622,7 @@ impl<'a> Iterator for OuterMergeJoinIterator<'a> { } }; } - Some(t) => t + Some(t) => t, }; let right_cache = match &self.right_cache { None => { @@ -659,12 +641,14 @@ impl<'a> Iterator for OuterMergeJoinIterator<'a> { } }; } - Some(t) => t + Some(t) => t, }; - let cmp_res = match compare_tuple_by_keys((&left_cache, self.left_keys), - (&right_cache, self.right_keys)) { + let cmp_res = match compare_tuple_by_keys( + (left_cache, self.left_keys), + (right_cache, self.right_keys), + ) { Ok(r) => r, - Err(e) => return Some(Err(e)) + Err(e) => return Some(Err(e)), }; match cmp_res { Ordering::Equal => { @@ -731,20 +715,22 @@ impl<'a> Iterator for MergeJoinIterator<'a> { let mut left_cache = match self.left.next() { None => return None, Some(Err(e)) => return Some(Err(e)), - Some(Ok(t)) => t + Some(Ok(t)) => t, }; let mut right_cache = match self.right.next() { None => return None, Some(Err(e)) => return Some(Err(e)), - Some(Ok(t)) => t + Some(Ok(t)) => t, }; loop { - let cmp_res = match compare_tuple_by_keys((&left_cache, self.left_keys), - (&right_cache, self.right_keys)) { + let cmp_res = match compare_tuple_by_keys( + (&left_cache, self.left_keys), + (&right_cache, self.right_keys), + ) { Ok(r) => r, - Err(e) => return Some(Err(e)) + Err(e) => return Some(Err(e)), }; match cmp_res { Ordering::Equal => { @@ -791,29 +777,29 @@ impl<'a> Iterator for CartesianProdIterator<'a> { self.left_cache = match self.left.next() { None => return None, Some(Ok(v)) => v, - Some(Err(e)) => return Some(Err(e)) + Some(Err(e)) => return Some(Err(e)), } } let r_tpl = match self.right.next() { None => { self.right = match self.right_source.iter() { Ok(it) => it, - Err(e) => return Some(Err(e)) + Err(e) => return Some(Err(e)), }; self.left_cache = match self.left.next() { None => return None, Some(Ok(v)) => v, - Some(Err(e)) => return Some(Err(e)) + Some(Err(e)) => return Some(Err(e)), }; match self.right.next() { // early return in case right is empty None => return None, Some(Ok(r_tpl)) => r_tpl, - Some(Err(e)) => return Some(Err(e)) + Some(Err(e)) => return Some(Err(e)), } } Some(Ok(r_tpl)) => r_tpl, - Some(Err(e)) => return Some(Err(e)) + Some(Err(e)) => return Some(Err(e)), }; let mut ret = self.left_cache.clone(); ret.keys.extend(r_tpl.keys); @@ -833,17 +819,17 @@ impl<'a> Iterator for FilterIterator<'a> { fn next(&mut self) -> Option { for t in self.it.by_ref() { match t { - Ok(t) => { - match tuple_eval(self.filter, &t) { - Ok(Value::Bool(true)) => { - return Some(Ok(t)); - } - Ok(Value::Bool(false)) | Ok(Value::Null) => {} - Ok(_v) => return Some(Err(LogicError("Unexpected type in filter".to_string()))), - Err(e) => return Some(Err(e)) + Ok(t) => match tuple_eval(self.filter, &t) { + Ok(Value::Bool(true)) => { + return Some(Ok(t)); } - } - Err(e) => return Some(Err(e)) + Ok(Value::Bool(false)) | Ok(Value::Null) => {} + Ok(_v) => { + return Some(Err(LogicError("Unexpected type in filter".to_string()))); + } + Err(e) => return Some(Err(e)), + }, + Err(e) => return Some(Err(e)), } } None @@ -871,7 +857,7 @@ impl<'a> Iterator for OutputIterator<'a> { match self.it.next() { None => None, Some(Err(e)) => Some(Err(e)), - Some(Ok(t)) => Some(tuple_eval(self.transform, &t).map(|v| v.to_static())) + Some(Ok(t)) => Some(tuple_eval(self.transform, &t).map(|v| v.to_static())), } } } @@ -896,16 +882,19 @@ impl<'a> Iterator for EvalIterator<'a> { for k in self.keys { match tuple_eval(k, &t) { Ok(v) => key_tuple.push_value(&v), - Err(e) => return Some(Err(e)) + Err(e) => return Some(Err(e)), } } for k in self.vals { match tuple_eval(k, &t) { Ok(v) => val_tuple.push_value(&v), - Err(e) => return Some(Err(e)) + Err(e) => return Some(Err(e)), } } - Some(Ok(MegaTuple { keys: vec![key_tuple.into()], vals: vec![val_tuple.into()] })) + Some(Ok(MegaTuple { + keys: vec![key_tuple.into()], + vals: vec![val_tuple.into()], + })) } } } @@ -913,16 +902,16 @@ impl<'a> Iterator for EvalIterator<'a> { #[cfg(test)] mod tests { - use std::collections::BTreeMap; - use std::fs; - use std::time::Instant; use crate::db::engine::Engine; - use crate::parser::{Parser, Rule}; - use pest::Parser as PestParser; use crate::db::iterator::{ExecPlan, OutputIterator}; use crate::db::query::FromEl; - use crate::relation::value::Value; use crate::error::Result; + use crate::parser::{Parser, Rule}; + use crate::relation::value::Value; + use pest::Parser as PestParser; + use std::collections::BTreeMap; + use std::fs; + use std::time::Instant; #[test] fn pair_value() -> Result<()> { @@ -961,25 +950,46 @@ mod tests { let start2 = Instant::now(); let s = "from e:Employee"; - let p = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap(); + let p = Parser::parse(Rule::from_pattern, s) + .unwrap() + .next() + .unwrap(); let from_pat = match sess.parse_from_pattern(p).unwrap().pop().unwrap() { FromEl::Simple(s) => s, - FromEl::Chain(_) => panic!() + FromEl::Chain(_) => panic!(), }; let s = "where e.id >= 100, e.id <= 105 || e.id == 110"; - let p = Parser::parse(Rule::where_pattern, s).unwrap().next().unwrap(); + let p = Parser::parse(Rule::where_pattern, s) + .unwrap() + .next() + .unwrap(); let where_pat = sess.parse_where_pattern(p).unwrap(); let s = r#"select {id: e.id, full_name: e.first_name ++ ' ' ++ e.last_name, bibio_name: e.last_name ++ ', ' ++ e.first_name ++ ': ' ++ (e.phone_number ~ 'N.A.')}"#; - let p = Parser::parse(Rule::select_pattern, s).unwrap().next().unwrap(); + let p = Parser::parse(Rule::select_pattern, s) + .unwrap() + .next() + .unwrap(); let sel_pat = sess.parse_select_pattern(p).unwrap(); - let amap = sess.base_relation_to_accessor_map(&from_pat.table, &from_pat.binding, &from_pat.info); - let (_, vals) = sess.partial_eval(sel_pat.vals, &Default::default(), &amap).unwrap(); - let (_, where_vals) = sess.partial_eval(where_pat, &Default::default(), &amap).unwrap(); - println!("{:#?}", sess.cnf_with_table_refs(where_vals.clone(), &Default::default(), &amap)); - let (vcoll, mut rel_tbls) = Value::extract_relevant_tables([vals, where_vals].into_iter()).unwrap(); + let amap = sess.base_relation_to_accessor_map( + &from_pat.table, + &from_pat.binding, + &from_pat.info, + ); + let (_, vals) = sess + .partial_eval(sel_pat.vals, &Default::default(), &amap) + .unwrap(); + let (_, where_vals) = sess + .partial_eval(where_pat, &Default::default(), &amap) + .unwrap(); + println!( + "{:#?}", + sess.cnf_with_table_refs(where_vals.clone(), &Default::default(), &amap) + ); + let (vcoll, mut rel_tbls) = + Value::extract_relevant_tables([vals, where_vals].into_iter()).unwrap(); let mut vcoll = vcoll.into_iter(); let vals = vcoll.next().unwrap(); let where_vals = vcoll.next().unwrap(); @@ -991,7 +1001,10 @@ mod tests { let tbl = rel_tbls.pop().unwrap(); let it = sess.iter_node(tbl); - let it = ExecPlan::FilterIt { filter: where_vals, it: it.into() }; + let it = ExecPlan::FilterIt { + filter: where_vals, + it: it.into(), + }; let it = OutputIterator::new(&it, &vals)?; for val in it { println!("{}", val.unwrap()); @@ -1001,9 +1014,11 @@ mod tests { println!("Time elapsed {:?} {:?}", duration, duration2); let it = ExecPlan::KeySortedWithAssocIt { main: Box::new(sess.iter_node(tbl)), - associates: vec![(tbl.id as u32, sess.raw_iterator(true).into()), - (tbl.id as u32, sess.raw_iterator(true).into()), - (tbl.id as u32, sess.raw_iterator(true).into())], + associates: vec![ + (tbl.id as u32, sess.raw_iterator(true).into()), + (tbl.id as u32, sess.raw_iterator(true).into()), + (tbl.id as u32, sess.raw_iterator(true).into()), + ], }; { for el in it.iter()? { @@ -1033,12 +1048,23 @@ mod tests { // if n % 4096 == 0 { // println!("{}: {:?}", n, el) // } - let _x = el.keys.into_iter().map(|v| v.iter().map(|_v| ()).collect::>()).collect::>(); - let _y = el.vals.into_iter().map(|v| v.iter().map(|_v| ()).collect::>()).collect::>(); + let _x = el + .keys + .into_iter() + .map(|v| v.iter().map(|_v| ()).collect::>()) + .collect::>(); + let _y = el + .vals + .into_iter() + .map(|v| v.iter().map(|_v| ()).collect::>()) + .collect::>(); n += 1; } let duration = start.elapsed(); - println!("{} items per second", 1e9 * (n as f64) / (duration.as_nanos() as f64)); + println!( + "{} items per second", + 1e9 * (n as f64) / (duration.as_nanos() as f64) + ); // let a = sess.iter_table(tbl); // let ac = (&a).into_iter().count(); // println!("{}", ac); @@ -1047,4 +1073,4 @@ mod tests { let _ = fs::remove_dir_all(db_path); Ok(()) } -} \ No newline at end of file +} diff --git a/src/db/mutation.rs b/src/db/mutation.rs index 7b633c80..0f487d24 100644 --- a/src/db/mutation.rs +++ b/src/db/mutation.rs @@ -1,17 +1,17 @@ -use std::borrow::Cow; -use std::cell::RefCell; -use std::collections::{BTreeMap, HashSet}; -use std::rc::Rc; -use pest::iterators::Pair; use crate::db::engine::Session; use crate::db::table::TableInfo; use crate::error::CozoError::LogicError; use crate::error::{CozoError, Result}; -use crate::parser::Rule; use crate::parser::text_identifier::build_name_in_def; +use crate::parser::Rule; use crate::relation::data::DataKind; use crate::relation::tuple::Tuple; use crate::relation::value::Value; +use pest::iterators::Pair; +use std::borrow::Cow; +use std::cell::RefCell; +use std::collections::{BTreeMap, HashSet}; +use std::rc::Rc; /// # key layouts /// @@ -36,23 +36,34 @@ enum MutationKind { } impl<'a> Session<'a> { - pub fn run_mutation(&mut self, pair: Pair, params: &BTreeMap) -> Result<()> { + pub fn run_mutation( + &mut self, + pair: Pair, + params: &BTreeMap, + ) -> Result<()> { let mut pairs = pair.into_inner(); let kind = match pairs.next().unwrap().as_rule() { Rule::upsert => MutationKind::Upsert, Rule::insert => MutationKind::Insert, - _ => unreachable!() + _ => unreachable!(), }; let (evaluated, expr) = self.partial_eval( Value::from_pair(pairs.next().unwrap())?, params, - &Default::default())?; + &Default::default(), + )?; if !evaluated { - return Err(LogicError("Mutation encountered unevaluated expression".to_string())); + return Err(LogicError( + "Mutation encountered unevaluated expression".to_string(), + )); } let expr = match expr { Value::List(v) => v, - _ => return Err(LogicError("Mutation requires iterator of values".to_string())) + _ => { + return Err(LogicError( + "Mutation requires iterator of values".to_string(), + )) + } }; let mut default_kind = None; // let mut filters: Option<()> = None; @@ -60,7 +71,7 @@ impl<'a> Session<'a> { match p.as_rule() { Rule::name_in_def => default_kind = Some(build_name_in_def(p, true)?), Rule::mutation_filter => todo!(), // filters = Some(()), // TODO - _ => unreachable!() + _ => unreachable!(), } } // println!("{:?}", kind); @@ -74,7 +85,7 @@ impl<'a> Session<'a> { for item in expr { let val_map = match item { Value::Dict(d) => d, - _ => return Err(LogicError("Must be structs".to_string())) + _ => return Err(LogicError("Must be structs".to_string())), }; mutation_manager.process_insert(kind == MutationKind::Insert, val_map)?; } @@ -91,27 +102,38 @@ struct MutationManager<'a, 'b> { impl<'a, 'b> MutationManager<'a, 'b> { fn new(sess: &'a Session<'b>, default_tbl: Option) -> Self { - Self { sess, cache: RefCell::new(BTreeMap::new()), default_tbl } + Self { + sess, + cache: RefCell::new(BTreeMap::new()), + default_tbl, + } } fn get_table_info(&self, tbl_name: Cow) -> Result> { if !self.cache.borrow().contains_key(tbl_name.as_ref()) { let coercer = self.sess.get_table_info(&tbl_name)?; - self.cache.borrow_mut().insert(tbl_name.as_ref().to_string(), Rc::new(coercer)); + self.cache + .borrow_mut() + .insert(tbl_name.as_ref().to_string(), Rc::new(coercer)); } let cache = self.cache.borrow(); - let info = cache.get(tbl_name.as_ref()) + let info = cache + .get(tbl_name.as_ref()) .ok_or_else(|| CozoError::LogicError("Cannot resolve table".to_string()))?; Ok(info.clone()) } - fn process_insert(&mut self, error_on_existing: bool, mut val_map: BTreeMap, Value>) -> Result<()> { + fn process_insert( + &mut self, + error_on_existing: bool, + mut val_map: BTreeMap, Value>, + ) -> Result<()> { let tbl_name = match val_map.get("_type") { Some(Value::Text(t)) => t.clone(), Some(_) => return Err(LogicError("Table kind must be text".to_string())), None => match &self.default_tbl { Some(v) => v.clone().into(), - None => return Err(LogicError("Cannot determine table kind".to_string())) - } + None => return Err(LogicError("Cannot determine table kind".to_string())), + }, }; let table_info = self.get_table_info(tbl_name)?; @@ -132,10 +154,18 @@ impl<'a, 'b> MutationManager<'a, 'b> { let processed = v.coerce(raw)?; val_tuple.push_value(&processed); } - if error_on_existing && self.sess.key_exists(&key_tuple, table_info.table_id.in_root)? { + if error_on_existing + && self + .sess + .key_exists(&key_tuple, table_info.table_id.in_root)? + { return Err(CozoError::KeyConflict(key_tuple)); } - self.sess.define_raw_key(&key_tuple, Some(&val_tuple), table_info.table_id.in_root)?; + self.sess.define_raw_key( + &key_tuple, + Some(&val_tuple), + table_info.table_id.in_root, + )?; } DataKind::Edge => { key_tuple = Tuple::with_prefix(table_info.table_id.id as u32); @@ -149,7 +179,7 @@ impl<'a, 'b> MutationManager<'a, 'b> { let src = val_map.remove("_src").unwrap_or(Value::Null); let src_key_list = match src { Value::List(v) => v, - v => vec![v] + v => vec![v], }; if src_key_list.len() != table_info.src_key_typing.len() { @@ -158,7 +188,11 @@ impl<'a, 'b> MutationManager<'a, 'b> { let mut src_keys = Vec::with_capacity(src_key_list.len()); - for (t, v) in table_info.src_key_typing.iter().zip(src_key_list.into_iter()) { + for (t, v) in table_info + .src_key_typing + .iter() + .zip(src_key_list.into_iter()) + { let v = t.coerce(v)?; key_tuple.push_value(&v); src_keys.push(v); @@ -169,14 +203,18 @@ impl<'a, 'b> MutationManager<'a, 'b> { let dst = val_map.remove("_dst").unwrap_or(Value::Null); let dst_key_list = match dst { Value::List(v) => v, - v => vec![v] + v => vec![v], }; if dst_key_list.len() != table_info.dst_key_typing.len() { return Err(CozoError::LogicError("Error in _dst key".to_string())); } - for (t, v) in table_info.dst_key_typing.iter().zip(dst_key_list.into_iter()) { + for (t, v) in table_info + .dst_key_typing + .iter() + .zip(dst_key_list.into_iter()) + { let v = t.coerce(v)?; key_tuple.push_value(&v); ikey_tuple.push_value(&v); @@ -198,13 +236,25 @@ impl<'a, 'b> MutationManager<'a, 'b> { let processed = v.coerce(raw)?; val_tuple.push_value(&processed); } - if error_on_existing && self.sess.key_exists(&key_tuple, table_info.table_id.in_root)? { + if error_on_existing + && self + .sess + .key_exists(&key_tuple, table_info.table_id.in_root)? + { return Err(CozoError::KeyConflict(key_tuple)); } - self.sess.define_raw_key(&key_tuple, Some(&val_tuple), table_info.table_id.in_root)?; - self.sess.define_raw_key(&ikey_tuple, Some(&key_tuple), table_info.table_id.in_root)?; + self.sess.define_raw_key( + &key_tuple, + Some(&val_tuple), + table_info.table_id.in_root, + )?; + self.sess.define_raw_key( + &ikey_tuple, + Some(&key_tuple), + table_info.table_id.in_root, + )?; } - _ => unreachable!() + _ => unreachable!(), } let existing_keys: HashSet<_> = val_map.iter().map(|(k, _)| k.to_string()).collect(); @@ -218,7 +268,8 @@ impl<'a, 'b> MutationManager<'a, 'b> { val_tuple.push_value(&processed); } key_tuple.overwrite_prefix(assoc.table_id.id as u32); - self.sess.define_raw_key(&key_tuple, Some(&val_tuple), assoc.table_id.in_root)?; + self.sess + .define_raw_key(&key_tuple, Some(&val_tuple), assoc.table_id.in_root)?; } } Ok(()) @@ -227,14 +278,14 @@ impl<'a, 'b> MutationManager<'a, 'b> { #[cfg(test)] mod tests { - use std::collections::BTreeMap; - use std::fs; - use std::time::Instant; - use pest::Parser as PestParser; use crate::db::engine::Engine; use crate::parser::{Parser, Rule}; use crate::relation::tuple::Tuple; use crate::relation::value::Value; + use pest::Parser as PestParser; + use std::collections::BTreeMap; + use std::fs; + use std::time::Instant; #[test] fn test_mutation() { @@ -349,4 +400,4 @@ mod tests { drop(engine); let _ = fs::remove_dir_all(db_path); } -} \ No newline at end of file +} diff --git a/src/db/plan.rs b/src/db/plan.rs index ac3c44fa..3e0e5cde 100644 --- a/src/db/plan.rs +++ b/src/db/plan.rs @@ -1,14 +1,13 @@ -use std::collections::BTreeMap; -use pest::iterators::Pair; -use cozorocks::{IteratorPtr}; use crate::db::engine::Session; -use crate::db::iterator::{IteratorSlot, ExecPlan, OutputIt}; +use crate::db::iterator::{ExecPlan, IteratorSlot, OutputIt}; use crate::db::query::{FromEl, Selection}; use crate::db::table::{ColId, TableId, TableInfo}; -use crate::relation::value::{StaticValue, Value}; +use crate::error::Result; use crate::parser::Rule; -use crate::error::{Result}; - +use crate::relation::value::{StaticValue, Value}; +use cozorocks::IteratorPtr; +use pest::iterators::Pair; +use std::collections::BTreeMap; #[derive(Eq, PartialEq, Copy, Clone, Debug)] pub enum OuterJoinType { @@ -17,14 +16,13 @@ pub enum OuterJoinType { FullOuterJoin, } - pub type AccessorMap = BTreeMap>; impl<'a> Session<'a> { - pub fn realize_intermediate_plan(&self, plan: ExecPlan) -> ExecPlan { + pub fn realize_intermediate_plan(&self, _plan: ExecPlan) -> ExecPlan { todo!() } - pub fn realize_output_plan(&self, plan: ExecPlan) -> OutputIt { + pub fn realize_output_plan(&self, _plan: ExecPlan) -> OutputIt { todo!() } pub fn query_to_plan(&self, pair: Pair) -> Result<()> { @@ -37,7 +35,7 @@ impl<'a> Session<'a> { nxt = pairs.next().unwrap(); r } - _ => true.into() + _ => true.into(), }; let select_data = self.parse_select_pattern(nxt)?; let plan = self.convert_from_data_to_plan(from_data)?; @@ -47,9 +45,12 @@ impl<'a> Session<'a> { Ok(()) } fn convert_from_data_to_plan(&self, mut from_data: Vec) -> Result { - let res = match from_data.pop().unwrap() { + let _res = match from_data.pop().unwrap() { FromEl::Simple(el) => { - println!("{:#?}", self.base_relation_to_accessor_map(&el.table, &el.binding, &el.info)); + println!( + "{:#?}", + self.base_relation_to_accessor_map(&el.table, &el.binding, &el.info) + ); todo!() // QueryPlan::BaseRelation { // table: el.table, @@ -57,11 +58,17 @@ impl<'a> Session<'a> { // info: el.info, // } } - FromEl::Chain(_) => todo!() + FromEl::Chain(_) => todo!(), }; - Ok(res) + // Ok(res) + // todo!() } - pub(crate) fn base_relation_to_accessor_map(&self, _table: &str, binding: &str, info: &TableInfo) -> AccessorMap { + pub(crate) fn base_relation_to_accessor_map( + &self, + _table: &str, + binding: &str, + info: &TableInfo, + ) -> AccessorMap { let mut ret = BTreeMap::new(); for (i, (k, _)) in info.key_typing.iter().enumerate() { ret.insert(k.into(), (info.table_id, (true, i).into())); @@ -79,11 +86,15 @@ impl<'a> Session<'a> { } BTreeMap::from([(binding.to_string(), ret)]) } - fn convert_where_data_to_plan(&self, plan: ExecPlan, where_data: StaticValue) -> Result { + fn convert_where_data_to_plan( + &self, + plan: ExecPlan, + where_data: StaticValue, + ) -> Result { let where_data = self.partial_eval(where_data, &Default::default(), &Default::default()); - let plan = match where_data?.1 { + let _plan = match where_data?.1 { Value::Bool(true) => plan, - v => { + _v => { todo!() // QueryPlan::Filter { rel: Box::new(plan), filter: v } } @@ -91,7 +102,11 @@ impl<'a> Session<'a> { // Ok(plan) todo!() } - fn convert_select_data_to_plan(&self, plan: ExecPlan, select_data: Selection) -> Result { + fn convert_select_data_to_plan( + &self, + _plan: ExecPlan, + _select_data: Selection, + ) -> Result { // Ok(MegaTupleIt::Projection { arg: Box::new(plan), projection: select_data }) todo!() } @@ -106,6 +121,9 @@ impl<'a> Session<'a> { pub fn iter_node(&self, tid: TableId) -> ExecPlan { let it = self.raw_iterator(tid.in_root); - ExecPlan::NodeIt { it: IteratorSlot::Reified(it), tid: tid.id as u32 } + ExecPlan::NodeIt { + it: IteratorSlot::Reified(it), + tid: tid.id as u32, + } } } diff --git a/src/db/query.rs b/src/db/query.rs index 297d3943..d54a405d 100644 --- a/src/db/query.rs +++ b/src/db/query.rs @@ -1,13 +1,13 @@ -use std::collections::BTreeMap; -use pest::iterators::Pair; use crate::db::engine::Session; use crate::db::table::TableInfo; -use crate::parser::Rule; use crate::error::{CozoError, Result}; use crate::parser::text_identifier::{build_name_in_def, parse_string}; +use crate::parser::Rule; use crate::relation::data::DataKind; use crate::relation::value; use crate::relation::value::{StaticValue, Value}; +use pest::iterators::Pair; +use std::collections::BTreeMap; #[derive(Debug, Eq, PartialEq, Clone)] pub enum FromEl { @@ -41,13 +41,14 @@ pub struct EdgeOrNodeEl { impl<'a> Session<'a> { pub fn parse_from_pattern(&self, pair: Pair) -> Result> { - let res: Result> = pair.into_inner().map(|p| { - match p.as_rule() { + let res: Result> = pair + .into_inner() + .map(|p| match p.as_rule() { Rule::simple_from_pattern => self.parse_simple_from_pattern(p), Rule::node_edge_pattern => self.parse_node_edge_pattern(p), - _ => unreachable!() - } - }).collect(); + _ => unreachable!(), + }) + .collect(); res } @@ -55,17 +56,24 @@ impl<'a> Session<'a> { let mut pairs = pair.into_inner(); let name = pairs.next().unwrap().as_str(); if name.starts_with('_') { - return Err(CozoError::LogicError("Pattern binding cannot start with underscore".to_string())); + return Err(CozoError::LogicError( + "Pattern binding cannot start with underscore".to_string(), + )); } let table_name = build_name_in_def(pairs.next().unwrap(), true)?; let table_info = self.get_table_info(&table_name)?; - let ret = FromEl::Simple(Box::new(SimpleFromEl { binding: name.to_string(), table: table_name, info: table_info })); + let ret = FromEl::Simple(Box::new(SimpleFromEl { + binding: name.to_string(), + table: table_name, + info: table_info, + })); Ok(ret) } fn parse_node_edge_pattern(&self, pair: Pair) -> Result { - let res: Result> = pair.into_inner().map(|p| { - match p.as_rule() { + let res: Result> = pair + .into_inner() + .map(|p| match p.as_rule() { Rule::node_pattern => self.parse_node_pattern(p), Rule::edge_pattern => { let right_join; @@ -78,21 +86,17 @@ impl<'a> Session<'a> { right_join = false; } let mut edge = match nxt.as_rule() { - Rule::fwd_edge_pattern => { - self.parse_edge_pattern(nxt, true)? - } - Rule::bwd_edge_pattern => { - self.parse_edge_pattern(nxt, false)? - } - _ => unreachable!() + Rule::fwd_edge_pattern => self.parse_edge_pattern(nxt, true)?, + Rule::bwd_edge_pattern => self.parse_edge_pattern(nxt, false)?, + _ => unreachable!(), }; edge.left_outer_marker = pairs.next().is_some(); edge.right_outer_marker = right_join; Ok(edge) } - _ => unreachable!() - } - }).collect(); + _ => unreachable!(), + }) + .collect(); let res = res?; let connects = res.windows(2).all(|v| { let left = &v[0]; @@ -110,7 +114,7 @@ impl<'a> Session<'a> { (EdgeOrNodeKind::Node, EdgeOrNodeKind::BwdEdge) => { left.info.table_id == right.info.dst_table_id } - _ => unreachable!() + _ => unreachable!(), } }); if !connects { @@ -146,7 +150,11 @@ impl<'a> Session<'a> { table, binding, info, - kind: if is_fwd { EdgeOrNodeKind::FwdEdge } else { EdgeOrNodeKind::BwdEdge }, + kind: if is_fwd { + EdgeOrNodeKind::FwdEdge + } else { + EdgeOrNodeKind::BwdEdge + }, left_outer_marker: false, right_outer_marker: false, }) @@ -171,7 +179,10 @@ impl<'a> Session<'a> { } pub fn parse_where_pattern(&self, pair: Pair) -> Result { - let conditions = pair.into_inner().map(Value::from_pair).collect::>>()?; + let conditions = pair + .into_inner() + .map(Value::from_pair) + .collect::>>()?; Ok(Value::Apply(value::OP_AND.into(), conditions).to_static()) } @@ -185,7 +196,7 @@ impl<'a> Session<'a> { nxt = pp.next().unwrap(); Some(name.to_string()) } - _ => None + _ => None, }; let mut keys = BTreeMap::new(); @@ -210,8 +221,14 @@ impl<'a> Session<'a> { Rule::spreading => { let el = p.into_inner().next().unwrap(); let to_concat = Value::from_pair(el)?; - if !matches!(to_concat, Value::Dict(_) | Value::Variable(_) | - Value::IdxAccess(_, _) | Value:: FieldAccess(_, _) | Value::Apply(_, _)) { + if !matches!( + to_concat, + Value::Dict(_) + | Value::Variable(_) + | Value::IdxAccess(_, _) + | Value::FieldAccess(_, _) + | Value::Apply(_, _) + ) { return Err(CozoError::LogicError("Cannot spread".to_string())); } if !collected_vals.is_empty() { @@ -222,11 +239,11 @@ impl<'a> Session<'a> { } Rule::scoped_accessor => { let name = parse_string(p.into_inner().next().unwrap())?; - let val = Value::FieldAccess(name.clone().into(), - Value::Variable("_".into()).into()); + let val = + Value::FieldAccess(name.clone().into(), Value::Variable("_".into()).into()); collected_vals.insert(name.into(), val); } - _ => unreachable!() + _ => unreachable!(), } } @@ -247,23 +264,40 @@ impl<'a> Session<'a> { match p.as_rule() { Rule::order_pattern => { for p in p.into_inner() { - ordering.push((p.as_rule() == Rule::order_asc, parse_string(p.into_inner().next().unwrap())?)) + ordering.push(( + p.as_rule() == Rule::order_asc, + parse_string(p.into_inner().next().unwrap())?, + )) } } Rule::offset_pattern => { for p in p.into_inner() { match p.as_rule() { Rule::limit_clause => { - limit = Some(p.into_inner().next().unwrap().as_str().replace('_', "").parse::()?); + limit = Some( + p.into_inner() + .next() + .unwrap() + .as_str() + .replace('_', "") + .parse::()?, + ); } Rule::offset_clause => { - offset = Some(p.into_inner().next().unwrap().as_str().replace('_', "").parse::()?); + offset = Some( + p.into_inner() + .next() + .unwrap() + .as_str() + .replace('_', "") + .parse::()?, + ); } - _ => unreachable!() + _ => unreachable!(), } } } - _ => unreachable!() + _ => unreachable!(), } } @@ -292,9 +326,9 @@ pub struct Selection { mod tests { use std::fs; // use super::*; + use crate::db::engine::Engine; use crate::parser::{Parser, Rule}; use pest::Parser as PestParser; - use crate::db::engine::Engine; #[test] fn parse_patterns() { @@ -335,27 +369,39 @@ mod tests { sess.commit().unwrap(); let s = "from a:Friend, (b:Person)-[:Friend]->(c:Z), x:Person"; - let parsed = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap(); + let parsed = Parser::parse(Rule::from_pattern, s) + .unwrap() + .next() + .unwrap(); assert_eq!(parsed.as_rule(), Rule::from_pattern); assert!(sess.parse_from_pattern(parsed).is_err()); let s = "from a:Friend, (b:Person)-[:Friend]->?(c:Person), x:Person"; - let parsed = Parser::parse(Rule::from_pattern, s).unwrap().next().unwrap(); + let parsed = Parser::parse(Rule::from_pattern, s) + .unwrap() + .next() + .unwrap(); assert_eq!(parsed.as_rule(), Rule::from_pattern); let from_pattern = sess.parse_from_pattern(parsed).unwrap(); println!("{:#?}", from_pattern); let s = "where b.id > c.id || x.name.is_null(), a.id == 5, x.name == 'Joe', x.name.len() == 3"; - let parsed = Parser::parse(Rule::where_pattern, s).unwrap().next().unwrap(); + let parsed = Parser::parse(Rule::where_pattern, s) + .unwrap() + .next() + .unwrap(); let where_result = sess.parse_where_pattern(parsed).unwrap(); println!("{:#?}", where_result); let s = "select {*id: a.id, b: a.b, c: a.c} ordered [e, +c, -b] limit 1 offset 2"; - let parsed = Parser::parse(Rule::select_pattern, s).unwrap().next().unwrap(); + let parsed = Parser::parse(Rule::select_pattern, s) + .unwrap() + .next() + .unwrap(); let select_result = sess.parse_select_pattern(parsed).unwrap(); println!("{:#?}", select_result); } drop(engine); let _ = fs::remove_dir_all(db_path); } -} \ No newline at end of file +} diff --git a/src/db/table.rs b/src/db/table.rs index af25b8ad..b9305832 100644 --- a/src/db/table.rs +++ b/src/db/table.rs @@ -1,10 +1,10 @@ -use std::collections::HashSet; -use std::fmt::{Debug, Formatter}; use crate::db::engine::Session; -use crate::error::{CozoError, Result}; use crate::error::CozoError::LogicError; +use crate::error::{CozoError, Result}; use crate::relation::data::DataKind; use crate::relation::typing::Typing; +use std::collections::HashSet; +use std::fmt::{Debug, Formatter}; #[derive(Eq, PartialEq, Clone, Copy, Ord, PartialOrd, Hash)] pub struct TableId { @@ -29,7 +29,10 @@ impl TableId { impl From<(bool, usize)> for TableId { fn from((in_root, id): (bool, usize)) -> Self { - Self { in_root, id: id as i64 } + Self { + in_root, + id: id as i64, + } } } @@ -59,13 +62,19 @@ impl From<(bool, i64)> for ColId { impl From<(bool, usize)> for ColId { fn from((is_key, id): (bool, usize)) -> Self { - Self { is_key, id: id as i64 } + Self { + is_key, + id: id as i64, + } } } impl Default for TableId { fn default() -> Self { - TableId { in_root: false, id: -1 } + TableId { + in_root: false, + id: -1, + } } } @@ -85,19 +94,35 @@ pub struct TableInfo { impl<'a> Session<'a> { pub fn get_table_info(&self, tbl_name: &str) -> Result { - let table_info = match self.resolve(&tbl_name)? { + let table_info = match self.resolve(tbl_name)? { None => return Err(CozoError::UndefinedType(tbl_name.to_string())), Some(tpl) => { let mut main_coercer = match tpl.data_kind()? { DataKind::Node => { - let key_extractor = Typing::try_from(tpl.get_text(2) - .ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())? - .extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; - let val_extractor = Typing::try_from(tpl.get_text(3) - .ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())? - .extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; - let in_root = tpl.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; - let table_id = tpl.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; + let key_extractor = Typing::try_from( + tpl.get_text(2) + .ok_or_else(|| { + CozoError::BadDataFormat(tpl.data.as_ref().to_vec()) + })? + .as_ref(), + )? + .extract_named_tuple() + .ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; + let val_extractor = Typing::try_from( + tpl.get_text(3) + .ok_or_else(|| { + CozoError::BadDataFormat(tpl.data.as_ref().to_vec()) + })? + .as_ref(), + )? + .extract_named_tuple() + .ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; + let in_root = tpl.get_bool(0).ok_or_else(|| { + CozoError::LogicError("Cannot extract in root".to_string()) + })?; + let table_id = tpl.get_int(1).ok_or_else(|| { + CozoError::LogicError("Cannot extract in root".to_string()) + })?; let table_id = TableId::new(in_root, table_id); TableInfo { @@ -114,38 +139,72 @@ impl<'a> Session<'a> { } } DataKind::Edge => { - let other_key_extractor = Typing::try_from(tpl.get_text(6) - .ok_or_else(|| CozoError::LogicError("Key extraction failed".to_string()))?.as_ref())? - .extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; - let val_extractor = Typing::try_from(tpl.get_text(7) - .ok_or_else(|| CozoError::LogicError("Val extraction failed".to_string()))?.as_ref())? - .extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; - let src_in_root = tpl.get_bool(2) - .ok_or_else(|| CozoError::LogicError("Src in root extraction failed".to_string()))?; - let src_id = tpl.get_int(3) - .ok_or_else(|| CozoError::LogicError("Src id extraction failed".to_string()))?; + let other_key_extractor = Typing::try_from( + tpl.get_text(6) + .ok_or_else(|| { + CozoError::LogicError("Key extraction failed".to_string()) + })? + .as_ref(), + )? + .extract_named_tuple() + .ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; + let val_extractor = Typing::try_from( + tpl.get_text(7) + .ok_or_else(|| { + CozoError::LogicError("Val extraction failed".to_string()) + })? + .as_ref(), + )? + .extract_named_tuple() + .ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; + let src_in_root = tpl.get_bool(2).ok_or_else(|| { + CozoError::LogicError("Src in root extraction failed".to_string()) + })?; + let src_id = tpl.get_int(3).ok_or_else(|| { + CozoError::LogicError("Src id extraction failed".to_string()) + })?; let src_table_id = TableId::new(src_in_root, src_id); - let dst_in_root = tpl.get_bool(4) - .ok_or_else(|| CozoError::LogicError("Dst in root extraction failed".to_string()))?; - let dst_id = tpl.get_int(5) - .ok_or_else(|| CozoError::LogicError("Dst id extraction failed".to_string()))?; + let dst_in_root = tpl.get_bool(4).ok_or_else(|| { + CozoError::LogicError("Dst in root extraction failed".to_string()) + })?; + let dst_id = tpl.get_int(5).ok_or_else(|| { + CozoError::LogicError("Dst id extraction failed".to_string()) + })?; let dst_table_id = TableId::new(dst_in_root, dst_id); - let src = self.table_data(src_id, src_in_root)? - .ok_or_else(|| CozoError::LogicError("Getting src failed".to_string()))?; - let src_key = Typing::try_from(src.get_text(2) - .ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())? - .extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; + let src = self.table_data(src_id, src_in_root)?.ok_or_else(|| { + CozoError::LogicError("Getting src failed".to_string()) + })?; + let src_key = Typing::try_from( + src.get_text(2) + .ok_or_else(|| { + CozoError::BadDataFormat(tpl.data.as_ref().to_vec()) + })? + .as_ref(), + )? + .extract_named_tuple() + .ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; let src_key_typing = src_key.into_iter().map(|(_, v)| v).collect(); - let dst = self.table_data(dst_id, dst_in_root)? - .ok_or_else(|| CozoError::LogicError("Getting dst failed".to_string()))?; - let dst_key = Typing::try_from(dst.get_text(2) - .ok_or_else(|| CozoError::BadDataFormat(tpl.data.as_ref().to_vec()))?.as_ref())? - .extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; + let dst = self.table_data(dst_id, dst_in_root)?.ok_or_else(|| { + CozoError::LogicError("Getting dst failed".to_string()) + })?; + let dst_key = Typing::try_from( + dst.get_text(2) + .ok_or_else(|| { + CozoError::BadDataFormat(tpl.data.as_ref().to_vec()) + })? + .as_ref(), + )? + .extract_named_tuple() + .ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; let dst_key_typing = dst_key.into_iter().map(|(_, v)| v).collect(); - let in_root = tpl.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; - let table_id = tpl.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; + let in_root = tpl.get_bool(0).ok_or_else(|| { + CozoError::LogicError("Cannot extract in root".to_string()) + })?; + let table_id = tpl.get_int(1).ok_or_else(|| { + CozoError::LogicError("Cannot extract in root".to_string()) + })?; let table_id = TableId::new(in_root, table_id); TableInfo { @@ -161,16 +220,22 @@ impl<'a> Session<'a> { associates: vec![], } } - _ => return Err(LogicError("Cannot insert into non-tables".to_string())) + _ => return Err(LogicError("Cannot insert into non-tables".to_string())), }; - let related = self.resolve_related_tables(&tbl_name)?; + let related = self.resolve_related_tables(tbl_name)?; for (_n, d) in related { - let t = d.get_text(4) - .ok_or_else(|| CozoError::LogicError("Unable to extract typing from assoc".to_string()))?; + let t = d.get_text(4).ok_or_else(|| { + CozoError::LogicError("Unable to extract typing from assoc".to_string()) + })?; let t = Typing::try_from(t.as_ref())? - .extract_named_tuple().ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; - let in_root = d.get_bool(0).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; - let table_id = d.get_int(1).ok_or_else(|| CozoError::LogicError("Cannot extract in root".to_string()))?; + .extract_named_tuple() + .ok_or_else(|| CozoError::LogicError("Corrupt data".to_string()))?; + let in_root = d.get_bool(0).ok_or_else(|| { + CozoError::LogicError("Cannot extract in root".to_string()) + })?; + let table_id = d.get_int(1).ok_or_else(|| { + CozoError::LogicError("Cannot extract in root".to_string()) + })?; let table_id = TableId::new(in_root, table_id); let coercer = TableInfo { @@ -193,4 +258,4 @@ impl<'a> Session<'a> { }; Ok(table_info) } -} \ No newline at end of file +} diff --git a/src/error.rs b/src/error.rs index c486dd86..979eac07 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,11 +1,11 @@ -use std::result; -use std::time::SystemTimeError; -use thiserror::Error; -use cozorocks::BridgeError; use crate::parser::Rule; use crate::relation::data::DataKind; use crate::relation::tuple::OwnTuple; -use crate::relation::value::{StaticValue}; +use crate::relation::value::StaticValue; +use cozorocks::BridgeError; +use std::result; +use std::time::SystemTimeError; +use thiserror::Error; #[derive(Error, Debug)] pub enum CozoError { @@ -15,15 +15,14 @@ pub enum CozoError { #[error("Invalid escape sequence")] InvalidEscapeSequence, -// #[error("Type mismatch")] -// TypeError, - + // #[error("Type mismatch")] + // TypeError, #[error("Reserved identifier")] ReservedIdent, // #[error("The requested name exists")] -// NameConflict, -// + // NameConflict, + // #[error("Undefined type '{0}'")] UndefinedType(String), @@ -50,31 +49,30 @@ pub enum CozoError { #[error("Undefined parameter {0}")] UndefinedParam(String), -// -// #[error("Undefined table")] -// UndefinedTable, -// -// #[error("Undefined parameter")] -// UndefinedParam, -// -// #[error("Value required")] -// ValueRequired, -// -// #[error("Incompatible value")] -// IncompatibleValue, -// -// #[error("Wrong type")] -// WrongType, -// -// #[error("Cannot have global edge between local nodes")] -// IncompatibleEdge, -// -// #[error("Unexpected index columns found")] -// UnexpectedIndexColumns, -// -// #[error("Database already closed")] -// DatabaseClosed, - + // + // #[error("Undefined table")] + // UndefinedTable, + // + // #[error("Undefined parameter")] + // UndefinedParam, + // + // #[error("Value required")] + // ValueRequired, + // + // #[error("Incompatible value")] + // IncompatibleValue, + // + // #[error("Wrong type")] + // WrongType, + // + // #[error("Cannot have global edge between local nodes")] + // IncompatibleEdge, + // + // #[error("Unexpected index columns found")] + // UnexpectedIndexColumns, + // + // #[error("Database already closed")] + // DatabaseClosed, #[error("InvalidArgument")] InvalidArgument, @@ -94,8 +92,8 @@ pub enum CozoError { TypeMismatch, // #[error(transparent)] -// Storage(#[from] cozo_rocks::BridgeStatus), -// + // Storage(#[from] cozo_rocks::BridgeStatus), + // #[error(transparent)] Io(#[from] std::io::Error), @@ -115,4 +113,4 @@ pub enum CozoError { Bridge(#[from] BridgeError), } -pub type Result = result::Result; \ No newline at end of file +pub type Result = result::Result; diff --git a/src/lib.rs b/src/lib.rs index 205a7318..ab144ed1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,10 @@ extern crate core; // pub mod storage; // pub mod mutation; // pub mod plan; -pub mod relation; pub mod db; pub mod error; pub mod parser; +pub mod relation; #[cfg(test)] mod tests { @@ -24,4 +24,4 @@ mod tests { let _o = OptionsPtr::default(); println!("Hello"); } -} \ No newline at end of file +} diff --git a/src/parser.rs b/src/parser.rs index 83a9eb2d..ee5793aa 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,13 +1,11 @@ -pub mod text_identifier; pub mod number; +pub mod text_identifier; use pest_derive::Parser; - #[derive(Parser)] #[grammar = "grammar.pest"] pub struct Parser; - #[cfg(test)] mod tests { use super::*; @@ -20,7 +18,10 @@ mod tests { assert_eq!(Parser::parse(Rule::ident, "x_y").unwrap().as_str(), "x_y"); assert_eq!(Parser::parse(Rule::ident, "x_").unwrap().as_str(), "x_"); assert_eq!(Parser::parse(Rule::ident, "你好").unwrap().as_str(), "你好"); - assert_eq!(Parser::parse(Rule::ident, "你好123").unwrap().as_str(), "你好123"); + assert_eq!( + Parser::parse(Rule::ident, "你好123").unwrap().as_str(), + "你好123" + ); assert_ne!(Parser::parse(Rule::ident, "x$y").unwrap().as_str(), "x$y"); assert_eq!(Parser::parse(Rule::ident, "_x").unwrap().as_str(), "_x"); @@ -38,33 +39,95 @@ mod tests { #[test] fn strings() { - assert_eq!(Parser::parse(Rule::string, r#""""#).unwrap().as_str(), r#""""#); - assert_eq!(Parser::parse(Rule::string, r#"" b a c""#).unwrap().as_str(), r#"" b a c""#); - assert_eq!(Parser::parse(Rule::string, r#""你好👋""#).unwrap().as_str(), r#""你好👋""#); - assert_eq!(Parser::parse(Rule::string, r#""\n""#).unwrap().as_str(), r#""\n""#); - assert_eq!(Parser::parse(Rule::string, r#""\u5678""#).unwrap().as_str(), r#""\u5678""#); + assert_eq!( + Parser::parse(Rule::string, r#""""#).unwrap().as_str(), + r#""""# + ); + assert_eq!( + Parser::parse(Rule::string, r#"" b a c""#).unwrap().as_str(), + r#"" b a c""# + ); + assert_eq!( + Parser::parse(Rule::string, r#""你好👋""#).unwrap().as_str(), + r#""你好👋""# + ); + assert_eq!( + Parser::parse(Rule::string, r#""\n""#).unwrap().as_str(), + r#""\n""# + ); + assert_eq!( + Parser::parse(Rule::string, r#""\u5678""#).unwrap().as_str(), + r#""\u5678""# + ); assert!(Parser::parse(Rule::string, r#""\ux""#).is_err()); - assert_eq!(Parser::parse(Rule::string, r###"r#"a"#"###).unwrap().as_str(), r##"r#"a"#"##); + assert_eq!( + Parser::parse(Rule::string, r###"r#"a"#"###) + .unwrap() + .as_str(), + r##"r#"a"#"## + ); } #[test] fn numbers() { assert_eq!(Parser::parse(Rule::number, "123").unwrap().as_str(), "123"); assert_eq!(Parser::parse(Rule::number, "0").unwrap().as_str(), "0"); - assert_eq!(Parser::parse(Rule::number, "0123").unwrap().as_str(), "0123"); - assert_eq!(Parser::parse(Rule::number, "000_1").unwrap().as_str(), "000_1"); + assert_eq!( + Parser::parse(Rule::number, "0123").unwrap().as_str(), + "0123" + ); + assert_eq!( + Parser::parse(Rule::number, "000_1").unwrap().as_str(), + "000_1" + ); assert!(Parser::parse(Rule::number, "_000_1").is_err()); - assert_eq!(Parser::parse(Rule::number, "0xAf03").unwrap().as_str(), "0xAf03"); - assert_eq!(Parser::parse(Rule::number, "0o0_7067").unwrap().as_str(), "0o0_7067"); - assert_ne!(Parser::parse(Rule::number, "0o0_7068").unwrap().as_str(), "0o0_7068"); - assert_eq!(Parser::parse(Rule::number, "0b0000_0000_1111").unwrap().as_str(), "0b0000_0000_1111"); - assert_ne!(Parser::parse(Rule::number, "0b0000_0000_1112").unwrap().as_str(), "0b0000_0000_1112"); + assert_eq!( + Parser::parse(Rule::number, "0xAf03").unwrap().as_str(), + "0xAf03" + ); + assert_eq!( + Parser::parse(Rule::number, "0o0_7067").unwrap().as_str(), + "0o0_7067" + ); + assert_ne!( + Parser::parse(Rule::number, "0o0_7068").unwrap().as_str(), + "0o0_7068" + ); + assert_eq!( + Parser::parse(Rule::number, "0b0000_0000_1111") + .unwrap() + .as_str(), + "0b0000_0000_1111" + ); + assert_ne!( + Parser::parse(Rule::number, "0b0000_0000_1112") + .unwrap() + .as_str(), + "0b0000_0000_1112" + ); - assert_eq!(Parser::parse(Rule::number, "123.45").unwrap().as_str(), "123.45"); - assert_eq!(Parser::parse(Rule::number, "1_23.4_5_").unwrap().as_str(), "1_23.4_5_"); - assert_ne!(Parser::parse(Rule::number, "123.").unwrap().as_str(), "123."); - assert_eq!(Parser::parse(Rule::number, "123.333e456").unwrap().as_str(), "123.333e456"); - assert_eq!(Parser::parse(Rule::number, "1_23.33_3e45_6").unwrap().as_str(), "1_23.33_3e45_6"); + assert_eq!( + Parser::parse(Rule::number, "123.45").unwrap().as_str(), + "123.45" + ); + assert_eq!( + Parser::parse(Rule::number, "1_23.4_5_").unwrap().as_str(), + "1_23.4_5_" + ); + assert_ne!( + Parser::parse(Rule::number, "123.").unwrap().as_str(), + "123." + ); + assert_eq!( + Parser::parse(Rule::number, "123.333e456").unwrap().as_str(), + "123.333e456" + ); + assert_eq!( + Parser::parse(Rule::number, "1_23.33_3e45_6") + .unwrap() + .as_str(), + "1_23.33_3e45_6" + ); } #[test] diff --git a/src/parser/text_identifier.rs b/src/parser/text_identifier.rs index eccbb272..01c0dfa2 100644 --- a/src/parser/text_identifier.rs +++ b/src/parser/text_identifier.rs @@ -1,11 +1,17 @@ -use pest::iterators::Pair; -use crate::parser::Rule; use crate::error::{CozoError, Result}; use crate::parser::number::parse_int; +use crate::parser::Rule; +use pest::iterators::Pair; #[inline] fn parse_raw_string(pair: Pair) -> Result { - Ok(pair.into_inner().into_iter().next().unwrap().as_str().to_string()) + Ok(pair + .into_inner() + .into_iter() + .next() + .unwrap() + .as_str() + .to_string()) } #[inline] @@ -29,13 +35,12 @@ fn parse_quoted_string(pair: Pair) -> Result { ret.push(ch); } s if s.starts_with('\\') => return Err(CozoError::InvalidEscapeSequence), - s => ret.push_str(s) + s => ret.push_str(s), } } Ok(ret) } - #[inline] fn parse_s_quoted_string(pair: Pair) -> Result { let pairs = pair.into_inner().next().unwrap().into_inner(); @@ -57,7 +62,7 @@ fn parse_s_quoted_string(pair: Pair) -> Result { ret.push(ch); } s if s.starts_with('\\') => return Err(CozoError::InvalidEscapeSequence), - s => ret.push_str(s) + s => ret.push_str(s), } } Ok(ret) @@ -70,7 +75,7 @@ pub fn parse_string(pair: Pair) -> Result { Rule::s_quoted_string => Ok(parse_s_quoted_string(pair)?), Rule::raw_string => Ok(parse_raw_string(pair)?), Rule::ident => Ok(pair.as_str().to_string()), - _ => unreachable!() + _ => unreachable!(), } } @@ -83,7 +88,7 @@ pub fn build_name_in_def(pair: Pair, forbid_underscore: bool) -> Result parse_ident(inner), Rule::raw_string | Rule::s_quoted_string | Rule::quoted_string => parse_string(inner)?, - _ => unreachable!() + _ => unreachable!(), }; if forbid_underscore && name.starts_with('_') { Err(CozoError::ReservedIdent) diff --git a/src/relation.rs b/src/relation.rs index 68b9cdf3..1f49559f 100644 --- a/src/relation.rs +++ b/src/relation.rs @@ -1,6 +1,6 @@ -pub mod tuple; -pub mod value; +pub mod data; pub mod key_order; -pub mod typing; pub mod table; -pub mod data; \ No newline at end of file +pub mod tuple; +pub mod typing; +pub mod value; diff --git a/src/relation/data.rs b/src/relation/data.rs index 9a73db22..dcb09364 100644 --- a/src/relation/data.rs +++ b/src/relation/data.rs @@ -1,7 +1,7 @@ -use std::borrow::Borrow; -use crate::relation::tuple::Tuple; use crate::error::{CozoError, Result}; +use crate::relation::tuple::Tuple; use crate::relation::typing::Typing; +use std::borrow::Borrow; #[repr(u32)] #[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Clone)] @@ -32,11 +32,13 @@ impl> Tuple { 5 => Val, 6 => Type, u32::MAX => Empty, - v => return Err(CozoError::UndefinedDataKind(v)) + v => return Err(CozoError::UndefinedDataKind(v)), }) } pub fn interpret_as_type(&self) -> Result { - let text = self.get_text(0).ok_or_else(|| CozoError::BadDataFormat(self.as_ref().to_vec()))?; + let text = self + .get_text(0) + .ok_or_else(|| CozoError::BadDataFormat(self.as_ref().to_vec()))?; Typing::try_from(text.borrow()) } -} \ No newline at end of file +} diff --git a/src/relation/key_order.rs b/src/relation/key_order.rs index c2aab9e8..23f69880 100644 --- a/src/relation/key_order.rs +++ b/src/relation/key_order.rs @@ -1,5 +1,5 @@ -use std::cmp::Ordering; use crate::relation::tuple::Tuple; +use std::cmp::Ordering; impl, T2: AsRef<[u8]>> PartialOrd> for Tuple { fn partial_cmp(&self, other: &Tuple) -> Option { @@ -24,16 +24,16 @@ pub fn compare(a: &[u8], b: &[u8]) -> i8 { match ta.cmp(&tb) { Ordering::Less => -1, Ordering::Greater => 1, - Ordering::Equal => 0 + Ordering::Equal => 0, } } #[cfg(test)] mod tests { - use std::collections::BTreeMap; use crate::relation::key_order::compare; use crate::relation::tuple::Tuple; use crate::relation::value::Value; + use std::collections::BTreeMap; #[test] fn ordering() { @@ -56,8 +56,15 @@ mod tests { t2.push_int(123); assert_eq!(compare(t.as_ref(), t2.as_ref()), -1); assert_eq!(compare(t.as_ref(), t.as_ref()), 0); - let vals: Value = vec![().into(), BTreeMap::new().into(), 1e23.into(), false.into(), "xxyx".into()].into(); + let vals: Value = vec![ + ().into(), + BTreeMap::new().into(), + 1e23.into(), + false.into(), + "xxyx".into(), + ] + .into(); t.push_value(&vals); assert_eq!(compare(t.as_ref(), t.as_ref()), 0); } -} \ No newline at end of file +} diff --git a/src/relation/table.rs b/src/relation/table.rs index 599f415c..2bd19484 100644 --- a/src/relation/table.rs +++ b/src/relation/table.rs @@ -1,6 +1,6 @@ -use std::cmp::Ordering; -use crate::relation::tuple::{CowTuple}; +use crate::relation::tuple::CowTuple; use crate::relation::typing::Typing; +use std::cmp::Ordering; #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone)] pub struct StorageId { @@ -49,7 +49,10 @@ pub struct MegaTuple { impl MegaTuple { pub fn empty_tuple() -> Self { - MegaTuple { keys: vec![], vals: vec![] } + MegaTuple { + keys: vec![], + vals: vec![], + } } pub fn is_empty(&self) -> bool { self.keys.is_empty() @@ -72,10 +75,10 @@ impl MegaTuple { pub fn all_keys_cmp(&self, other: &Self) -> Ordering { for (l, r) in self.keys.iter().zip(&other.keys) { match l.key_part_cmp(r) { - Ordering::Equal => {}, - v => return v + Ordering::Equal => {} + v => return v, } } Ordering::Equal } -} \ No newline at end of file +} diff --git a/src/relation/tuple.rs b/src/relation/tuple.rs index 3188dcd0..5f8d4030 100644 --- a/src/relation/tuple.rs +++ b/src/relation/tuple.rs @@ -1,24 +1,28 @@ -use std::borrow::{Cow}; +use crate::db::table::{ColId, TableId}; +use crate::relation::data::DataKind; +use crate::relation::value::{Tag, Value}; +use cozorocks::SlicePtr; +use std::borrow::Cow; use std::cell::RefCell; use std::cmp::Ordering; use std::collections::BTreeMap; use std::fmt::{Debug, Formatter}; use std::hash::{Hash, Hasher}; use uuid::Uuid; -use cozorocks::SlicePtr; -use crate::db::table::{ColId, TableId}; -use crate::relation::data::DataKind; -use crate::relation::value::{Tag, Value}; #[derive(Clone)] pub struct Tuple - where T: AsRef<[u8]> +where + T: AsRef<[u8]>, { pub data: T, idx_cache: RefCell>, } -impl AsRef<[u8]> for Tuple where T: AsRef<[u8]> { +impl AsRef<[u8]> for Tuple +where + T: AsRef<[u8]>, +{ fn as_ref(&self) -> &[u8] { self.data.as_ref() } @@ -55,7 +59,7 @@ impl AsRef<[u8]> for CowSlice { fn as_ref(&self) -> &[u8] { match self { CowSlice::Ptr(s) => s.as_ref(), - CowSlice::Own(o) => o.as_ref() + CowSlice::Own(o) => o.as_ref(), } } } @@ -76,7 +80,7 @@ impl CowTuple { pub fn to_owned(self) -> OwnTuple { match self.data { CowSlice::Ptr(p) => OwnTuple::new(p.as_ref().to_vec()), - CowSlice::Own(o) => OwnTuple::new(o) + CowSlice::Own(o) => OwnTuple::new(o), } } } @@ -120,7 +124,7 @@ impl> Tuple { fn all_cached(&self) -> bool { match self.idx_cache.borrow().last() { None => self.data.as_ref().len() == PREFIX_LEN, - Some(l) => *l == self.data.as_ref().len() + Some(l) => *l == self.data.as_ref().len(), } } #[inline] @@ -157,11 +161,9 @@ impl> Tuple { let slen = slen as usize; start + slen + offset } - Tag::List | - Tag::Apply | - Tag::Dict | - Tag::IdxAccess | - Tag::FieldAccess => start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize, + Tag::List | Tag::Apply | Tag::Dict | Tag::IdxAccess | Tag::FieldAccess => { + start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize + } Tag::TupleRef => { let temp = start + 1 + self.parse_varint(start + 1).1 + 1; temp + self.parse_varint(temp).1 @@ -202,7 +204,7 @@ impl> Tuple { } Some(val) } - None => None + None => None, } } @@ -210,7 +212,7 @@ impl> Tuple { pub fn get_null(&self, idx: usize) -> Option<()> { match self.get(idx)? { Value::Null => Some(()), - _ => None + _ => None, } } @@ -218,7 +220,7 @@ impl> Tuple { pub fn get_int(&self, idx: usize) -> Option { match self.get(idx)? { Value::Int(i) => Some(i), - _ => None + _ => None, } } @@ -226,7 +228,7 @@ impl> Tuple { pub fn get_text(&self, idx: usize) -> Option> { match self.get(idx)? { Value::Text(d) => Some(d), - _ => None + _ => None, } } @@ -234,16 +236,15 @@ impl> Tuple { pub fn get_bool(&self, idx: usize) -> Option { match self.get(idx)? { Value::Bool(b) => Some(b), - _ => None + _ => None, } } - #[inline] pub fn get_float(&self, idx: usize) -> Option { match self.get(idx)? { Value::Float(f) => Some(f.into_inner()), - _ => None + _ => None, } } @@ -251,7 +252,7 @@ impl> Tuple { pub fn get_uuid(&self, idx: usize) -> Option { match self.get(idx)? { Value::Uuid(u) => Some(u), - _ => None + _ => None, } } @@ -259,7 +260,7 @@ impl> Tuple { pub fn get_list(&self, idx: usize) -> Option> { match self.get(idx)? { Value::List(u) => Some(u), - _ => None + _ => None, } } @@ -267,7 +268,7 @@ impl> Tuple { pub fn get_dict(&self, idx: usize) -> Option, Value>> { match self.get(idx)? { Value::Dict(u) => Some(u), - _ => None + _ => None, } } @@ -275,7 +276,7 @@ impl> Tuple { pub fn get_variable(&self, idx: usize) -> Option> { match self.get(idx)? { Value::Variable(u) => Some(u), - _ => None + _ => None, } } @@ -283,7 +284,7 @@ impl> Tuple { pub fn get_apply(&self, idx: usize) -> Option<(Cow, Vec)> { match self.get(idx)? { Value::Apply(n, l) => Some((n, l)), - _ => None + _ => None, } } @@ -293,7 +294,7 @@ impl> Tuple { let start = pos + 1; let tag = match Tag::try_from(data[pos]) { Ok(t) => t, - Err(e) => panic!("Cannot parse tag {} for {:?}", e, data) + Err(e) => panic!("Cannot parse tag {} for {:?}", e, data), }; let (nxt, val): (usize, Value) = match tag { Tag::Null => (start, ().into()), @@ -304,8 +305,14 @@ impl> Tuple { let val = Self::varint_to_zigzag(u); (start + offset, val.into()) } - Tag::Float => (start + 8, f64::from_be_bytes(data[start..start + 8].try_into().unwrap()).into()), - Tag::Uuid => (start + 16, Uuid::from_slice(&data[start..start + 16]).unwrap().into()), + Tag::Float => ( + start + 8, + f64::from_be_bytes(data[start..start + 8].try_into().unwrap()).into(), + ), + Tag::Uuid => ( + start + 16, + Uuid::from_slice(&data[start..start + 16]).unwrap().into(), + ), Tag::Text => { let (slen, offset) = self.parse_varint(start); let slen = slen as usize; @@ -325,7 +332,8 @@ impl> Tuple { (start + slen + offset, Value::Variable(s.into())) } Tag::List => { - let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize; + let end_pos = + start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize; let mut start_pos = start + 4; let mut collected = vec![]; while start_pos < end_pos { @@ -336,14 +344,15 @@ impl> Tuple { (end_pos, collected.into()) } Tag::Apply => { - let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize; + let end_pos = + start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize; let mut start_pos = start + 4; let mut collected = vec![]; let (val, new_pos) = self.parse_value_at(start_pos); start_pos = new_pos; let op = match val { Value::Variable(s) => s, - _ => panic!("Corrupt data when parsing Apply") + _ => panic!("Corrupt data when parsing Apply"), }; while start_pos < end_pos { let (val, new_pos) = self.parse_value_at(start_pos); @@ -353,7 +362,8 @@ impl> Tuple { (end_pos, Value::Apply(op, collected)) } Tag::Dict => { - let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize; + let end_pos = + start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize; let mut start_pos = start + 4; let mut collected: BTreeMap, Value> = BTreeMap::new(); while start_pos < end_pos { @@ -371,7 +381,8 @@ impl> Tuple { } Tag::MaxTag => (start, Value::EndSentinel), Tag::IdxAccess => { - let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize; + let end_pos = + start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize; let mut start_pos = start + 4; let (idx, offset) = self.parse_varint(start_pos); start_pos += offset; @@ -379,7 +390,8 @@ impl> Tuple { (end_pos, Value::IdxAccess(idx as usize, val.into())) } Tag::FieldAccess => { - let end_pos = start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize; + let end_pos = + start + u32::from_be_bytes(data[start..start + 4].try_into().unwrap()) as usize; let mut start_pos = start + 4; let (slen, offset) = self.parse_varint(start); @@ -398,9 +410,19 @@ impl> Tuple { let (tidu, parse_len) = self.parse_varint(start + 1); let is_key = self.parse_value_at(parse_len + start + 1).0 == Value::Bool(true); let (cidu, parse_len2) = self.parse_varint(start + 1 + parse_len + 1); - (start + 1 + parse_len + 1 + parse_len2, - Value::TupleRef(TableId { in_root, id: Self::varint_to_zigzag(tidu) }, - ColId { is_key, id: Self::varint_to_zigzag(cidu) })) + ( + start + 1 + parse_len + 1 + parse_len2, + Value::TupleRef( + TableId { + in_root, + id: Self::varint_to_zigzag(tidu), + }, + ColId { + is_key, + id: Self::varint_to_zigzag(cidu), + }, + ), + ) } }; (val, nxt) @@ -431,8 +453,12 @@ impl> Debug for Tuple { write!(f, "Tuple<{}>{{", self.get_prefix())?; } } - let strings = self.iter().enumerate().map(|(i, v)| format!("{}: {}", i, v)) - .collect::>().join(", "); + let strings = self + .iter() + .enumerate() + .map(|(i, v)| format!("{}: {}", i, v)) + .collect::>() + .join(", "); write!(f, "{}}}", strings) } } @@ -641,7 +667,6 @@ impl OwnTuple { } } - #[inline] fn push_varint(&mut self, u: u64) { let mut u = u; @@ -687,7 +712,7 @@ impl OwnTuple { impl<'a> Extend> for OwnTuple { #[inline] - fn extend>>(&mut self, iter: T) { + fn extend>>(&mut self, iter: T) { for v in iter { self.push_value(&v) } @@ -709,11 +734,10 @@ impl> Hash for Tuple { impl> Eq for Tuple {} - #[cfg(test)] mod tests { - use std::collections::BTreeMap; use super::*; + use std::collections::BTreeMap; #[test] fn serde() { @@ -724,11 +748,7 @@ mod tests { t.push_null(); t.push_str("abcdef"); t.push_null(); - t.push_value(&vec![ - true.into(), - 1e236.into(), - "xxyyzz".into(), - ].into()); + t.push_value(&vec![true.into(), 1e236.into(), "xxyyzz".into()].into()); t.push_int(-123345); t.push_value(&BTreeMap::from([]).into()); t.push_int(12121212); @@ -758,11 +778,14 @@ mod tests { assert_eq!(Value::Null, t.get(5).unwrap()); t3.get_pos(6); assert_eq!(t.idx_cache.borrow().last(), t3.idx_cache.borrow().last()); - assert_eq!(Value::from(Value::from(vec![ - true.into(), - 1e236.into(), - "xxyyzz".into(), - ])), t.get(6).unwrap()); + assert_eq!( + Value::from(Value::from(vec![ + true.into(), + 1e236.into(), + "xxyyzz".into(), + ])), + t.get(6).unwrap() + ); t3.get_pos(7); assert_eq!(t.idx_cache.borrow().last(), t3.idx_cache.borrow().last()); assert_eq!(Value::from(-123345i64), t.get(7).unwrap()); @@ -774,7 +797,10 @@ mod tests { assert_eq!(Value::from(12121212i64), t.get(9).unwrap()); t3.get_pos(10); assert_eq!(t.idx_cache.borrow().last(), t3.idx_cache.borrow().last()); - assert_eq!(Value::from(BTreeMap::from([("yzyz".into(), "fifo".into())])), t.get(10).unwrap()); + assert_eq!( + Value::from(BTreeMap::from([("yzyz".into(), "fifo".into())])), + t.get(10).unwrap() + ); t3.get_pos(11); assert_eq!(t.idx_cache.borrow().last(), t3.idx_cache.borrow().last()); assert_eq!(Value::from(1e245), t.get(11).unwrap()); @@ -797,14 +823,20 @@ mod tests { assert_eq!(Value::from(BTreeMap::new()), t.get(8).unwrap()); assert_eq!(Value::Null, t.get(3).unwrap()); assert_eq!(Value::from("abcdef"), t.get(4).unwrap()); - assert_eq!(Value::from(Value::from(vec![ - true.into(), - 1e236.into(), - "xxyyzz".into(), - ])), t.get(6).unwrap()); + assert_eq!( + Value::from(Value::from(vec![ + true.into(), + 1e236.into(), + "xxyyzz".into(), + ])), + t.get(6).unwrap() + ); assert_eq!(None, t.get(13)); assert_eq!(Value::from(-123345i64), t.get(7).unwrap()); - assert_eq!(Value::from(BTreeMap::from([("yzyz".into(), "fifo".into())])), t.get(10).unwrap()); + assert_eq!( + Value::from(BTreeMap::from([("yzyz".into(), "fifo".into())])), + t.get(10).unwrap() + ); assert_eq!(None, t.get(13131)); println!("{:?}", t.iter().collect::>()); @@ -834,4 +866,4 @@ mod tests { v.push_int(-64); println!("{:?} {:?}", v, v.data); } -} \ No newline at end of file +} diff --git a/src/relation/typing.rs b/src/relation/typing.rs index 1511a99d..cadad2a7 100644 --- a/src/relation/typing.rs +++ b/src/relation/typing.rs @@ -1,14 +1,13 @@ -use std::fmt::{Display, Formatter}; -use pest::iterators::Pair; -use crate::error::{Result, CozoError}; -use crate::relation::value::Value; -use pest::Parser as PestParser; use crate::db::engine::Session; +use crate::error::{CozoError, Result}; +use crate::parser::text_identifier::build_name_in_def; use crate::parser::Parser; use crate::parser::Rule; -use crate::parser::text_identifier::build_name_in_def; use crate::relation::data::DataKind; - +use crate::relation::value::Value; +use pest::iterators::Pair; +use pest::Parser as PestParser; +use std::fmt::{Display, Formatter}; #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone)] pub enum Typing { @@ -42,15 +41,21 @@ impl Display for Typing { write!(f, "({})", joined) } Typing::NamedTuple(n) => { - let collected = n.iter().map(|(k, v)| - format!(r##""{}":{}"##, k, v)).collect::>(); + let collected = n + .iter() + .map(|(k, v)| format!(r##""{}":{}"##, k, v)) + .collect::>(); let joined = collected.join(","); write!(f, "{{")?; write!(f, "{}", joined)?; write!(f, "}}") } Typing::Function(args, ret) => { - let args_display = args.iter().map(|t| t.to_string()).collect::>().join(","); + let args_display = args + .iter() + .map(|t| t.to_string()) + .collect::>() + .join(","); write!(f, "<{}>->{}", args_display, ret) } } @@ -69,7 +74,7 @@ impl Typing { } impl Typing { - pub fn from_pair<'a, 't>(pair: Pair, env: Option<&Session<'a>>) -> Result { + pub fn from_pair<'a>(pair: Pair, env: Option<&Session<'a>>) -> Result { Ok(match pair.as_rule() { Rule::simple_type => match pair.as_str() { "Any" => Typing::Any, @@ -78,52 +83,67 @@ impl Typing { "Float" => Typing::Float, "Text" => Typing::Text, "Uuid" => Typing::Uuid, - t => { - match env { - None => return Err(CozoError::UndefinedType(t.to_string())), - Some(env) => { - let resolved = env.resolve(t)?; - let resolved = resolved.ok_or_else(|| CozoError::UndefinedType(t.to_string()))?; - match resolved.data_kind()? { - DataKind::Type => resolved.interpret_as_type()?, - _ => return Err(CozoError::UndefinedType(t.to_string())) - } + t => match env { + None => return Err(CozoError::UndefinedType(t.to_string())), + Some(env) => { + let resolved = env.resolve(t)?; + let resolved = + resolved.ok_or_else(|| CozoError::UndefinedType(t.to_string()))?; + match resolved.data_kind()? { + DataKind::Type => resolved.interpret_as_type()?, + _ => return Err(CozoError::UndefinedType(t.to_string())), } } - } + }, }, - Rule::nullable_type => Typing::Nullable(Box::new(Typing::from_pair(pair.into_inner().next().unwrap(), env)?)), - Rule::homogeneous_list_type => Typing::Homogeneous(Box::new(Typing::from_pair(pair.into_inner().next().unwrap(), env)?)), + Rule::nullable_type => Typing::Nullable(Box::new(Typing::from_pair( + pair.into_inner().next().unwrap(), + env, + )?)), + Rule::homogeneous_list_type => Typing::Homogeneous(Box::new(Typing::from_pair( + pair.into_inner().next().unwrap(), + env, + )?)), Rule::unnamed_tuple_type => { - let types = pair.into_inner().map(|p| Typing::from_pair(p, env)).collect::>>()?; + let types = pair + .into_inner() + .map(|p| Typing::from_pair(p, env)) + .collect::>>()?; 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, env)?; - Ok((name, typ)) - }).collect::>>()?; + 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, env)?; + Ok((name, typ)) + }) + .collect::>>()?; Typing::NamedTuple(types) } Rule::function_type => { let mut pairs = pair.into_inner(); - let args = pairs.next().unwrap().into_inner() - .map(|p| Typing::from_pair(p, env)).collect::>>()?; + let args = pairs + .next() + .unwrap() + .into_inner() + .map(|p| Typing::from_pair(p, env)) + .collect::>>()?; let ret = Typing::from_pair(pairs.next().unwrap(), env)?; Typing::Function(args, ret.into()) } - _ => unreachable!() + _ => unreachable!(), }) } pub fn extract_named_tuple(self) -> Option> { match self { Typing::NamedTuple(t) => Some(t), - _ => None + _ => None, } } @@ -149,14 +169,14 @@ impl Typing { 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::>>()?)) - } - _ => Err(CozoError::TypeMismatch) - } - } + Typing::Homogeneous(t) => match v { + Value::List(vs) => Ok(Value::List( + vs.into_iter() + .map(|v| t.coerce(v)) + .collect::>>()?, + )), + _ => Err(CozoError::TypeMismatch), + }, Typing::UnnamedTuple(_ut) => { todo!() } @@ -165,37 +185,39 @@ impl Typing { } Typing::Any => unreachable!(), Typing::Nullable(_) => unreachable!(), - Typing::Function(_, _) => Err(CozoError::LogicError("Cannot coerce function types".to_string())) + Typing::Function(_, _) => Err(CozoError::LogicError( + "Cannot coerce function types".to_string(), + )), } } fn coerce_bool<'a>(&self, v: Value<'a>) -> Result> { match v { v @ Value::Bool(_) => Ok(v), - _ => Err(CozoError::TypeMismatch) + _ => Err(CozoError::TypeMismatch), } } fn coerce_int<'a>(&self, v: Value<'a>) -> Result> { match v { v @ Value::Int(_) => Ok(v), - _ => Err(CozoError::TypeMismatch) + _ => Err(CozoError::TypeMismatch), } } fn coerce_float<'a>(&self, v: Value<'a>) -> Result> { match v { v @ Value::Float(_) => Ok(v), - _ => Err(CozoError::TypeMismatch) + _ => Err(CozoError::TypeMismatch), } } fn coerce_text<'a>(&self, v: Value<'a>) -> Result> { match v { v @ Value::Text(_) => Ok(v), - _ => Err(CozoError::TypeMismatch) + _ => Err(CozoError::TypeMismatch), } } fn coerce_uuid<'a>(&self, v: Value<'a>) -> Result> { match v { v @ Value::Uuid(_) => Ok(v), - _ => Err(CozoError::TypeMismatch) + _ => Err(CozoError::TypeMismatch), } } } @@ -217,7 +239,10 @@ mod tests { #[test] fn to_string() { assert_eq!( - format!("{}", Typing::Nullable(Box::new(Typing::Homogeneous(Box::new(Typing::Text))))), + format!( + "{}", + Typing::Nullable(Box::new(Typing::Homogeneous(Box::new(Typing::Text)))) + ), "?[Text]" ); } @@ -246,4 +271,4 @@ mod tests { println!("{:#?}", res); assert!(res.is_ok()); } -} \ No newline at end of file +} diff --git a/src/relation/value.rs b/src/relation/value.rs index c3a59311..e88e4933 100644 --- a/src/relation/value.rs +++ b/src/relation/value.rs @@ -1,19 +1,18 @@ -use std::borrow::Cow; -use std::collections::BTreeMap; -use std::fmt::{Debug, Display, Formatter, Write}; -use lazy_static::lazy_static; -use pest::prec_climber::{Assoc, PrecClimber, Operator}; -use ordered_float::OrderedFloat; -use pest::Parser as PestParser; -use pest::iterators::Pair; -use uuid::Uuid; use crate::db::table::{ColId, TableId}; -use crate::parser::{Parser, Rule}; -use crate::error::{CozoError, Result}; use crate::error::CozoError::LogicError; +use crate::error::{CozoError, Result}; use crate::parser::number::parse_int; use crate::parser::text_identifier::parse_string; - +use crate::parser::{Parser, Rule}; +use lazy_static::lazy_static; +use ordered_float::OrderedFloat; +use pest::iterators::Pair; +use pest::prec_climber::{Assoc, Operator, PrecClimber}; +use pest::Parser as PestParser; +use std::borrow::Cow; +use std::collections::BTreeMap; +use std::fmt::{Debug, Display, Formatter, Write}; +use uuid::Uuid; #[repr(u8)] #[derive(Ord, PartialOrd, Eq, PartialEq)] @@ -60,7 +59,7 @@ impl TryFrom for Tag { 253 => Variable, 254 => Apply, 255 => MaxTag, - v => return Err(v) + v => return Err(v), }) } } @@ -91,7 +90,6 @@ impl TryFrom for Tag { // C64Arr = 73, // C128Arr = 74, - #[derive(Clone, PartialEq, Ord, PartialOrd, Eq)] pub enum Value<'a> { // evaluated @@ -107,7 +105,7 @@ pub enum Value<'a> { // not evaluated Variable(Cow<'a, str>), TupleRef(TableId, ColId), - Apply(Cow<'a, str>, Vec>), // TODO optimization: special case for small number of args (esp. 0, 1, 2) + Apply(Cow<'a, str>, Vec>), // TODO optimization: special case for small number of args (esp. 0, 1, 2) FieldAccess(Cow<'a, str>, Box>), IdxAccess(usize, Box>), // cannot exist @@ -116,7 +114,7 @@ pub enum Value<'a> { pub type StaticValue = Value<'static>; -impl <'a> Debug for Value<'a> { +impl<'a> Debug for Value<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "Value {{ {} }}", self) } @@ -133,41 +131,47 @@ impl<'a> Value<'a> { Value::Uuid(u) => Value::from(u), Value::Text(t) => Value::from(t.into_owned()), Value::Variable(s) => Value::Variable(Cow::Owned(s.into_owned())), - Value::List(l) => l.into_iter().map(|v| v.to_static()).collect::>().into(), - Value::Apply(op, args) => { - Value::Apply(Cow::Owned(op.into_owned()), - args.into_iter().map(|v| v.to_static()).collect::>()) - } - Value::Dict(d) => d.into_iter() + Value::List(l) => l + .into_iter() + .map(|v| v.to_static()) + .collect::>() + .into(), + Value::Apply(op, args) => Value::Apply( + Cow::Owned(op.into_owned()), + args.into_iter() + .map(|v| v.to_static()) + .collect::>(), + ), + Value::Dict(d) => d + .into_iter() .map(|(k, v)| (Cow::Owned(k.into_owned()), v.to_static())) - .collect::, StaticValue>>().into(), + .collect::, StaticValue>>() + .into(), Value::EndSentinel => panic!("Cannot process sentinel value"), Value::FieldAccess(field, value) => { Value::FieldAccess(Cow::from(field.into_owned()), value.to_static().into()) } - Value::IdxAccess(idx, value) => { - Value::IdxAccess(idx, value.to_static().into()) - } - Value::TupleRef(tid, cid) => Value::TupleRef(tid, cid) + Value::IdxAccess(idx, value) => Value::IdxAccess(idx, value.to_static().into()), + Value::TupleRef(tid, cid) => Value::TupleRef(tid, cid), } } #[inline] pub fn is_evaluated(&self) -> bool { match self { - Value::Null | - Value::Bool(_) | - Value::Int(_) | - Value::Float(_) | - Value::Uuid(_) | - Value::Text(_) | - Value::EndSentinel => true, + Value::Null + | Value::Bool(_) + | Value::Int(_) + | Value::Float(_) + | Value::Uuid(_) + | Value::Text(_) + | Value::EndSentinel => true, Value::List(l) => l.iter().all(|v| v.is_evaluated()), Value::Dict(d) => d.values().all(|v| v.is_evaluated()), Value::Variable(_) => false, Value::Apply(_, _) => false, Value::FieldAccess(_, _) => false, Value::IdxAccess(_, _) => false, - Value::TupleRef(_, _) => false + Value::TupleRef(_, _) => false, } } #[inline] @@ -182,7 +186,9 @@ impl<'a> Value<'a> { Value::from_pair(pair) } - pub fn extract_relevant_tables>(data: T) -> Result<(Vec, Vec)> { + pub fn extract_relevant_tables>( + data: T, + ) -> Result<(Vec, Vec)> { let mut coll = vec![]; let mut res = Vec::with_capacity(data.size_hint().1.unwrap_or(0)); for v in data { @@ -193,24 +199,23 @@ impl<'a> Value<'a> { fn do_extract_relevant_tables(self, coll: &mut Vec) -> Result { Ok(match self { - v @ (Value::Null | - Value::Bool(_) | - Value::Int(_) | - Value::Float(_) | - Value::Uuid(_) | - Value::Text(_) | - Value::Variable(_)) => v, - Value::List(l) => { - Value::List(l.into_iter() + v @ (Value::Null + | Value::Bool(_) + | Value::Int(_) + | Value::Float(_) + | Value::Uuid(_) + | Value::Text(_) + | Value::Variable(_)) => v, + Value::List(l) => Value::List( + l.into_iter() .map(|v| v.do_extract_relevant_tables(coll)) - .collect::>>()?) - } - Value::Dict(d) => { - Value::Dict(d.into_iter() - .map(|(k, v)| - v.do_extract_relevant_tables(coll).map(|v| (k, v))) - .collect::>>()?) - } + .collect::>>()?, + ), + Value::Dict(d) => Value::Dict( + d.into_iter() + .map(|(k, v)| v.do_extract_relevant_tables(coll).map(|v| (k, v))) + .collect::>>()?, + ), Value::TupleRef(tid, cid) => { let pos = coll.iter().position(|id| id == &tid).unwrap_or_else(|| { let olen = coll.len(); @@ -219,11 +224,12 @@ impl<'a> Value<'a> { }); Value::TupleRef((false, pos).into(), cid) } - Value::Apply(op, args) => { - Value::Apply(op, args.into_iter() + Value::Apply(op, args) => Value::Apply( + op, + args.into_iter() .map(|v| v.do_extract_relevant_tables(coll)) - .collect::>>()?) - } + .collect::>>()?, + ), Value::FieldAccess(field, arg) => { Value::FieldAccess(field, arg.do_extract_relevant_tables(coll)?.into()) } @@ -272,7 +278,6 @@ impl From for StaticValue { } } - impl From> for StaticValue { #[inline] fn from(f: OrderedFloat) -> Self { @@ -315,28 +320,55 @@ impl<'a> From, Value<'a>>> for Value<'a> { } } - 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::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::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_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('"')?; @@ -367,15 +399,18 @@ impl<'a> Display for Value<'a> { } f.write_char('}')?; } - Value::Variable(s) => { - write!(f, "`{}`", s)? - } - Value::EndSentinel => { - write!(f, "Sentinel")? - } + Value::Variable(s) => write!(f, "`{}`", s)?, + Value::EndSentinel => write!(f, "Sentinel")?, Value::Apply(op, args) => { - write!(f, "({} {})", op, - args.iter().map(|v| v.to_string()).collect::>().join(" "))?; + write!( + f, + "({} {})", + op, + args.iter() + .map(|v| v.to_string()) + .collect::>() + .join(" ") + )?; } Value::FieldAccess(field, value) => { write!(f, "(.{} {})", field, value)?; @@ -384,7 +419,14 @@ impl<'a> Display for Value<'a> { write!(f, "(.{} {})", idx, value)?; } Value::TupleRef(tid, cid) => { - write!(f, "#{}{}.{}{}", if tid.in_root { 'G' } else { 'L' }, tid.id, if cid.is_key { 'K' } else { 'D' }, cid.id)?; + write!( + f, + "#{}{}.{}{}", + if tid.in_root { 'G' } else { 'L' }, + tid.id, + if cid.is_key { 'K' } else { 'D' }, + cid.id + )?; } } Ok(()) @@ -398,13 +440,18 @@ lazy_static! { PrecClimber::new(vec![ Operator::new(Rule::op_or, Left), Operator::new(Rule::op_and, Left), - Operator::new(Rule::op_gt, Left) | Operator::new(Rule::op_lt, Left) | Operator::new(Rule::op_ge,Left) | Operator::new(Rule::op_le, Left), + Operator::new(Rule::op_gt, Left) + | Operator::new(Rule::op_lt, Left) + | Operator::new(Rule::op_ge, Left) + | Operator::new(Rule::op_le, Left), Operator::new(Rule::op_mod, Left), Operator::new(Rule::op_eq, Left) | Operator::new(Rule::op_ne, Left), - Operator::new(Rule::op_add, Left) | Operator::new(Rule::op_sub, Left) | Operator::new(Rule::op_str_cat, Left), + Operator::new(Rule::op_add, Left) + | Operator::new(Rule::op_sub, Left) + | Operator::new(Rule::op_str_cat, Left), Operator::new(Rule::op_mul, Left) | Operator::new(Rule::op_div, Left), Operator::new(Rule::op_pow, Assoc::Right), - Operator::new(Rule::op_coalesce, Assoc::Left) + Operator::new(Rule::op_coalesce, Assoc::Left), ]) }; } @@ -432,8 +479,11 @@ pub const METHOD_NOT_NULL: &str = "not_null"; pub const METHOD_CONCAT: &str = "concat"; pub const METHOD_MERGE: &str = "merge"; - -fn build_expr_infix<'a>(lhs: Result>, op: Pair, rhs: Result>) -> Result> { +fn build_expr_infix<'a>( + lhs: Result>, + op: Pair, + rhs: Result>, +) -> Result> { let lhs = lhs?; let rhs = rhs?; let op = match op.as_rule() { @@ -453,12 +503,11 @@ fn build_expr_infix<'a>(lhs: Result>, op: Pair, rhs: Result OP_LE, Rule::op_pow => OP_POW, Rule::op_coalesce => OP_COALESCE, - _ => unreachable!() + _ => unreachable!(), }; Ok(Value::Apply(op.into(), vec![lhs, rhs])) } - fn build_expr_primary(pair: Pair) -> Result { match pair.as_rule() { Rule::expr => build_expr_primary(pair.into_inner().next().unwrap()), @@ -483,7 +532,7 @@ fn build_expr_primary(pair: Pair) -> Result { args.extend(pairs.map(Value::from_pair).collect::>>()?); head = Value::Apply(method_name.into(), args); } - _ => todo!() + _ => todo!(), } } Ok(head) @@ -498,7 +547,7 @@ fn build_expr_primary(pair: Pair) -> Result { Rule::term => return build_expr_primary(p), Rule::negate => OP_NEGATE, Rule::minus => OP_MINUS, - _ => unreachable!() + _ => unreachable!(), }; let term = build_expr_primary(inner.next().unwrap())?; Ok(Value::Apply(op.into(), vec![term])) @@ -508,11 +557,14 @@ fn build_expr_primary(pair: Pair) -> Result { Rule::hex_pos_int => Ok(Value::Int(parse_int(pair.as_str(), 16))), Rule::octo_pos_int => Ok(Value::Int(parse_int(pair.as_str(), 8))), Rule::bin_pos_int => Ok(Value::Int(parse_int(pair.as_str(), 2))), - Rule::dot_float | Rule::sci_float => Ok(Value::Float(pair.as_str().replace('_', "").parse::()?.into())), + Rule::dot_float | Rule::sci_float => Ok(Value::Float( + pair.as_str().replace('_', "").parse::()?.into(), + )), Rule::null => Ok(Value::Null), Rule::boolean => Ok(Value::Bool(pair.as_str() == "true")), - Rule::quoted_string | Rule::s_quoted_string | Rule::raw_string => Ok( - Value::Text(Cow::Owned(parse_string(pair)?))), + Rule::quoted_string | Rule::s_quoted_string | Rule::raw_string => { + Ok(Value::Text(Cow::Owned(parse_string(pair)?))) + } Rule::list => { let mut spread_collected = vec![]; let mut collected = vec![]; @@ -522,8 +574,14 @@ fn build_expr_primary(pair: Pair) -> Result { Rule::spreading => { let el = p.into_inner().next().unwrap(); let to_concat = Value::from_pair(el)?; - if !matches!(to_concat, Value::List(_) | Value::Variable(_) | - Value::IdxAccess(_, _) | Value:: FieldAccess(_, _) | Value::Apply(_, _)) { + if !matches!( + to_concat, + Value::List(_) + | Value::Variable(_) + | Value::IdxAccess(_, _) + | Value::FieldAccess(_, _) + | Value::Apply(_, _) + ) { return Err(CozoError::LogicError("Cannot spread".to_string())); } if !collected.is_empty() { @@ -532,7 +590,7 @@ fn build_expr_primary(pair: Pair) -> Result { } spread_collected.push(to_concat); } - _ => unreachable!() + _ => unreachable!(), } } if spread_collected.is_empty() { @@ -556,15 +614,23 @@ fn build_expr_primary(pair: Pair) -> Result { } Rule::scoped_accessor => { let name = parse_string(p.into_inner().next().unwrap())?; - let val = Value::FieldAccess(name.clone().into(), - Value::Variable("_".into()).into()); + let val = Value::FieldAccess( + name.clone().into(), + Value::Variable("_".into()).into(), + ); collected.insert(name.into(), val); } Rule::spreading => { let el = p.into_inner().next().unwrap(); let to_concat = build_expr_primary(el)?; - if !matches!(to_concat, Value::Dict(_) | Value::Variable(_) | - Value::IdxAccess(_, _) | Value:: FieldAccess(_, _) | Value::Apply(_, _)) { + if !matches!( + to_concat, + Value::Dict(_) + | Value::Variable(_) + | Value::IdxAccess(_, _) + | Value::FieldAccess(_, _) + | Value::Apply(_, _) + ) { return Err(CozoError::LogicError("Cannot spread".to_string())); } if !collected.is_empty() { @@ -573,7 +639,7 @@ fn build_expr_primary(pair: Pair) -> Result { } spread_collected.push(to_concat); } - _ => unreachable!() + _ => unreachable!(), } } @@ -586,12 +652,8 @@ fn build_expr_primary(pair: Pair) -> Result { } Ok(Value::Apply(METHOD_MERGE.into(), spread_collected)) } - Rule::param => { - Ok(Value::Variable(pair.as_str().into())) - } - Rule::ident => { - Ok(Value::Variable(pair.as_str().into())) - } + Rule::param => Ok(Value::Variable(pair.as_str().into())), + Rule::ident => Ok(Value::Variable(pair.as_str().into())), _ => { println!("Unhandled rule {:?}", pair.as_rule()); unimplemented!() @@ -599,7 +661,6 @@ fn build_expr_primary(pair: Pair) -> Result { } } - #[cfg(test)] mod tests { use super::*; @@ -607,7 +668,10 @@ mod tests { use pest::Parser as PestParser; fn parse_expr_from_str>(s: S) -> Result { - let pair = Parser::parse(Rule::expr, s.as_ref()).unwrap().next().unwrap(); + let pair = Parser::parse(Rule::expr, s.as_ref()) + .unwrap() + .next() + .unwrap(); Value::from_pair(pair).map(|v| v.to_static()) } @@ -628,22 +692,55 @@ mod tests { assert_eq!(parse_expr_from_str("1").unwrap(), Value::Int(1)); assert_eq!(parse_expr_from_str("12_3").unwrap(), Value::Int(123)); assert_eq!(parse_expr_from_str("0xaf").unwrap(), Value::Int(0xaf)); - assert_eq!(parse_expr_from_str("0xafcE_f").unwrap(), Value::Int(0xafcef)); - assert_eq!(parse_expr_from_str("0o1234_567").unwrap(), Value::Int(0o1234567)); - assert_eq!(parse_expr_from_str("0o0001234_567").unwrap(), Value::Int(0o1234567)); - assert_eq!(parse_expr_from_str("0b101010").unwrap(), Value::Int(0b101010)); - - assert_eq!(parse_expr_from_str("0.0").unwrap(), Value::Float((0.).into())); - assert_eq!(parse_expr_from_str("10.022_3").unwrap(), Value::Float(10.0223.into())); - assert_eq!(parse_expr_from_str("10.022_3e-100").unwrap(), Value::Float(10.0223e-100.into())); + assert_eq!( + parse_expr_from_str("0xafcE_f").unwrap(), + Value::Int(0xafcef) + ); + assert_eq!( + parse_expr_from_str("0o1234_567").unwrap(), + Value::Int(0o1234567) + ); + assert_eq!( + parse_expr_from_str("0o0001234_567").unwrap(), + Value::Int(0o1234567) + ); + assert_eq!( + parse_expr_from_str("0b101010").unwrap(), + Value::Int(0b101010) + ); + + assert_eq!( + parse_expr_from_str("0.0").unwrap(), + Value::Float((0.).into()) + ); + assert_eq!( + parse_expr_from_str("10.022_3").unwrap(), + Value::Float(10.0223.into()) + ); + assert_eq!( + parse_expr_from_str("10.022_3e-100").unwrap(), + Value::Float(10.0223e-100.into()) + ); assert_eq!(parse_expr_from_str("null").unwrap(), Value::Null); assert_eq!(parse_expr_from_str("true").unwrap(), Value::Bool(true)); assert_eq!(parse_expr_from_str("false").unwrap(), Value::Bool(false)); - assert_eq!(parse_expr_from_str(r#""x \n \ty \"""#).unwrap(), Value::Text(Cow::Borrowed("x \n \ty \""))); - assert_eq!(parse_expr_from_str(r#""x'""#).unwrap(), Value::Text("x'".into())); - assert_eq!(parse_expr_from_str(r#"'"x"'"#).unwrap(), Value::Text(r##""x""##.into())); - assert_eq!(parse_expr_from_str(r#####"r###"x"yz"###"#####).unwrap(), (Value::Text(r##"x"yz"##.into()))); + assert_eq!( + parse_expr_from_str(r#""x \n \ty \"""#).unwrap(), + Value::Text(Cow::Borrowed("x \n \ty \"")) + ); + assert_eq!( + parse_expr_from_str(r#""x'""#).unwrap(), + Value::Text("x'".into()) + ); + assert_eq!( + parse_expr_from_str(r#"'"x"'"#).unwrap(), + Value::Text(r##""x""##.into()) + ); + assert_eq!( + parse_expr_from_str(r#####"r###"x"yz"###"#####).unwrap(), + (Value::Text(r##"x"yz"##.into())) + ); } #[test] @@ -655,4 +752,4 @@ mod tests { println!("{}", parse_expr_from_str("[...a,...b,1,2,...e,3]")?); Ok(()) } -} \ No newline at end of file +}