use crate::engine::error::Result;
use bumpalo::Bump;
use datalogic_rs::{Engine, Logic};
use datavalue::{DataValue, OwnedDataValue};
use log::error;
use std::cell::RefCell;
use std::sync::Arc;
const ARENA_INITIAL_CAPACITY: usize = 128 * 1024;
thread_local! {
static EVAL_ARENA: RefCell<Bump> = RefCell::new(Bump::with_capacity(ARENA_INITIAL_CAPACITY));
}
#[inline]
pub(crate) fn eval_to_owned(
engine: &Engine,
compiled: &Logic,
context: &OwnedDataValue,
) -> std::result::Result<OwnedDataValue, datalogic_rs::Error> {
EVAL_ARENA.with(|cell| {
let mut arena = cell.borrow_mut();
arena.reset();
let r = engine.evaluate(compiled, context, &arena)?;
Ok(r.to_owned())
})
}
#[inline]
pub(crate) fn with_arena<R>(f: impl FnOnce(&Bump) -> R) -> R {
EVAL_ARENA.with(|cell| {
let mut arena = cell.borrow_mut();
arena.reset();
f(&arena)
})
}
pub(crate) struct ArenaContext<'a> {
arena: &'a Bump,
top_keys: Vec<&'a str>,
top_values: Vec<DataValue<'a>>,
depth2: Vec<Option<Depth2Cache<'a>>>,
}
struct Depth2Cache<'a> {
keys: Vec<&'a str>,
values: Vec<DataValue<'a>>,
}
impl<'a> ArenaContext<'a> {
pub fn from_owned(ctx: &OwnedDataValue, arena: &'a Bump) -> Self {
let mut top_keys: Vec<&'a str> = Vec::with_capacity(4);
let mut top_values: Vec<DataValue<'a>> = Vec::with_capacity(4);
let mut depth2: Vec<Option<Depth2Cache<'a>>> = Vec::with_capacity(4);
if let OwnedDataValue::Object(pairs) = ctx {
for (k, v) in pairs {
top_keys.push(arena.alloc_str(k));
match v {
OwnedDataValue::Object(children) => {
let mut d2_keys: Vec<&'a str> = Vec::with_capacity(children.len());
let mut d2_vals: Vec<DataValue<'a>> = Vec::with_capacity(children.len());
for (ck, cv) in children {
d2_keys.push(arena.alloc_str(ck));
d2_vals.push(cv.to_arena(arena));
}
let slice = build_object_slice(arena, &d2_keys, &d2_vals);
top_values.push(DataValue::Object(slice));
depth2.push(Some(Depth2Cache {
keys: d2_keys,
values: d2_vals,
}));
}
_ => {
top_values.push(v.to_arena(arena));
depth2.push(None);
}
}
}
}
Self {
arena,
top_keys,
top_values,
depth2,
}
}
pub fn as_data_value(&self) -> DataValue<'a> {
let slice = build_object_slice(self.arena, &self.top_keys, &self.top_values);
DataValue::Object(slice)
}
#[inline]
pub fn arena(&self) -> &'a Bump {
self.arena
}
pub fn apply_mutation_parts(
&mut self,
owned_ctx: &mut OwnedDataValue,
parts: &[Arc<str>],
apply: impl FnOnce(&mut OwnedDataValue),
) {
apply(owned_ctx);
self.refresh_after_write_parts(owned_ctx, parts);
}
pub fn refresh_for_path(&mut self, owned_ctx: &OwnedDataValue, path: &str) {
self.refresh_after_write(owned_ctx, path);
}
fn refresh_after_write_parts(&mut self, owned_ctx: &OwnedDataValue, parts: &[Arc<str>]) {
let top_raw: &str = match parts.first() {
Some(p) if !p.is_empty() => p,
_ => {
self.rebuild_all_from(owned_ctx);
return;
}
};
let top = top_raw.strip_prefix('#').unwrap_or(top_raw);
fn strip<'p>(p: &'p Arc<str>) -> &'p str {
let s: &'p str = p;
s.strip_prefix('#').unwrap_or(s)
}
let depth2_key: Option<&str> = parts.get(1).map(strip);
let depth3_key: Option<&str> = parts.get(2).map(strip);
self.refresh_after_write_inner(owned_ctx, top, depth2_key, depth3_key);
}
fn refresh_after_write(&mut self, owned_ctx: &OwnedDataValue, path: &str) {
let mut parts = path.split('.');
let top_raw = match parts.next() {
Some(p) if !p.is_empty() => p,
_ => {
self.rebuild_all_from(owned_ctx);
return;
}
};
let top = top_raw.strip_prefix('#').unwrap_or(top_raw);
let depth2_key = parts.next().map(|p| p.strip_prefix('#').unwrap_or(p));
let depth3_key = parts.next().map(|p| p.strip_prefix('#').unwrap_or(p));
self.refresh_after_write_inner(owned_ctx, top, depth2_key, depth3_key);
}
fn refresh_after_write_inner(
&mut self,
owned_ctx: &OwnedDataValue,
top: &str,
depth2_key: Option<&str>,
_depth3_key: Option<&str>,
) {
let OwnedDataValue::Object(owned_pairs) = owned_ctx else {
self.rebuild_all_from(owned_ctx);
return;
};
let owned_top_val = owned_pairs.iter().find(|(k, _)| k == top).map(|(_, v)| v);
let top_idx = self.top_keys.iter().position(|k| *k == top);
match (owned_top_val, top_idx) {
(None, Some(idx)) => {
self.top_keys.remove(idx);
self.top_values.remove(idx);
self.depth2.remove(idx);
}
(Some(new_val), idx_opt) => {
let idx = match idx_opt {
Some(i) => i,
None => {
self.top_keys.push(self.arena.alloc_str(top));
self.top_values.push(DataValue::Null);
self.depth2.push(None);
self.top_keys.len() - 1
}
};
match (new_val, depth2_key, &mut self.depth2[idx]) {
(OwnedDataValue::Object(new_children), Some(child_key), Some(d2)) => {
if let Some(new_child) = new_children
.iter()
.find(|(k, _)| k == child_key)
.map(|(_, v)| v)
{
let child_arena = new_child.to_arena(self.arena);
if let Some(pos) = d2.keys.iter().position(|k| *k == child_key) {
d2.values[pos] = child_arena;
} else {
d2.keys.push(self.arena.alloc_str(child_key));
d2.values.push(child_arena);
}
if d2.keys.len() != new_children.len() {
self.rebuild_top_slot(owned_top_val.unwrap(), idx);
return;
}
} else {
if let Some(pos) = d2.keys.iter().position(|k| *k == child_key) {
d2.keys.remove(pos);
d2.values.remove(pos);
}
}
let slice = build_object_slice(self.arena, &d2.keys, &d2.values);
self.top_values[idx] = DataValue::Object(slice);
}
_ => {
self.rebuild_top_slot(new_val, idx);
}
}
}
(None, None) => { }
}
}
fn rebuild_top_slot(&mut self, owned: &OwnedDataValue, idx: usize) {
match owned {
OwnedDataValue::Object(children) => {
let mut d2_keys: Vec<&'a str> = Vec::with_capacity(children.len());
let mut d2_vals: Vec<DataValue<'a>> = Vec::with_capacity(children.len());
for (ck, cv) in children {
d2_keys.push(self.arena.alloc_str(ck));
d2_vals.push(cv.to_arena(self.arena));
}
let slice = build_object_slice(self.arena, &d2_keys, &d2_vals);
self.top_values[idx] = DataValue::Object(slice);
self.depth2[idx] = Some(Depth2Cache {
keys: d2_keys,
values: d2_vals,
});
}
_ => {
self.top_values[idx] = owned.to_arena(self.arena);
self.depth2[idx] = None;
}
}
}
fn rebuild_all_from(&mut self, ctx: &OwnedDataValue) {
let rebuilt = ArenaContext::from_owned(ctx, self.arena);
self.top_keys = rebuilt.top_keys;
self.top_values = rebuilt.top_values;
self.depth2 = rebuilt.depth2;
}
}
fn build_object_slice<'a>(
arena: &'a Bump,
keys: &[&'a str],
values: &[DataValue<'a>],
) -> &'a [(&'a str, DataValue<'a>)] {
debug_assert_eq!(keys.len(), values.len());
arena.alloc_slice_fill_iter(keys.iter().zip(values.iter()).map(|(k, v)| (*k, *v)))
}
pub fn evaluate_condition(
engine: &Engine,
compiled_condition: Option<&Arc<Logic>>,
context: &OwnedDataValue,
) -> Result<bool> {
match compiled_condition {
Some(compiled) => match eval_to_owned(engine, compiled, context) {
Ok(value) => Ok(matches!(value, OwnedDataValue::Bool(true))),
Err(e) => {
error!("Failed to evaluate condition: {:?}", e);
Ok(false)
}
},
None => Ok(true),
}
}
pub fn evaluate_condition_in_arena(
engine: &Engine,
compiled_condition: Option<&Arc<Logic>>,
ctx: DataValue<'_>,
arena: &Bump,
) -> Result<bool> {
match compiled_condition {
Some(compiled) => match engine.evaluate(compiled, ctx, arena) {
Ok(value) => Ok(matches!(value, DataValue::Bool(true))),
Err(e) => {
error!("Failed to evaluate condition: {:?}", e);
Ok(false)
}
},
None => Ok(true),
}
}