Skip to main content

examples/queries/
query_group_by_custom.rs

1use crate::z_ignore_test_common::*;
2
3use core::ffi::c_void;
4use flecs_ecs::prelude::*;
5use flecs_ecs::sys;
6
7#[derive(Debug, Component)]
8pub struct Position {
9    pub x: f32,
10    pub y: f32,
11}
12
13#[derive(Component)]
14pub struct Tag;
15
16#[derive(Component)]
17pub struct First;
18
19#[derive(Component)]
20pub struct Second;
21
22#[derive(Component)]
23pub struct Third;
24
25#[derive(Component)]
26pub struct Group;
27
28#[extern_abi]
29fn callback_group_by_relationship(
30    world: *mut sys::ecs_world_t,
31    table: *mut sys::ecs_table_t,
32    id: u64,
33    _group_by_ctx: *mut c_void,
34) -> u64 {
35    // Use sys::ecs_search to find the target for the relationship in the table
36    let mut match_id: sys::ecs_id_t = Default::default();
37    let world = unsafe { WorldRef::from_ptr(world) };
38    let id = IdView::new_from_id(world, (id, flecs::Wildcard::ID)).id();
39    if unsafe { sys::ecs_search(world.world_ptr_mut(), table, *id, &mut match_id) } != -1 {
40        *IdView::new_from_id(world, match_id).second_id().id() // First, Second or Third
41    } else {
42        0
43    }
44}
45
46fn main() {
47    let world = World::new();
48
49    // Register components in order so that id for First is lower than Third
50    world.component::<First>();
51    world.component::<Second>();
52    world.component::<Third>();
53
54    // Grouped query
55    let query = world
56        .query::<&Position>()
57        .group_by_fn(Group, Some(callback_group_by_relationship))
58        .build();
59
60    // Create entities in 6 different tables with 3 group ids
61    world
62        .entity()
63        .add((Group, Third))
64        .set(Position { x: 1.0, y: 1.0 });
65    world
66        .entity()
67        .add((Group, Second))
68        .set(Position { x: 2.0, y: 2.0 });
69    world
70        .entity()
71        .add((Group, First))
72        .set(Position { x: 3.0, y: 3.0 });
73
74    world
75        .entity()
76        .add((Group, Third))
77        .set(Position { x: 4.0, y: 4.0 })
78        .add(Tag);
79    world
80        .entity()
81        .add((Group, Second))
82        .set(Position { x: 5.0, y: 5.0 })
83        .add(Tag);
84    world
85        .entity()
86        .add((Group, First))
87        .set(Position { x: 6.0, y: 6.0 })
88        .add(Tag);
89
90    println!();
91
92    // The query cache now looks like this:
93    //  - group First:
94    //     - table [Position, (Group, First)]
95    //     - table [Position, Tag, (Group, First)]
96    //
97    //  - group Second:
98    //     - table [Position, (Group, Second)]
99    //     - table [Position, Tag, (Group, Second)]
100    //
101    //  - group Third:
102    //     - table [Position, (Group, Third)]
103    //     - table [Position, Tag, (Group, Third)]
104    //
105
106    query.run(|mut it| {
107        while it.next() {
108            let group = world.entity_from_id(it.group_id());
109            let pos = it.field::<Position>(0);
110
111            println!(
112                "Group: {:?} - Table: [{:?}]",
113                group.path().unwrap(),
114                it.archetype()
115            );
116
117            for i in it.iter() {
118                println!(" [{:?}]", pos[i]);
119            }
120
121            println!();
122        }
123    });
124
125    // Output:
126    //  Group: "::First" - Table: [Position, (Group,First)]
127    //  [Position { x: 3.0, y: 3.0 }]
128    //
129    //  Group: "::First" - Table: [Position, Tag, (Group,First)]
130    //  [Position { x: 6.0, y: 6.0 }]
131    //
132    //  Group: "::Second" - Table: [Position, (Group,Second)]
133    //  [Position { x: 2.0, y: 2.0 }]
134    //
135    //  Group: "::Second" - Table: [Position, Tag, (Group,Second)]
136    //  [Position { x: 5.0, y: 5.0 }]
137    //
138    //  Group: "::Third" - Table: [Position, (Group,Third)]
139    //  [Position { x: 1.0, y: 1.0 }]
140    //
141    //  Group: "::Third" - Table: [Position, Tag, (Group,Third)]
142    //  [Position { x: 4.0, y: 4.0 }]
143}
144
145#[cfg(feature = "flecs_nightly_tests")]
146#[test]
147fn test() {
148    let output_capture = OutputCapture::capture().unwrap();
149    main();
150    output_capture.test("query_group_by_custom".to_string());
151}