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 110 111 112 113 114 115
use std::rc::Rc;
use crate::core::{Fork, State, StateIter};
use super::Goal;
/**
A [Goal](crate::goals::Goal) that succeeds if either sub-goal
succeed. Create with [`either`].
*/
#[derive(Clone, Debug)]
pub struct Either {
a: Rc<dyn Goal>,
b: Rc<dyn Goal>,
}
/**
Create a [goal](crate::goals::Goal) that succeeds if either sub-goal
succeed.
This is essentially an "OR" operation, and will eventually lead to zero, one
or two [resolved states](crate::State), depending on the
success or failure of the sub-goals.
# Examples
Two successful goals will yield up two different results:
```
use canrun::{either, unify, LVar, Query};
let x = LVar::new();
let goal = either(unify(x, 1), unify(x, 2));
let result: Vec<_> = goal.query(x).collect();
assert_eq!(result, vec![1, 2])
```
One failing goal will not cause the other to fail:
```
# use canrun::{either, unify, LVar, Query};
# let x = LVar::new();
let goal = either(unify(1, 2), unify(x, 3));
let result: Vec<_> = goal.query(x).collect();
assert_eq!(result, vec![3])
```
Both goals can fail, leading to no results:
```
# use canrun::{either, unify, LVar, Query};
# let x: LVar<usize> = LVar::new();
let goal = either(unify(6, 5), unify(1, 2));
let result: Vec<_> = goal.query(x).collect();
assert_eq!(result, vec![]) // Empty result
```
*/
pub fn either(a: impl Goal, b: impl Goal) -> Either {
Either {
a: Rc::new(a),
b: Rc::new(b),
}
}
impl Goal for Either {
fn apply(&self, state: State) -> Option<State> {
state.fork(self.clone())
}
}
impl Fork for Either {
fn fork(&self, state: &State) -> StateIter {
let a = self.a.apply(state.clone()).into_iter();
let b = self.b.apply(state.clone()).into_iter();
Box::new(a.chain(b))
}
}
#[cfg(test)]
mod test {
use crate::core::StateIterator;
use crate::goals::{fail::Fail, succeed::Succeed};
use super::*;
#[test]
fn either_succeed() {
let state = State::new();
let goal = either(Succeed, Succeed);
let result = goal.apply(state);
assert_eq!(result.into_states().count(), 2);
}
#[test]
fn either_succeed_or_fail() {
let state = State::new();
let goal = either(Succeed, Fail);
let result = goal.apply(state);
assert_eq!(result.into_states().count(), 1);
}
#[test]
fn either_fail_or_succeed() {
let state = State::new();
let goal = either(Fail, Succeed);
let result = goal.apply(state);
assert_eq!(result.into_states().count(), 1);
}
#[test]
fn either_fail() {
let state = State::new();
let goal = either(Fail, Fail);
let result = goal.apply(state);
assert_eq!(result.into_states().count(), 0);
}
}