Skip to main content

examples/queries/
query_cyclic_variables.rs

1use crate::z_ignore_test_common::*;
2
3use flecs_ecs::prelude::*;
4// This example shows how a rule may have terms with cyclic dependencies on
5// variables.
6
7#[derive(Component)]
8struct Likes;
9
10fn main() {
11    let world = World::new();
12
13    let bob = world.entity_named("Bob");
14    let alice = world.entity_named("Alice");
15    let john = world.entity_named("John");
16    let jane = world.entity_named("Jane");
17
18    bob.add((Likes, alice));
19    alice.add((Likes, bob));
20    john.add((Likes, jane));
21    jane.add((Likes, john));
22    bob.add((Likes, jane)); // inserting a bit of drama
23
24    // The following rule will only return entities that have a cyclic Likes
25    // relationship- that is they must both like each other.
26    //
27    // The equivalent query in the DSL is:
28    //   Likes($X, $Y), Likes($Y, $X)
29    //
30    // This is also an example of a query where all sources are variables. By
31    // default queries use the builtin "This" variable as subject, which is what
32    // populates the entities array in the query result (accessed by the
33    // iter::entity function).
34    //
35    // Because this query does not use This at all, the entities array will not
36    // be populated, and it.count() will always be 0.
37
38    let rule = world
39        .query::<()>()
40        .with((Likes, "$Y"))
41        .set_src("$X")
42        .with((Likes, "$X"))
43        .set_src("$Y")
44        .build();
45
46    // Lookup the index of the variables. This will let us quickly lookup their
47    // values while we're iterating.
48    let x_var = rule.find_var("X").unwrap();
49    let y_var = rule.find_var("Y").unwrap();
50
51    // Because the query doesn't use the This variable we cannot use "each"
52    // which iterates the entities array. Instead we can use iter like this:
53    rule.run(|mut it| {
54        while it.next() {
55            let x = it.get_var(x_var);
56            let y = it.get_var(y_var);
57            println!("{} likes {}", x.name(), y.name());
58        }
59    });
60
61    // Output:
62    //  Alice likes Bob
63    //  John likes Jane
64    //  Jane likes John
65    //  Bob likes Alice
66
67    // Note that the rule returns each pair twice. The reason for this is that
68    // the goal of the rule engine is to return all "facts" that are true
69    // within the given constraints. Since we did not give it any constraints
70    // that would favor a person being matched by X or Y, the rule engine
71    // returns both.
72}
73
74#[cfg(feature = "flecs_nightly_tests")]
75#[test]
76fn test() {
77    let output_capture = OutputCapture::capture().unwrap();
78    main();
79    output_capture.test("query_cyclic_variables".to_string());
80}