|
|
@ -27,7 +27,7 @@
|
|
|
|
#[cfg(test)]
|
|
|
|
#[cfg(test)]
|
|
|
|
use crate::engine::ql::ast::InplaceData;
|
|
|
|
use crate::engine::ql::ast::InplaceData;
|
|
|
|
use {
|
|
|
|
use {
|
|
|
|
super::parse_entity,
|
|
|
|
super::{parse_entity, read_ident},
|
|
|
|
crate::{
|
|
|
|
crate::{
|
|
|
|
engine::{
|
|
|
|
engine::{
|
|
|
|
memory::DataType,
|
|
|
|
memory::DataType,
|
|
|
@ -39,14 +39,105 @@ use {
|
|
|
|
},
|
|
|
|
},
|
|
|
|
util::{compiler, MaybeInit},
|
|
|
|
util::{compiler, MaybeInit},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
core::mem::{discriminant, Discriminant},
|
|
|
|
core::{
|
|
|
|
std::collections::HashMap,
|
|
|
|
cmp,
|
|
|
|
|
|
|
|
mem::{discriminant, Discriminant},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
std::{
|
|
|
|
|
|
|
|
collections::HashMap,
|
|
|
|
|
|
|
|
time::{Duration, SystemTime, UNIX_EPOCH},
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
uuid::Uuid,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
Impls for insert
|
|
|
|
Impls for insert
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub const T_UUIDSTR: &str = "4593264b-0231-43e9-b0aa-50784f14e204";
|
|
|
|
|
|
|
|
pub const T_UUIDBIN: &[u8] = T_UUIDSTR.as_bytes();
|
|
|
|
|
|
|
|
pub const T_TIMESEC: u64 = 1673187839_u64;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type ProducerFn = fn() -> DataType;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// base
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
fn pfnbase_time() -> Duration {
|
|
|
|
|
|
|
|
if cfg!(debug_assertions) {
|
|
|
|
|
|
|
|
Duration::from_secs(T_TIMESEC)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
SystemTime::now().duration_since(UNIX_EPOCH).unwrap()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
fn pfnbase_uuid() -> Uuid {
|
|
|
|
|
|
|
|
if cfg!(debug_assertions) {
|
|
|
|
|
|
|
|
Uuid::parse_str(T_UUIDSTR).unwrap()
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
Uuid::new_v4()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// impl
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
fn pfn_timesec() -> DataType {
|
|
|
|
|
|
|
|
DataType::UnsignedInt(pfnbase_time().as_secs())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
fn pfn_uuidstr() -> DataType {
|
|
|
|
|
|
|
|
DataType::String(pfnbase_uuid().to_string().into_boxed_str())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
fn pfn_uuidbin() -> DataType {
|
|
|
|
|
|
|
|
DataType::Binary(pfnbase_uuid().as_bytes().to_vec().into_boxed_slice())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static PRODUCER_G: [u8; 4] = [0, 2, 3, 0];
|
|
|
|
|
|
|
|
static PRODUCER_F: [(&[u8], ProducerFn); 3] = [
|
|
|
|
|
|
|
|
(b"uuidstr", pfn_uuidstr),
|
|
|
|
|
|
|
|
(b"uuidbin", pfn_uuidbin),
|
|
|
|
|
|
|
|
(b"timesec", pfn_timesec),
|
|
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
const MAGIC_1: [u8; 7] = *b"cp21rLd";
|
|
|
|
|
|
|
|
const MAGIC_2: [u8; 7] = *b"zS8zgaK";
|
|
|
|
|
|
|
|
const MAGIC_L: usize = MAGIC_1.len();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
fn hashf(key: &[u8], m: &[u8]) -> u32 {
|
|
|
|
|
|
|
|
let mut i = 0;
|
|
|
|
|
|
|
|
let mut s = 0;
|
|
|
|
|
|
|
|
while i < key.len() {
|
|
|
|
|
|
|
|
s += m[(i % MAGIC_L) as usize] as u32 * key[i] as u32;
|
|
|
|
|
|
|
|
i += 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
s % PRODUCER_G.len() as u32
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
fn hashp(key: &[u8]) -> u32 {
|
|
|
|
|
|
|
|
(PRODUCER_G[hashf(key, &MAGIC_1) as usize] + PRODUCER_G[hashf(key, &MAGIC_2) as usize]) as u32
|
|
|
|
|
|
|
|
% PRODUCER_G.len() as u32
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
fn ldfunc(func: &[u8]) -> Option<ProducerFn> {
|
|
|
|
|
|
|
|
let ph = hashp(func) as usize;
|
|
|
|
|
|
|
|
let min = cmp::min(ph, PRODUCER_F.len() - 1);
|
|
|
|
|
|
|
|
let data = PRODUCER_F[min as usize];
|
|
|
|
|
|
|
|
if data.0 == func {
|
|
|
|
|
|
|
|
Some(data.1)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
None
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
fn ldfunc_exists(func: &[u8]) -> bool {
|
|
|
|
|
|
|
|
ldfunc(func).is_some()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
unsafe fn ldfunc_unchecked(func: &[u8]) -> ProducerFn {
|
|
|
|
|
|
|
|
let ph = hashp(func) as usize;
|
|
|
|
|
|
|
|
debug_assert_eq!(PRODUCER_F[ph as usize].0, func);
|
|
|
|
|
|
|
|
PRODUCER_F[ph as usize].1
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// ## Panics
|
|
|
|
/// ## Panics
|
|
|
|
/// - If tt length is less than 1
|
|
|
|
/// - If tt length is less than 1
|
|
|
|
pub(super) fn parse_list<'a, Qd: QueryData<'a>>(
|
|
|
|
pub(super) fn parse_list<'a, Qd: QueryData<'a>>(
|
|
|
@ -58,17 +149,15 @@ pub(super) fn parse_list<'a, Qd: QueryData<'a>>(
|
|
|
|
let mut overall_dscr = None;
|
|
|
|
let mut overall_dscr = None;
|
|
|
|
let mut prev_nlist_dscr = None;
|
|
|
|
let mut prev_nlist_dscr = None;
|
|
|
|
while state.not_exhausted() && state.okay() && !stop {
|
|
|
|
while state.not_exhausted() && state.okay() && !stop {
|
|
|
|
let d = match state.read() {
|
|
|
|
let d = match state.fw_read() {
|
|
|
|
tok if state.can_read_lit_from(tok) => {
|
|
|
|
tok if state.can_read_lit_from(tok) => {
|
|
|
|
let r = unsafe {
|
|
|
|
let r = unsafe {
|
|
|
|
// UNSAFE(@ohsayan): the if guard guarantees correctness
|
|
|
|
// UNSAFE(@ohsayan): the if guard guarantees correctness
|
|
|
|
DataType::clone_from_litir(state.read_cursor_lit_unchecked())
|
|
|
|
DataType::clone_from_litir(state.read_lit_unchecked_from(tok))
|
|
|
|
};
|
|
|
|
};
|
|
|
|
state.cursor_ahead();
|
|
|
|
|
|
|
|
r
|
|
|
|
r
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Token![open []] => {
|
|
|
|
Token![open []] => {
|
|
|
|
state.cursor_ahead();
|
|
|
|
|
|
|
|
// a nested list
|
|
|
|
// a nested list
|
|
|
|
let mut nested_list = Vec::new();
|
|
|
|
let mut nested_list = Vec::new();
|
|
|
|
let nlist_dscr = parse_list(state, &mut nested_list);
|
|
|
|
let nlist_dscr = parse_list(state, &mut nested_list);
|
|
|
@ -83,7 +172,18 @@ pub(super) fn parse_list<'a, Qd: QueryData<'a>>(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataType::List(nested_list)
|
|
|
|
DataType::List(nested_list)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Token![@] if state.cursor_signature_match_fn_arity0_rounded() => match unsafe {
|
|
|
|
|
|
|
|
// UNSAFE(@ohsayan): Just verified at guard
|
|
|
|
|
|
|
|
handle_func_sub(state)
|
|
|
|
|
|
|
|
} {
|
|
|
|
|
|
|
|
Some(value) => value,
|
|
|
|
|
|
|
|
None => {
|
|
|
|
|
|
|
|
state.poison();
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
_ => {
|
|
|
|
|
|
|
|
state.cursor_back();
|
|
|
|
state.poison();
|
|
|
|
state.poison();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -100,6 +200,15 @@ pub(super) fn parse_list<'a, Qd: QueryData<'a>>(
|
|
|
|
overall_dscr
|
|
|
|
overall_dscr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[inline(always)]
|
|
|
|
|
|
|
|
/// ## Safety
|
|
|
|
|
|
|
|
/// - Cursor must match arity(0) function signature
|
|
|
|
|
|
|
|
unsafe fn handle_func_sub<'a, Qd: QueryData<'a>>(state: &mut State<'a, Qd>) -> Option<DataType> {
|
|
|
|
|
|
|
|
let func = read_ident(state.fw_read());
|
|
|
|
|
|
|
|
state.cursor_ahead_by(2); // skip tt:paren
|
|
|
|
|
|
|
|
ldfunc(func).map(move |f| f())
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
#[cfg(test)]
|
|
|
|
pub fn parse_list_full<'a>(tok: &'a [Token], qd: impl QueryData<'a>) -> Option<Vec<DataType>> {
|
|
|
|
pub fn parse_list_full<'a>(tok: &'a [Token], qd: impl QueryData<'a>) -> Option<Vec<DataType>> {
|
|
|
|
let mut l = Vec::new();
|
|
|
|
let mut l = Vec::new();
|
|
|
@ -118,27 +227,33 @@ pub(super) fn parse_data_tuple_syntax<'a, Qd: QueryData<'a>>(
|
|
|
|
state.cursor_ahead_if(stop);
|
|
|
|
state.cursor_ahead_if(stop);
|
|
|
|
let mut data = Vec::new();
|
|
|
|
let mut data = Vec::new();
|
|
|
|
while state.not_exhausted() && state.okay() && !stop {
|
|
|
|
while state.not_exhausted() && state.okay() && !stop {
|
|
|
|
match state.read() {
|
|
|
|
match state.fw_read() {
|
|
|
|
tok if state.can_read_lit_from(tok) => {
|
|
|
|
tok if state.can_read_lit_from(tok) => unsafe {
|
|
|
|
unsafe {
|
|
|
|
// UNSAFE(@ohsayan): if guard guarantees correctness
|
|
|
|
// UNSAFE(@ohsayan): if guard guarantees correctness
|
|
|
|
data.push(Some(DataType::clone_from_litir(
|
|
|
|
data.push(Some(DataType::clone_from_litir(
|
|
|
|
state.read_lit_unchecked_from(tok),
|
|
|
|
state.read_cursor_lit_unchecked(),
|
|
|
|
)))
|
|
|
|
)))
|
|
|
|
},
|
|
|
|
}
|
|
|
|
Token![open []] if state.not_exhausted() => {
|
|
|
|
state.cursor_ahead();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Token![open []] if state.remaining() >= 2 => {
|
|
|
|
|
|
|
|
state.cursor_ahead();
|
|
|
|
|
|
|
|
let mut l = Vec::new();
|
|
|
|
let mut l = Vec::new();
|
|
|
|
let _ = parse_list(state, &mut l);
|
|
|
|
let _ = parse_list(state, &mut l);
|
|
|
|
data.push(Some(l.into()));
|
|
|
|
data.push(Some(l.into()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Token![null] => {
|
|
|
|
Token![null] => {
|
|
|
|
state.cursor_ahead();
|
|
|
|
|
|
|
|
data.push(None);
|
|
|
|
data.push(None);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Token![@] if state.cursor_signature_match_fn_arity0_rounded() => match unsafe {
|
|
|
|
|
|
|
|
// UNSAFE(@ohsayan): Just verified at guard
|
|
|
|
|
|
|
|
handle_func_sub(state)
|
|
|
|
|
|
|
|
} {
|
|
|
|
|
|
|
|
Some(value) => data.push(Some(value)),
|
|
|
|
|
|
|
|
None => {
|
|
|
|
|
|
|
|
state.poison();
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
_ => {
|
|
|
|
|
|
|
|
state.cursor_back();
|
|
|
|
state.poison();
|
|
|
|
state.poison();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -169,31 +284,40 @@ pub(super) fn parse_data_map_syntax<'a, Qd: QueryData<'a>>(
|
|
|
|
state.cursor_ahead_if(stop);
|
|
|
|
state.cursor_ahead_if(stop);
|
|
|
|
let mut data = HashMap::with_capacity(2);
|
|
|
|
let mut data = HashMap::with_capacity(2);
|
|
|
|
while state.has_remaining(3) && state.okay() && !stop {
|
|
|
|
while state.has_remaining(3) && state.okay() && !stop {
|
|
|
|
let field = state.read();
|
|
|
|
let field = state.fw_read();
|
|
|
|
let colon = state.read_ahead(1);
|
|
|
|
let colon = state.fw_read();
|
|
|
|
let expr = state.read_ahead(2);
|
|
|
|
let expr = state.fw_read();
|
|
|
|
state.poison_if_not(Token![:].eq(colon));
|
|
|
|
state.poison_if_not(Token![:].eq(colon));
|
|
|
|
match (field, expr) {
|
|
|
|
match (field, expr) {
|
|
|
|
(Token::Ident(id), tok) if state.can_read_lit_from(tok) => {
|
|
|
|
(Token::Ident(id), tok) if state.can_read_lit_from(tok) => {
|
|
|
|
state.cursor_ahead_by(2); // ident + colon
|
|
|
|
|
|
|
|
let ldata = Some(DataType::clone_from_litir(unsafe {
|
|
|
|
let ldata = Some(DataType::clone_from_litir(unsafe {
|
|
|
|
// UNSAFE(@ohsayan): The if guard guarantees correctness
|
|
|
|
// UNSAFE(@ohsayan): The if guard guarantees correctness
|
|
|
|
state.read_cursor_lit_unchecked()
|
|
|
|
state.read_lit_unchecked_from(tok)
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
state.cursor_ahead();
|
|
|
|
|
|
|
|
state.poison_if_not(data.insert(*id, ldata).is_none());
|
|
|
|
state.poison_if_not(data.insert(*id, ldata).is_none());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(Token::Ident(id), Token![null]) => {
|
|
|
|
(Token::Ident(id), Token![null]) => {
|
|
|
|
state.cursor_ahead_by(3);
|
|
|
|
|
|
|
|
state.poison_if_not(data.insert(*id, None).is_none());
|
|
|
|
state.poison_if_not(data.insert(*id, None).is_none());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(Token::Ident(id), Token![open []]) if state.remaining() >= 4 => {
|
|
|
|
(Token::Ident(id), Token![open []]) if state.not_exhausted() => {
|
|
|
|
state.cursor_ahead_by(3);
|
|
|
|
|
|
|
|
let mut l = Vec::new();
|
|
|
|
let mut l = Vec::new();
|
|
|
|
let _ = parse_list(state, &mut l);
|
|
|
|
let _ = parse_list(state, &mut l);
|
|
|
|
state.poison_if_not(data.insert(*id, Some(l.into())).is_none());
|
|
|
|
state.poison_if_not(data.insert(*id, Some(l.into())).is_none());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
(Token::Ident(id), Token![@]) if state.cursor_signature_match_fn_arity0_rounded() => {
|
|
|
|
|
|
|
|
match unsafe {
|
|
|
|
|
|
|
|
// UNSAFE(@ohsayan): Just verified at guard
|
|
|
|
|
|
|
|
handle_func_sub(state)
|
|
|
|
|
|
|
|
} {
|
|
|
|
|
|
|
|
Some(value) => state.poison_if_not(data.insert(*id, Some(value)).is_none()),
|
|
|
|
|
|
|
|
None => {
|
|
|
|
|
|
|
|
state.poison();
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
_ => {
|
|
|
|
|
|
|
|
state.cursor_back_by(3);
|
|
|
|
state.poison();
|
|
|
|
state.poison();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -271,10 +395,8 @@ impl<'a> InsertStatement<'a> {
|
|
|
|
// entity
|
|
|
|
// entity
|
|
|
|
let mut entity = MaybeInit::uninit();
|
|
|
|
let mut entity = MaybeInit::uninit();
|
|
|
|
parse_entity(state, &mut entity);
|
|
|
|
parse_entity(state, &mut entity);
|
|
|
|
let what_data = state.read();
|
|
|
|
|
|
|
|
state.cursor_ahead(); // ignore errors for now
|
|
|
|
|
|
|
|
let mut data = None;
|
|
|
|
let mut data = None;
|
|
|
|
match what_data {
|
|
|
|
match state.fw_read() {
|
|
|
|
Token![() open] if state.not_exhausted() => {
|
|
|
|
Token![() open] if state.not_exhausted() => {
|
|
|
|
let this_data = parse_data_tuple_syntax(state);
|
|
|
|
let this_data = parse_data_tuple_syntax(state);
|
|
|
|
data = Some(InsertData::Ordered(this_data));
|
|
|
|
data = Some(InsertData::Ordered(this_data));
|
|
|
|