proto_vulcan/operator/
anyo.rs

1use crate::engine::Engine;
2use crate::goal::{AnyGoal, Goal};
3use crate::operator::conde::conde;
4use crate::operator::conj::Conj;
5use crate::operator::OperatorParam;
6use crate::solver::{Solve, Solver};
7use crate::state::State;
8use crate::stream::Stream;
9use crate::user::User;
10use crate::GoalCast;
11use std::rc::Rc;
12
13#[derive(Derivative)]
14#[derivative(Debug(bound = "U: User"))]
15pub struct Anyo<U, E>
16where
17    U: User,
18    E: Engine<U>,
19{
20    g: Goal<U, E>,
21}
22
23impl<U, E> Anyo<U, E>
24where
25    U: User,
26    E: Engine<U>,
27{
28    pub fn new(g: Goal<U, E>) -> Goal<U, E> {
29        Goal::dynamic(Rc::new(Anyo { g }))
30    }
31}
32
33impl<U, E> Solve<U, E> for Anyo<U, E>
34where
35    U: User,
36    E: Engine<U>,
37{
38    fn solve(&self, solver: &Solver<U, E>, state: State<U, E>) -> Stream<U, E> {
39        let g = self.g.clone();
40        let g2 = self.g.clone();
41        let goal = proto_vulcan!(
42            conde {
43                g,
44                anyo {
45                    g2
46                },
47            }
48        );
49        goal.solve(solver, state)
50    }
51}
52
53/// Try a goal unbounded number of times operator.
54///
55/// Proto-vulcan provides a built-in keyword `loop` that maps to anyo.
56/// # Example
57/// In this example the conde-operator would be tried unbounded number of times.
58/// ```rust
59/// extern crate proto_vulcan;
60/// use proto_vulcan::prelude::*;
61/// fn main() {
62///     let query = proto_vulcan_query!(|q| {
63///         loop {
64///             conde {
65///                 1 == q,
66///                 2 == q,
67///                 3 == q,
68///             }
69///         }
70///     });
71///     let mut iter = query.run();
72///     assert_eq!(iter.next().unwrap().q, 1);
73///     assert_eq!(iter.next().unwrap().q, 2);
74///     assert_eq!(iter.next().unwrap().q, 3);
75///     assert_eq!(iter.next().unwrap().q, 1);
76///     assert_eq!(iter.next().unwrap().q, 2);
77///     assert_eq!(iter.next().unwrap().q, 3);
78/// }
79/// ```
80pub fn anyo<U, E>(param: OperatorParam<U, E, Goal<U, E>>) -> Goal<U, E>
81where
82    U: User,
83    E: Engine<U>,
84{
85    Anyo::new(GoalCast::cast_into(Conj::from_conjunctions(param.body)))
86}
87
88#[cfg(test)]
89mod tests {
90    use super::anyo;
91    use crate::operator::conde::conde;
92    use crate::prelude::*;
93
94    #[test]
95    fn test_anyo_1() {
96        let query = proto_vulcan_query!(|q| {
97            conde {
98                anyo {
99                    false == q,
100                },
101                true == q,
102            }
103        });
104        let mut iter = query.run();
105        assert_eq!(iter.next().unwrap().q, true);
106        assert_eq!(iter.next().unwrap().q, false);
107        assert_eq!(iter.next().unwrap().q, false);
108        assert_eq!(iter.next().unwrap().q, false);
109        assert_eq!(iter.next().unwrap().q, false);
110    }
111
112    #[test]
113    fn test_anyo_2() {
114        let query = proto_vulcan_query!(|q| {
115            anyo {
116                conde {
117                    1 == q,
118                    2 == q,
119                    3 == q,
120                }
121            }
122        });
123        let mut iter = query.run();
124        assert_eq!(iter.next().unwrap().q, 1);
125        assert_eq!(iter.next().unwrap().q, 2);
126        assert_eq!(iter.next().unwrap().q, 3);
127        assert_eq!(iter.next().unwrap().q, 1);
128        assert_eq!(iter.next().unwrap().q, 2);
129        assert_eq!(iter.next().unwrap().q, 3);
130    }
131
132    #[test]
133    fn test_anyo_3() {
134        // Test "loop" operator keyword
135        let query = proto_vulcan_query!(|q| {
136            loop {
137                conde {
138                    1 == q,
139                    2 == q,
140                    3 == q,
141                }
142            }
143        });
144        let mut iter = query.run();
145        assert_eq!(iter.next().unwrap().q, 1);
146        assert_eq!(iter.next().unwrap().q, 2);
147        assert_eq!(iter.next().unwrap().q, 3);
148        assert_eq!(iter.next().unwrap().q, 1);
149        assert_eq!(iter.next().unwrap().q, 2);
150        assert_eq!(iter.next().unwrap().q, 3);
151    }
152}