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
use std::fmt;
use std::rc::Rc;
use crate::State;
use super::Goal;
/// A [Goal](crate::goals::Goal) that gives access to the underlying
/// [`State`](crate::core::State) struct. Create with [`custom`].
#[derive(Clone)]
pub struct Custom(Rc<dyn Fn(State) -> Option<State>>);
impl Goal for Custom {
fn apply(&self, state: State) -> Option<State> {
(self.0)(state)
}
}
/**
Create a [goal](crate::goals::Goal) that gives access to the underlying
[`State`](crate::core::State) struct.
Similar to [`lazy`](crate::goals::lazy()), the passed in callback is given
access to the state so it can call the lower level [State] manipulation
methods. This should approach should be used sparingly. Ideally most logic
should be composable out of lower level primitive goals.
Because the [State] methods return an `Option<[State]>` the
[question mark operator `?`](https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html)
can be used to allow chaining operations on the [State].
# Examples
```
use canrun::{custom, LVar, Query};
let x = LVar::new();
let goal = custom(move |state| {
let y = LVar::new();
state.unify(&y.into(), &1.into())?
.unify(&x.into(), &y.into())
});
let result: Vec<_> = goal.query(x).collect();
assert_eq!(result, vec![1])
```
*/
pub fn custom<F>(func: F) -> Custom
where
F: Fn(State) -> Option<State> + 'static,
{
Custom(Rc::new(func))
}
impl fmt::Debug for Custom {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Custom(<fn>)")
}
}
#[cfg(test)]
mod tests {
use super::custom;
use crate::{LVar, Query};
#[test]
fn succeeds() {
let x = LVar::new();
let goal = custom(move |s| s.unify(&x.into(), &1.into()));
let results: Vec<_> = goal.query(x).collect();
assert_eq!(results, vec![1]);
}
#[test]
fn debug_impl() {
let goal = custom(|_| None);
assert_eq!(format!("{goal:?}"), "Custom(<fn>)");
}
}