use cel::{Context, ResolveResult, objects::Value};
use std::sync::Arc;
use crate::value_ops::val_eq;
pub fn register(ctx: &mut Context<'_>) {
ctx.add_function("sets.contains", sets_contains);
ctx.add_function("sets.equivalent", sets_equivalent);
ctx.add_function("sets.intersects", sets_intersects);
}
fn sets_contains(a: Arc<Vec<Value>>, b: Arc<Vec<Value>>) -> ResolveResult {
for item in b.iter() {
if !a.iter().any(|x| val_eq(x, item)) {
return Ok(Value::Bool(false));
}
}
Ok(Value::Bool(true))
}
fn sets_equivalent(a: Arc<Vec<Value>>, b: Arc<Vec<Value>>) -> ResolveResult {
for item in b.iter() {
if !a.iter().any(|x| val_eq(x, item)) {
return Ok(Value::Bool(false));
}
}
for item in a.iter() {
if !b.iter().any(|x| val_eq(x, item)) {
return Ok(Value::Bool(false));
}
}
Ok(Value::Bool(true))
}
fn sets_intersects(a: Arc<Vec<Value>>, b: Arc<Vec<Value>>) -> ResolveResult {
for item in a.iter() {
if b.iter().any(|x| val_eq(x, item)) {
return Ok(Value::Bool(true));
}
}
Ok(Value::Bool(false))
}
#[cfg(test)]
mod tests {
use super::*;
use cel::Program;
fn eval(expr: &str) -> Value {
let mut ctx = Context::default();
register(&mut ctx);
Program::compile(expr).unwrap().execute(&ctx).unwrap()
}
#[test]
fn test_contains() {
assert_eq!(eval("sets.contains([1, 2, 3], [1, 2])"), Value::Bool(true));
assert_eq!(eval("sets.contains([1, 2, 3], [4])"), Value::Bool(false));
assert_eq!(eval("sets.contains([1, 2, 3], [])"), Value::Bool(true));
}
#[test]
fn test_equivalent() {
assert_eq!(eval("sets.equivalent([1, 2, 3], [3, 2, 1])"), Value::Bool(true));
assert_eq!(eval("sets.equivalent([1, 2, 2], [1, 2])"), Value::Bool(true));
assert_eq!(eval("sets.equivalent([1, 2], [1, 3])"), Value::Bool(false));
}
#[test]
fn test_intersects() {
assert_eq!(eval("sets.intersects([1, 2], [2, 3])"), Value::Bool(true));
assert_eq!(eval("sets.intersects([1, 2], [3, 4])"), Value::Bool(false));
assert_eq!(eval("sets.intersects([], [1])"), Value::Bool(false));
}
#[test]
fn test_equivalent_empty() {
assert_eq!(eval("sets.equivalent([], [])"), Value::Bool(true));
}
#[test]
fn test_intersects_both_empty() {
assert_eq!(eval("sets.intersects([], [])"), Value::Bool(false));
}
#[test]
fn test_contains_strings() {
assert_eq!(
eval("sets.contains(['a', 'b', 'c'], ['a', 'c'])"),
Value::Bool(true)
);
assert_eq!(eval("sets.contains(['a', 'b'], ['d'])"), Value::Bool(false));
}
#[test]
fn test_intersects_strings() {
assert_eq!(eval("sets.intersects(['a', 'b'], ['b', 'c'])"), Value::Bool(true));
}
#[test]
fn test_contains_negated() {
assert_eq!(eval("!sets.contains([1], [2])"), Value::Bool(true));
}
#[test]
fn test_equivalent_negated() {
assert_eq!(eval("!sets.equivalent([2, 1], [1])"), Value::Bool(true));
}
#[test]
fn test_intersects_negated() {
assert_eq!(eval("!sets.intersects([], [])"), Value::Bool(true));
assert_eq!(eval("!sets.intersects([1], [2])"), Value::Bool(true));
}
#[test]
fn test_contains_empty_superset() {
assert_eq!(eval("sets.contains([], [])"), Value::Bool(true));
}
#[test]
fn test_contains_with_duplicates() {
assert_eq!(eval("sets.contains([1, 1, 2, 2, 3], [1, 2])"), Value::Bool(true));
}
#[test]
fn test_equivalent_with_duplicates() {
assert_eq!(eval("sets.equivalent([1, 1, 2], [2, 2, 1])"), Value::Bool(true));
}
}