1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
use super::GoalEnum;
use crate::domains::Domain;
use crate::state::{Fork, State};
use std::iter::repeat;

#[derive(Debug)]
pub(super) struct Any<'a, D>
where
    D: Domain<'a>,
{
    pub(super) goals: Vec<GoalEnum<'a, D>>,
}

impl<'a, D> Fork<'a, D> for Any<'a, D>
where
    D: Domain<'a>,
{
    fn fork(&self, state: State<'a, D>) -> crate::state::StateIter<'a, D> {
        let goals = self.goals.clone().into_iter();
        let states = repeat(state);
        Box::new(goals.zip(states).flat_map(|(g, s)| g.apply(s).into_iter()))
    }
}

/// Create a [goal](crate::goals::Goal) that yields a state for every successful
/// sub-goal.
///
/// This is essentially an "OR" operation on a vector of goals. It may yield
/// from zero to as many [resolved states](crate::state::ResolvedState) as there
/// are sub-goals.
///
/// # Examples
///
/// Each successful goal will yield a different result:
/// ```
/// use canrun::{Goal, any, unify, var};
/// use canrun::example::I32;
///
/// let x = var();
/// let goal: Goal<I32> = any![unify(x, 1), unify(x, 2), unify(x, 3)];
/// let result: Vec<_> = goal.query(x).collect();
/// assert_eq!(result, vec![1, 2, 3])
/// ```
///
/// One failing goal will not cause the other to fail:
/// ```
/// # use canrun::{Goal, any, unify, var};
/// # use canrun::example::I32;
/// # let x = var();
/// let goal: Goal<I32> = any!(unify(1, 2), unify(x, 2), unify(x, 3));
/// let result: Vec<_> = goal.query(x).collect();
/// assert_eq!(result, vec![2, 3])
/// ```
///
/// All goals can fail, leading to no results:
/// ```
/// # use canrun::{Goal, any, unify, var};
/// # use canrun::example::I32;
/// # let x = var();
/// let goal: Goal<I32> = any!(unify(6, 5), unify(42, 0), unify(1, 2));
/// let result: Vec<_> = goal.query(x).collect();
/// assert_eq!(result, vec![]) // Empty result
/// ```
#[macro_export]
macro_rules! any {
    ($($item:expr),* $(,)?) => {
        canrun::Goal::any(vec![$($item),*])
    };
}
pub use any;

#[cfg(test)]
mod tests {
    use super::any;
    use crate as canrun;
    use crate::example::I32;
    use crate::goals::unify::unify;
    use crate::goals::Goal;
    use crate::util;
    use crate::value::var;

    #[test]
    fn both_succeeds() {
        let x = var();
        let goal: Goal<I32> = any![unify(x, 5), unify(x, 7)];
        let results = util::goal_resolves_to(goal, x);
        assert_eq!(results, vec![5, 7]);
    }

    #[test]
    fn one_succeeds() {
        let x = var();
        let bad: Goal<I32> = unify(6, 5);

        let first = util::goal_resolves_to(any![unify(x, 1), bad.clone()], x);
        assert_eq!(first, vec![1]);

        let second = util::goal_resolves_to(any![bad, unify(x, 2)], x);
        assert_eq!(second, vec![2]);
    }

    #[test]
    fn both_fail() {
        let x = var();
        let goal: Goal<I32> = any![unify(6, 5), unify(1, 2)];
        let results = util::goal_resolves_to(goal, x);
        assert_eq!(results, vec![] as Vec<i32>);
    }
}