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
use super::Goal;
use crate::core::State;
/**
A [Goal](crate::goals::Goal) that only succeeds if both sub-goals succeed. Create with [`both`].
*/
#[derive(Debug)]
pub struct Both {
a: Box<dyn Goal>,
b: Box<dyn Goal>,
}
/**
Create a [goal](crate::goals::Goal) that only succeeds if both sub-goals
succeed.
This is essentially an "AND" operation. The resulting state will be the
result of the combining the two sub-goals.
If the first goal fails, the second goal will not be attempted.
# Examples
Two successful goals allow values to flow between vars:
```
use canrun::{both, unify, LVar, Query};
let x = LVar::new();
let y = LVar::new();
let goal = both(unify(y, x), unify(1, x));
let result: Vec<_> = goal.query(x).collect();
assert_eq!(result, vec![1])
```
A failing goal will cause the entire goal to fail:
```
# use canrun::{both, unify, LVar, Query};
# let x = LVar::new();
let goal = both(unify(2, x), unify(1, x));
let result: Vec<_> = goal.query(x).collect();
assert_eq!(result, vec![]) // Empty result
```
*/
pub fn both(a: impl Goal, b: impl Goal) -> Both {
Both {
a: Box::new(a),
b: Box::new(b),
}
}
impl Goal for Both {
fn apply(&self, state: State) -> Option<State> {
self.a.apply(state).and_then(|s| self.b.apply(s))
}
}
#[cfg(test)]
mod test {
use crate::goals::{fail::Fail, succeed::Succeed};
use super::*;
#[test]
fn both_succeed() {
let state = State::new();
let goal = both(Succeed, Succeed);
let result = goal.apply(state);
assert!(result.is_some());
}
#[test]
fn both_succeed_then_fail() {
let state = State::new();
let goal = both(Succeed, Fail);
let result = goal.apply(state);
assert!(result.is_none());
}
#[test]
fn both_fail_then_succeed() {
let state = State::new();
let goal = both(Fail, Succeed);
let result = goal.apply(state);
assert!(result.is_none());
}
}