anathema-value-resolver 0.2.11

Anathema value resolver
Documentation
use crate::ValueKind;

pub(super) fn contains<'bp>(args: &[ValueKind<'bp>]) -> ValueKind<'bp> {
    if args.len() != 2 {
        return ValueKind::Null;
    }

    let haystack = &args[0];
    let needle = &args[1];

    match haystack {
        ValueKind::Str(string) => match needle {
            ValueKind::Str(other) => ValueKind::Bool(string.as_ref().contains(other.as_ref())),
            _ => ValueKind::Bool(false),
        },
        ValueKind::List(elements) => elements
            .iter()
            .find_map(|el| needle.eq(el).then_some(ValueKind::Bool(true)))
            .unwrap_or(ValueKind::Bool(false)),
        ValueKind::DynList(haystack) => {
            let Some(haystack) = haystack.as_state() else { return ValueKind::Bool(false) };
            let Some(haystack) = haystack.as_any_list() else { return ValueKind::Bool(false) };
            for val in haystack.iter() {
                if needle.compare_pending(val) {
                    return ValueKind::Bool(true);
                }
            }
            ValueKind::Bool(false)
        }
        _ => ValueKind::Null,
    }
}

#[cfg(test)]
mod test {
    use anathema_state::{List, Value};

    use super::*;
    use crate::functions::test::{list, value};

    #[test]
    fn list_contains_int() {
        let haystack = list([1, 2]);
        let needle = value(2);
        let args = [haystack, needle];
        assert!(matches!(contains(&args), ValueKind::Bool(true)));
    }

    #[test]
    fn list_contains_list() {
        let haystack = list([list([1, 2]), list([4, 8])]);
        let needle = list([4, 8]);
        let args = [haystack, needle];
        assert!(matches!(contains(&args), ValueKind::Bool(true)));
    }

    #[test]
    fn dyn_list_contains() {
        let list = Value::new(List::from_iter(0..10));
        let haystack = ValueKind::DynList(list.reference());
        let needle = value(0);
        let args = [haystack, needle];
        contains(&args);
        assert!(matches!(contains(&args), ValueKind::Bool(true)));
    }

    #[test]
    fn static_string_contains() {
        let haystack = value("like looking for a needle in a");
        let needle = value("needle");
        let args = [haystack, needle];
        assert!(matches!(contains(&args), ValueKind::Bool(true)));
    }

    #[test]
    fn dyn_list_of_lists_contains() {
        let haystack = List::from_iter(vec![List::from_iter(0..10), List::from_iter(100..110)]);
        let haystack = Value::new(haystack);
        let haystack = ValueKind::DynList(haystack.reference());
        let needle = List::from_iter(100..110);
        let needle = Value::new(needle);
        let needle = ValueKind::DynList(needle.reference());
        let args = [haystack, needle];
        let result = contains(&args);
        assert!(matches!(result, ValueKind::Bool(true)));
    }
}