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}