Skip to main content

examples/queries/
query_facts.rs

1use crate::z_ignore_test_common::*;
2
3use flecs_ecs::prelude::*;
4// This example shows how to use queries for testing facts. A fact is a query that
5// has no variable elements. Consider a regular ECS query like this:
6//   Position, Velocity
7//
8// When written out in full, this query looks like:
9//   Position($This), Velocity($This)
10//
11// "This" is a (builtin) query variable that is unknown before we evaluate the
12// query. Therefore this query does not test a fact, we can't know which values
13// This will assume.
14//
15// An example of a fact-checking query is:
16//   IsA(Cat, Animal)
17//
18// This is a fact: the query has no elements that are unknown before evaluating
19// the query. A rule that checks a fact does not return entities, but will
20// instead return the reasons why a fact is true (if it is true).
21
22#[derive(Component)]
23struct Likes;
24
25fn main() {
26    let world = World::new();
27
28    let bob = world.entity_named("Bob");
29    let alice = world.entity_named("Alice");
30    let john = world.entity_named("John");
31    let jane = world.entity_named("Jane");
32
33    bob.add((Likes, alice));
34    alice.add((Likes, bob));
35    john.add((Likes, jane));
36    jane.add((Likes, john));
37    bob.add((Likes, jane)); // inserting a bit of drama
38
39    // Create a rule that checks if two entities like each other. By itself this
40    // rule is not a fact, but we can use it to check facts by populating both
41    // of its variables.
42    //
43    // The equivalent query in the DSL is:
44    //  Likes($X, $Y), Likes($Y, $X)
45    //
46    // Instead of using variables we could have created a rule that referred the
47    // entities directly, but then we would have to create a rule for each
48    // fact, vs reusing a single rule for multiple facts.
49
50    let mut friends = world
51        .query::<()>()
52        .with((Likes, "$Y"))
53        .set_src("$X")
54        .with((Likes, "$X"))
55        .set_src("$Y")
56        .build();
57
58    let x_var = friends.find_var("X").unwrap();
59    let y_var = friends.find_var("Y").unwrap();
60
61    // Check a few facts
62
63    println!(
64        "Are Bob and Alice friends? {}",
65        if friends.set_var(x_var, bob).set_var(y_var, alice).is_true() {
66            "Yes"
67        } else {
68            "No"
69        }
70    );
71
72    println!(
73        "Are Bob and John friends? {}",
74        if friends.set_var(x_var, bob).set_var(y_var, john).is_true() {
75            "Yes"
76        } else {
77            "No"
78        }
79    );
80
81    println!(
82        "Are Jane and John friends? {}",
83        if friends.set_var(x_var, jane).set_var(y_var, john).is_true() {
84            "Yes"
85        } else {
86            "No"
87        }
88    );
89
90    // It doesn't matter who we assign to X or Y. After the variables are
91    // substituted, either yields a fact that is true.
92
93    println!(
94        "Are John and Jane friends? {}",
95        if friends.set_var(x_var, john).set_var(y_var, jane).is_true() {
96            "Yes"
97        } else {
98            "No"
99        }
100    );
101
102    // Output:
103    //  Are Bob and Alice friends? Yes
104    //  Are Bob and John friends? No
105    //  Are Jane and John friends? Yes
106    //  Are John and Jane friends? Yes
107}
108
109#[cfg(feature = "flecs_nightly_tests")]
110#[test]
111fn test() {
112    let output_capture = OutputCapture::capture().unwrap();
113    main();
114    output_capture.test("query_facts".to_string());
115}