use super::{array_get, array_len, current_data};
use crate::Result;
use crate::arena::{ContextStack, DataValue};
use crate::node::PathSegment;
use crate::operators::eager::Cx;
use crate::operators::extract::{Any, RestArgs};
#[inline]
pub(crate) fn evaluate_exists_compiled<'a>(
scope_level: u32,
segments: &[PathSegment],
binding: crate::node::ScopeBinding,
ctx: &mut ContextStack<'a>,
) -> Result<&'a DataValue<'a>> {
super::debug_check_binding(binding, scope_level, ctx);
if binding == crate::node::ScopeBinding::Root {
let found = segments.is_empty()
|| crate::arena::value::traverse_segments(ctx.root_input(), segments).is_some();
return Ok(crate::arena::singletons::singleton_bool(found));
}
let aref = match binding {
crate::node::ScopeBinding::Current => ctx.current(),
_ => match ctx.get_at_level(scope_level as isize) {
Some(f) => f,
None => return Ok(crate::arena::singletons::singleton_false()),
},
};
let av = aref.data();
let found =
segments.is_empty() || crate::arena::value::traverse_segments(av, segments).is_some();
Ok(crate::arena::singletons::singleton_bool(found))
}
#[inline]
fn object_contains(av: &DataValue<'_>, key: &str) -> bool {
match av {
DataValue::Object(pairs) => crate::arena::value::object_lookup_field(pairs, key).is_some(),
_ => false,
}
}
#[inline]
fn object_step<'a>(av: &'a DataValue<'a>, key: &str) -> Option<&'a DataValue<'a>> {
match av {
DataValue::Object(pairs) => crate::arena::value::object_lookup_field(pairs, key),
_ => None,
}
}
#[inline]
pub(crate) fn exists<'a>(
cx: &mut Cx<'_, 'a>,
first: &'a DataValue<'a>,
rest: RestArgs<'a, Any>,
) -> Result<bool> {
let cur = current_data(cx.ctx);
if rest.is_empty() {
if let Some(s) = first.as_str() {
return Ok(object_contains(cur, s));
}
let Some(arr_len) = array_len(first) else {
return Ok(false);
};
if arr_len == 0 {
return Ok(false);
}
let mut walk = cur;
for i in 0..arr_len {
let elem =
array_get(first, i).unwrap_or_else(|| crate::arena::singletons::singleton_null());
let Some(seg) = elem.as_str() else {
return Ok(false);
};
if i == arr_len - 1 {
return Ok(object_contains(walk, seg));
}
match object_step(walk, seg) {
Some(next) => walk = next,
None => return Ok(false),
}
}
return Ok(true);
}
let Some(mut prev) = first.as_str() else {
return Ok(false);
};
let mut walk = Some(cur);
for i in 0..rest.len() {
let Some(seg) = rest.get(i, cx)?.as_str() else {
return Ok(false);
};
walk = walk.and_then(|w| object_step(w, prev));
prev = seg;
}
Ok(walk.is_some_and(|w| object_contains(w, prev)))
}