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>)");
    }
}