ixa/macros/
all.rs

1/// Creates a query matching all entities of a given type, optionally filtered by properties.
2///
3/// # Examples
4///
5/// ```ignore
6/// // Add an entity with default properties
7/// let query = all!(Person);
8/// context.add_entity(query)?;
9///
10/// // An inline query matching a single property
11/// let person = context.sample_entity(MyRng, all!(Person, Age(12)))?;
12///
13/// // A query matching multiple properties
14/// let query = all!(Person, Age(12), RiskCategory::High);
15/// let count = context.count_entities(query);
16/// ```
17#[macro_export]
18macro_rules! all {
19    // No properties - generates empty tuple query
20    ($entity:ty) => {
21        $crate::EntityPropertyTuple::<$entity, _>::new(())
22    };
23    // One or more properties
24    ($entity:ty, $($prop:expr),+ $(,)?) => {
25        $crate::EntityPropertyTuple::<$entity, _>::new(($($prop,)+))
26    };
27}
28
29#[cfg(test)]
30mod tests {
31    use crate::context::Context;
32    use crate::entity::ContextEntitiesExt;
33    use crate::random::ContextRandomExt;
34    use crate::{define_entity, define_property, define_rng, impl_property};
35
36    define_entity!(TestPerson);
37    define_property!(struct Age(u8), TestPerson, default_const = Age(0));
38    define_property!(
39        enum Risk {
40            High,
41            Low,
42        },
43        TestPerson
44    );
45    define_rng!(AllMacroTestRng);
46
47    #[test]
48    fn all_macro_with_add_entity() {
49        let mut context = Context::new();
50
51        // Use all! macro to add an entity
52        let person = context
53            .add_entity(all!(TestPerson, Age(42), Risk::High))
54            .unwrap();
55
56        // Verify properties were set correctly
57        assert_eq!(context.get_property::<TestPerson, Age>(person), Age(42));
58        assert_eq!(context.get_property::<TestPerson, Risk>(person), Risk::High);
59    }
60
61    #[test]
62    fn all_macro_with_sample_entity() {
63        let mut context = Context::new();
64        context.init_random(42);
65
66        // Add some entities
67        let p1 = context
68            .add_entity(all!(TestPerson, Age(30), Risk::High))
69            .unwrap();
70        let _ = context
71            .add_entity(all!(TestPerson, Age(30), Risk::Low))
72            .unwrap();
73        let _ = context
74            .add_entity(all!(TestPerson, Age(25), Risk::High))
75            .unwrap();
76
77        // Sample from entities matching the query
78        let sampled = context.sample_entity(AllMacroTestRng, all!(TestPerson, Age(30), Risk::High));
79        assert_eq!(sampled, Some(p1));
80    }
81
82    #[test]
83    fn all_macro_with_sample_entity_no_match() {
84        let mut context = Context::new();
85        context.init_random(42);
86
87        // Add some entities that don't match the query
88        let _ = context
89            .add_entity(all!(TestPerson, Age(30), Risk::Low))
90            .unwrap();
91
92        // Sample should return None when no entities match
93        let sampled = context.sample_entity(AllMacroTestRng, all!(TestPerson, Age(30), Risk::High));
94        assert_eq!(sampled, None);
95    }
96
97    // Demonstrate that `all!` can disambiguate entities in otherwise ambiguous cases.
98    use crate::entity::EntityId;
99    define_entity!(TestMammal);
100    define_entity!(TestAvian);
101    define_property!(struct IsBipedal(bool), TestMammal, default_const = IsBipedal(false));
102    impl_property!(IsBipedal, TestAvian, default_const = IsBipedal(true));
103
104    #[test]
105    fn all_macro_disambiguates_entities() {
106        let mut context = Context::new();
107
108        context
109            .add_entity(all!(TestAvian, IsBipedal(true)))
110            .unwrap();
111        context
112            .add_entity(all!(TestMammal, IsBipedal(true)))
113            .unwrap();
114
115        let result = context.query_result_iterator(all!(TestMammal, IsBipedal(true)));
116        assert_eq!(result.count(), 1);
117
118        let sampled_id = context
119            .sample_entity(AllMacroTestRng, all!(TestAvian, IsBipedal(true)))
120            .unwrap();
121        let expected_id: EntityId<TestAvian> = EntityId::new(0);
122        assert_eq!(sampled_id, expected_id);
123    }
124}