pub struct QueryBuilder<'w, D = (), F = ()>where
D: QueryData,
F: QueryFilter,{ /* private fields */ }Expand description
Builder struct to create QueryState instances at runtime.
let mut world = World::new();
let entity_a = world.spawn((A, B)).id();
let entity_b = world.spawn((A, C)).id();
// Instantiate the builder using the type signature of the iterator you will consume
let mut query = QueryBuilder::<(Entity, &B)>::new(&mut world)
// Add additional terms through builder methods
.with::<A>()
.without::<C>()
.build();
// Consume the QueryState
let (entity, b) = query.single(&world).unwrap();Implementations§
Source§impl<'w, D, F> QueryBuilder<'w, D, F>where
D: QueryData,
F: QueryFilter,
impl<'w, D, F> QueryBuilder<'w, D, F>where
D: QueryData,
F: QueryFilter,
Sourcepub fn new(world: &'w mut World) -> QueryBuilder<'w, D, F>
pub fn new(world: &'w mut World) -> QueryBuilder<'w, D, F>
Creates a new builder with the accesses required for D and F
Examples found in repository?
69fn main() {
70 let mut world = World::new();
71 let mut lines = std::io::stdin().lines();
72 let mut component_names = HashMap::<String, ComponentId>::new();
73 let mut component_info = HashMap::<ComponentId, ComponentInfo>::new();
74 let mut event_names = HashMap::<String, EventKey>::new();
75
76 println!("{PROMPT}");
77 loop {
78 print!("\n> ");
79 let _ = std::io::stdout().flush();
80 let Some(Ok(line)) = lines.next() else {
81 return;
82 };
83
84 if line.is_empty() {
85 return;
86 };
87
88 let Some((first, rest)) = line.trim().split_once(|c: char| c.is_whitespace()) else {
89 match &line.chars().next() {
90 Some('c') => println!("{COMPONENT_PROMPT}"),
91 Some('s') => println!("{ENTITY_PROMPT}"),
92 Some('q') => println!("{QUERY_PROMPT}"),
93 Some('e') => println!("{EVENT_PROMPT}"),
94 Some('t') => println!("{EMIT_PROMPT}"),
95 _ => println!("{PROMPT}"),
96 }
97 continue;
98 };
99
100 match &first[0..1] {
101 "c" => {
102 rest.split(',').for_each(|component| {
103 let mut component = component.split_whitespace();
104 let Some(name) = component.next() else {
105 return;
106 };
107 let size = match component.next().map(str::parse) {
108 Some(Ok(size)) => size,
109 _ => 0,
110 };
111 // Register our new component to the world with a layout specified by its size
112 // SAFETY: [u64] is Send + Sync
113 let id = world.register_component_with_descriptor(unsafe {
114 ComponentDescriptor::new_with_layout(
115 name.to_string(),
116 StorageType::Table,
117 Layout::array::<u64>(size).unwrap(),
118 None,
119 true,
120 false,
121 ComponentCloneBehavior::Default,
122 None,
123 )
124 });
125 let Some(info) = world.components().get_info(id) else {
126 return;
127 };
128 component_names.insert(name.to_string(), id);
129 component_info.insert(id, info.clone());
130 println!("Component {} created with id: {}", name, id.index());
131 });
132 }
133 "s" => {
134 let mut to_insert_ids = Vec::new();
135 let mut to_insert_data = Vec::new();
136 rest.split(',').for_each(|component| {
137 let mut component = component.split_whitespace();
138 let Some(name) = component.next() else {
139 return;
140 };
141
142 // Get the id for the component with the given name
143 let Some(&id) = component_names.get(name) else {
144 println!("Component {name} does not exist");
145 return;
146 };
147
148 // Calculate the length for the array based on the layout created for this component id
149 let info = world.components().get_info(id).unwrap();
150 let len = info.layout().size() / size_of::<u64>();
151 let mut values: Vec<u64> = component
152 .take(len)
153 .filter_map(|value| value.parse::<u64>().ok())
154 .collect();
155 values.resize(len, 0);
156
157 // Collect the id and array to be inserted onto our entity
158 to_insert_ids.push(id);
159 to_insert_data.push(values);
160 });
161
162 let mut entity = world.spawn_empty();
163
164 // Construct an `OwningPtr` for each component in `to_insert_data`
165 let to_insert_ptr = to_owning_ptrs(&mut to_insert_data);
166
167 // SAFETY:
168 // - Component ids have been taken from the same world
169 // - Each array is created to the layout specified in the world
170 unsafe {
171 entity.insert_by_ids(&to_insert_ids, to_insert_ptr.into_iter());
172 }
173
174 println!("Entity spawned with id: {}", entity.id());
175 }
176 "q" => {
177 let mut builder = QueryBuilder::<FilteredEntityMut>::new(&mut world);
178 parse_query(rest, &mut builder, &component_names);
179 let mut query = builder.build();
180 query.iter_mut(&mut world).for_each(|filtered_entity| {
181 let terms = filtered_entity
182 .access()
183 .try_iter_access()
184 .unwrap()
185 .map(|component_access| {
186 let id = *component_access.index();
187 let ptr = filtered_entity.get_by_id(id).unwrap();
188 let info = component_info.get(&id).unwrap();
189 let len = info.layout().size() / size_of::<u64>();
190
191 // SAFETY:
192 // - All components are created with layout [u64]
193 // - len is calculated from the component descriptor
194 let data = unsafe {
195 std::slice::from_raw_parts_mut(
196 ptr.assert_unique().as_ptr().cast::<u64>(),
197 len,
198 )
199 };
200
201 // If we have write access, increment each value once
202 if matches!(component_access, ComponentAccessKind::Exclusive(_)) {
203 data.iter_mut().for_each(|data| {
204 *data += 1;
205 });
206 }
207
208 format!("{}: {:?}", info.name(), data[0..len].to_vec())
209 })
210 .collect::<Vec<_>>()
211 .join(", ");
212
213 println!("{}: {}", filtered_entity.id(), terms);
214 });
215 }
216 "e" => {
217 rest.split(',').for_each(|event| {
218 let name = event.trim();
219 if name.is_empty() {
220 return;
221 }
222
223 // Register a ComponentId for this event, no Rust type needed.
224 // SAFETY: ZST with no drop
225 let event_component_id = world.register_component_with_descriptor(unsafe {
226 ComponentDescriptor::new_with_layout(
227 format!("event:{name}"),
228 StorageType::Table,
229 Layout::new::<()>(),
230 None,
231 false,
232 false,
233 ComponentCloneBehavior::Ignore,
234 None,
235 )
236 });
237 // SAFETY: event_component_id was just registered for this event
238 let event_key = unsafe { EventKey::new(event_component_id) };
239 event_names.insert(name.to_string(), event_key);
240
241 // Build a dynamic observer that prints when the event fires.
242 let runner: ObserverRunner = |mut world, _observer, ctx, _event, _trigger| {
243 println!(" Observer fired!");
244 if let Some(mut counts) = world.get_resource_mut::<EventFireCount>() {
245 *counts.0.entry(ctx.event_key).or_insert(0) += 1;
246 }
247 };
248
249 // SAFETY: event_key was just registered, runner ignores pointers
250 let observer =
251 unsafe { Observer::with_dynamic_runner(runner).with_event_key(event_key) };
252 world.spawn(observer);
253
254 println!(
255 "Event '{name}' registered (key: {}) with a dynamic observer",
256 event_component_id.index()
257 );
258 });
259
260 // Ensure the counter resource exists.
261 world.init_resource::<EventFireCount>();
262 }
263 "t" => {
264 let name = rest.trim();
265 let Some(&event_key) = event_names.get(name) else {
266 println!(
267 "Event '{name}' does not exist. Register it first with 'event {name}'"
268 );
269 continue;
270 };
271
272 let mut event_data = ();
273 let mut trigger_data = ();
274 // SAFETY: event_key was registered in this world, both pointers are valid ZSTs
275 unsafe {
276 world.trigger_dynamic(
277 event_key,
278 PtrMut::from(&mut event_data),
279 PtrMut::from(&mut trigger_data),
280 );
281 }
282
283 let count = world
284 .get_resource::<EventFireCount>()
285 .map_or(0, |c| c.0.get(&event_key).copied().unwrap_or(0));
286 println!("Event '{name}' triggered ({count} fires)");
287 }
288 _ => continue,
289 }
290 }
291}Sourcepub fn world_mut(&mut self) -> &mut World
pub fn world_mut(&mut self) -> &mut World
Returns a mutable reference to the world passed to Self::new.
Sourcepub fn extend_access(&mut self, access: FilteredAccess)
pub fn extend_access(&mut self, access: FilteredAccess)
Adds access to self’s underlying FilteredAccess respecting Self::or and Self::and
Sourcepub fn data<T>(&mut self) -> &mut QueryBuilder<'w, D, F>where
T: QueryData,
pub fn data<T>(&mut self) -> &mut QueryBuilder<'w, D, F>where
T: QueryData,
Adds accesses required for T to self.
Sourcepub fn filter<T>(&mut self) -> &mut QueryBuilder<'w, D, F>where
T: QueryFilter,
pub fn filter<T>(&mut self) -> &mut QueryBuilder<'w, D, F>where
T: QueryFilter,
Adds filter from T to self.
Sourcepub fn with<T>(&mut self) -> &mut QueryBuilder<'w, D, F>where
T: Component,
pub fn with<T>(&mut self) -> &mut QueryBuilder<'w, D, F>where
T: Component,
Adds With<T> to the FilteredAccess of self.
Sourcepub fn with_id(&mut self, id: ComponentId) -> &mut QueryBuilder<'w, D, F>
pub fn with_id(&mut self, id: ComponentId) -> &mut QueryBuilder<'w, D, F>
Adds With<T> to the FilteredAccess of self from a runtime ComponentId.
Examples found in repository?
315fn parse_term<Q: QueryData>(
316 str: &str,
317 builder: &mut QueryBuilder<Q>,
318 components: &HashMap<String, ComponentId>,
319) {
320 let mut matched = false;
321 let str = str.trim();
322 match str.chars().next() {
323 // Optional term
324 Some('?') => {
325 builder.optional(|b| parse_term(&str[1..], b, components));
326 matched = true;
327 }
328 // Reference term
329 Some('&') => {
330 let mut parts = str.split_whitespace();
331 let first = parts.next().unwrap();
332 if first == "&mut" {
333 if let Some(str) = parts.next()
334 && let Some(&id) = components.get(str)
335 {
336 builder.mut_id(id);
337 matched = true;
338 };
339 } else if let Some(&id) = components.get(&first[1..]) {
340 builder.ref_id(id);
341 matched = true;
342 }
343 }
344 // With term
345 Some(_) => {
346 if let Some(&id) = components.get(str) {
347 builder.with_id(id);
348 matched = true;
349 }
350 }
351 None => {}
352 };
353
354 if !matched {
355 println!("Unable to find component: {str}");
356 }
357}Sourcepub fn without<T>(&mut self) -> &mut QueryBuilder<'w, D, F>where
T: Component,
pub fn without<T>(&mut self) -> &mut QueryBuilder<'w, D, F>where
T: Component,
Adds Without<T> to the FilteredAccess of self.
Sourcepub fn without_id(&mut self, id: ComponentId) -> &mut QueryBuilder<'w, D, F>
pub fn without_id(&mut self, id: ComponentId) -> &mut QueryBuilder<'w, D, F>
Adds Without<T> to the FilteredAccess of self from a runtime ComponentId.
Sourcepub fn ref_id(&mut self, id: ComponentId) -> &mut QueryBuilder<'w, D, F>
pub fn ref_id(&mut self, id: ComponentId) -> &mut QueryBuilder<'w, D, F>
Adds &T to the FilteredAccess of self.
Examples found in repository?
315fn parse_term<Q: QueryData>(
316 str: &str,
317 builder: &mut QueryBuilder<Q>,
318 components: &HashMap<String, ComponentId>,
319) {
320 let mut matched = false;
321 let str = str.trim();
322 match str.chars().next() {
323 // Optional term
324 Some('?') => {
325 builder.optional(|b| parse_term(&str[1..], b, components));
326 matched = true;
327 }
328 // Reference term
329 Some('&') => {
330 let mut parts = str.split_whitespace();
331 let first = parts.next().unwrap();
332 if first == "&mut" {
333 if let Some(str) = parts.next()
334 && let Some(&id) = components.get(str)
335 {
336 builder.mut_id(id);
337 matched = true;
338 };
339 } else if let Some(&id) = components.get(&first[1..]) {
340 builder.ref_id(id);
341 matched = true;
342 }
343 }
344 // With term
345 Some(_) => {
346 if let Some(&id) = components.get(str) {
347 builder.with_id(id);
348 matched = true;
349 }
350 }
351 None => {}
352 };
353
354 if !matched {
355 println!("Unable to find component: {str}");
356 }
357}More examples
78fn stress_test(num_entities: u32, num_components: u32, num_systems: u32) {
79 let mut rng = ChaCha8Rng::seed_from_u64(42);
80 let mut app = App::default();
81 let world = app.world_mut();
82
83 // register a bunch of components
84 let component_ids: Vec<ComponentId> = (1..=num_components)
85 .map(|i| {
86 world.register_component_with_descriptor(
87 // SAFETY:
88 // * We don't implement a drop function
89 // * u8 is Sync and Send
90 unsafe {
91 ComponentDescriptor::new_with_layout(
92 format!("Component{i}").to_string(),
93 StorageType::Table,
94 Layout::new::<u8>(),
95 None,
96 true, // is mutable
97 false, // has no summary tick
98 ComponentCloneBehavior::Default,
99 None,
100 )
101 },
102 )
103 })
104 .collect();
105
106 // fill the schedule with systems
107 let mut schedule = Schedule::new(Update);
108 for _ in 1..=num_systems {
109 let num_access_components = rng.random_range(1..10);
110 let access_components: Vec<ComponentId> = component_ids
111 .sample(&mut rng, num_access_components)
112 .copied()
113 .collect();
114 let system = (QueryParamBuilder::new(|builder| {
115 for &access_component in &access_components {
116 if rand::random::<bool>() {
117 builder.mut_id(access_component);
118 } else {
119 builder.ref_id(access_component);
120 }
121 }
122 }),)
123 .build_state(world)
124 .build_any_system(base_system);
125 schedule.add_systems((move || access_components.clone()).pipe(system));
126 }
127
128 // spawn a bunch of entities
129 for _ in 1..=num_entities {
130 let num_components = rng.random_range(1..10);
131 let components: Vec<ComponentId> = component_ids
132 .sample(&mut rng, num_components)
133 .copied()
134 .collect();
135
136 let mut entity = world.spawn_empty();
137 // We use `ManuallyDrop` here as we need to avoid dropping the u8's when `values` is dropped
138 // since ownership of the values is passed to the world in `insert_by_ids`.
139 // But we do want to deallocate the memory when values is dropped.
140 let mut values: Vec<ManuallyDrop<u8>> = components
141 .iter()
142 .map(|_id| ManuallyDrop::new(rng.random_range(0..255)))
143 .collect();
144 let ptrs: Vec<OwningPtr> = values
145 .iter_mut()
146 .map(|value| {
147 // SAFETY:
148 // * We don't read/write `values` binding after this and values are `ManuallyDrop`,
149 // so we have the right to drop/move the values
150 unsafe { PtrMut::from(value).promote() }
151 })
152 .collect();
153 // SAFETY:
154 // * component_id's are from the same world
155 // * `values` was initialized above, so references are valid
156 unsafe {
157 entity.insert_by_ids(&components, ptrs.into_iter());
158 }
159 }
160
161 // overwrite Update schedule in the app
162 app.add_schedule(schedule);
163 app.add_plugins(MinimalPlugins)
164 .add_plugins(DiagnosticsPlugin)
165 .add_plugins(LogPlugin::default())
166 .add_plugins(FrameTimeDiagnosticsPlugin::default())
167 .add_plugins(LogDiagnosticsPlugin::filtered(HashSet::from_iter([
168 DiagnosticPath::new("fps"),
169 ])));
170 app.run();
171}Sourcepub fn mut_id(&mut self, id: ComponentId) -> &mut QueryBuilder<'w, D, F>
pub fn mut_id(&mut self, id: ComponentId) -> &mut QueryBuilder<'w, D, F>
Adds &mut T to the FilteredAccess of self.
Examples found in repository?
315fn parse_term<Q: QueryData>(
316 str: &str,
317 builder: &mut QueryBuilder<Q>,
318 components: &HashMap<String, ComponentId>,
319) {
320 let mut matched = false;
321 let str = str.trim();
322 match str.chars().next() {
323 // Optional term
324 Some('?') => {
325 builder.optional(|b| parse_term(&str[1..], b, components));
326 matched = true;
327 }
328 // Reference term
329 Some('&') => {
330 let mut parts = str.split_whitespace();
331 let first = parts.next().unwrap();
332 if first == "&mut" {
333 if let Some(str) = parts.next()
334 && let Some(&id) = components.get(str)
335 {
336 builder.mut_id(id);
337 matched = true;
338 };
339 } else if let Some(&id) = components.get(&first[1..]) {
340 builder.ref_id(id);
341 matched = true;
342 }
343 }
344 // With term
345 Some(_) => {
346 if let Some(&id) = components.get(str) {
347 builder.with_id(id);
348 matched = true;
349 }
350 }
351 None => {}
352 };
353
354 if !matched {
355 println!("Unable to find component: {str}");
356 }
357}More examples
78fn stress_test(num_entities: u32, num_components: u32, num_systems: u32) {
79 let mut rng = ChaCha8Rng::seed_from_u64(42);
80 let mut app = App::default();
81 let world = app.world_mut();
82
83 // register a bunch of components
84 let component_ids: Vec<ComponentId> = (1..=num_components)
85 .map(|i| {
86 world.register_component_with_descriptor(
87 // SAFETY:
88 // * We don't implement a drop function
89 // * u8 is Sync and Send
90 unsafe {
91 ComponentDescriptor::new_with_layout(
92 format!("Component{i}").to_string(),
93 StorageType::Table,
94 Layout::new::<u8>(),
95 None,
96 true, // is mutable
97 false, // has no summary tick
98 ComponentCloneBehavior::Default,
99 None,
100 )
101 },
102 )
103 })
104 .collect();
105
106 // fill the schedule with systems
107 let mut schedule = Schedule::new(Update);
108 for _ in 1..=num_systems {
109 let num_access_components = rng.random_range(1..10);
110 let access_components: Vec<ComponentId> = component_ids
111 .sample(&mut rng, num_access_components)
112 .copied()
113 .collect();
114 let system = (QueryParamBuilder::new(|builder| {
115 for &access_component in &access_components {
116 if rand::random::<bool>() {
117 builder.mut_id(access_component);
118 } else {
119 builder.ref_id(access_component);
120 }
121 }
122 }),)
123 .build_state(world)
124 .build_any_system(base_system);
125 schedule.add_systems((move || access_components.clone()).pipe(system));
126 }
127
128 // spawn a bunch of entities
129 for _ in 1..=num_entities {
130 let num_components = rng.random_range(1..10);
131 let components: Vec<ComponentId> = component_ids
132 .sample(&mut rng, num_components)
133 .copied()
134 .collect();
135
136 let mut entity = world.spawn_empty();
137 // We use `ManuallyDrop` here as we need to avoid dropping the u8's when `values` is dropped
138 // since ownership of the values is passed to the world in `insert_by_ids`.
139 // But we do want to deallocate the memory when values is dropped.
140 let mut values: Vec<ManuallyDrop<u8>> = components
141 .iter()
142 .map(|_id| ManuallyDrop::new(rng.random_range(0..255)))
143 .collect();
144 let ptrs: Vec<OwningPtr> = values
145 .iter_mut()
146 .map(|value| {
147 // SAFETY:
148 // * We don't read/write `values` binding after this and values are `ManuallyDrop`,
149 // so we have the right to drop/move the values
150 unsafe { PtrMut::from(value).promote() }
151 })
152 .collect();
153 // SAFETY:
154 // * component_id's are from the same world
155 // * `values` was initialized above, so references are valid
156 unsafe {
157 entity.insert_by_ids(&components, ptrs.into_iter());
158 }
159 }
160
161 // overwrite Update schedule in the app
162 app.add_schedule(schedule);
163 app.add_plugins(MinimalPlugins)
164 .add_plugins(DiagnosticsPlugin)
165 .add_plugins(LogPlugin::default())
166 .add_plugins(FrameTimeDiagnosticsPlugin::default())
167 .add_plugins(LogDiagnosticsPlugin::filtered(HashSet::from_iter([
168 DiagnosticPath::new("fps"),
169 ])));
170 app.run();
171}Sourcepub fn optional(
&mut self,
f: impl FnOnce(&mut QueryBuilder<'_>),
) -> &mut QueryBuilder<'w, D, F>
pub fn optional( &mut self, f: impl FnOnce(&mut QueryBuilder<'_>), ) -> &mut QueryBuilder<'w, D, F>
Takes a function over mutable access to a QueryBuilder, calls that function
on an empty builder and then adds all accesses from that builder to self as optional.
Examples found in repository?
315fn parse_term<Q: QueryData>(
316 str: &str,
317 builder: &mut QueryBuilder<Q>,
318 components: &HashMap<String, ComponentId>,
319) {
320 let mut matched = false;
321 let str = str.trim();
322 match str.chars().next() {
323 // Optional term
324 Some('?') => {
325 builder.optional(|b| parse_term(&str[1..], b, components));
326 matched = true;
327 }
328 // Reference term
329 Some('&') => {
330 let mut parts = str.split_whitespace();
331 let first = parts.next().unwrap();
332 if first == "&mut" {
333 if let Some(str) = parts.next()
334 && let Some(&id) = components.get(str)
335 {
336 builder.mut_id(id);
337 matched = true;
338 };
339 } else if let Some(&id) = components.get(&first[1..]) {
340 builder.ref_id(id);
341 matched = true;
342 }
343 }
344 // With term
345 Some(_) => {
346 if let Some(&id) = components.get(str) {
347 builder.with_id(id);
348 matched = true;
349 }
350 }
351 None => {}
352 };
353
354 if !matched {
355 println!("Unable to find component: {str}");
356 }
357}Sourcepub fn and(
&mut self,
f: impl FnOnce(&mut QueryBuilder<'_>),
) -> &mut QueryBuilder<'w, D, F>
pub fn and( &mut self, f: impl FnOnce(&mut QueryBuilder<'_>), ) -> &mut QueryBuilder<'w, D, F>
Takes a function over mutable access to a QueryBuilder, calls that function
on an empty builder and then adds all accesses from that builder to self.
Primarily used when inside a Self::or closure to group several terms.
Sourcepub fn or(
&mut self,
f: impl FnOnce(&mut QueryBuilder<'_>),
) -> &mut QueryBuilder<'w, D, F>
pub fn or( &mut self, f: impl FnOnce(&mut QueryBuilder<'_>), ) -> &mut QueryBuilder<'w, D, F>
Takes a function over mutable access to a QueryBuilder, calls that function
on an empty builder, all accesses added to that builder will become terms in an or expression.
QueryBuilder::<Entity>::new(&mut world).or(|builder| {
builder.with::<A>();
builder.with::<B>();
});
// is equivalent to
QueryBuilder::<Entity>::new(&mut world).filter::<Or<(With<A>, With<B>)>>();Examples found in repository?
359fn parse_query<Q: QueryData>(
360 str: &str,
361 builder: &mut QueryBuilder<Q>,
362 components: &HashMap<String, ComponentId>,
363) {
364 let str = str.split(',');
365 str.for_each(|term| {
366 let sub_terms: Vec<_> = term.split("||").collect();
367 if sub_terms.len() == 1 {
368 parse_term(sub_terms[0], builder, components);
369 } else {
370 builder.or(|b| {
371 sub_terms
372 .iter()
373 .for_each(|term| parse_term(term, b, components));
374 });
375 }
376 });
377}Sourcepub fn access(&self) -> &FilteredAccess
pub fn access(&self) -> &FilteredAccess
Returns a reference to the FilteredAccess that will be provided to the built Query.
Sourcepub fn transmute<NewD>(&mut self) -> &mut QueryBuilder<'w, NewD>where
NewD: QueryData,
pub fn transmute<NewD>(&mut self) -> &mut QueryBuilder<'w, NewD>where
NewD: QueryData,
Transmute the existing builder adding required accesses. This will maintain all existing accesses.
If including a filter type see Self::transmute_filtered
Sourcepub fn transmute_filtered<NewD, NewF>(
&mut self,
) -> &mut QueryBuilder<'w, NewD, NewF>where
NewD: QueryData,
NewF: QueryFilter,
pub fn transmute_filtered<NewD, NewF>(
&mut self,
) -> &mut QueryBuilder<'w, NewD, NewF>where
NewD: QueryData,
NewF: QueryFilter,
Transmute the existing builder adding required accesses. This will maintain all existing accesses.
Sourcepub fn build(&mut self) -> QueryState<D, F>
pub fn build(&mut self) -> QueryState<D, F>
Create a QueryState with the accesses of the builder.
Takes &mut self to access the inner world reference while initializing
state for the new QueryState
Examples found in repository?
69fn main() {
70 let mut world = World::new();
71 let mut lines = std::io::stdin().lines();
72 let mut component_names = HashMap::<String, ComponentId>::new();
73 let mut component_info = HashMap::<ComponentId, ComponentInfo>::new();
74 let mut event_names = HashMap::<String, EventKey>::new();
75
76 println!("{PROMPT}");
77 loop {
78 print!("\n> ");
79 let _ = std::io::stdout().flush();
80 let Some(Ok(line)) = lines.next() else {
81 return;
82 };
83
84 if line.is_empty() {
85 return;
86 };
87
88 let Some((first, rest)) = line.trim().split_once(|c: char| c.is_whitespace()) else {
89 match &line.chars().next() {
90 Some('c') => println!("{COMPONENT_PROMPT}"),
91 Some('s') => println!("{ENTITY_PROMPT}"),
92 Some('q') => println!("{QUERY_PROMPT}"),
93 Some('e') => println!("{EVENT_PROMPT}"),
94 Some('t') => println!("{EMIT_PROMPT}"),
95 _ => println!("{PROMPT}"),
96 }
97 continue;
98 };
99
100 match &first[0..1] {
101 "c" => {
102 rest.split(',').for_each(|component| {
103 let mut component = component.split_whitespace();
104 let Some(name) = component.next() else {
105 return;
106 };
107 let size = match component.next().map(str::parse) {
108 Some(Ok(size)) => size,
109 _ => 0,
110 };
111 // Register our new component to the world with a layout specified by its size
112 // SAFETY: [u64] is Send + Sync
113 let id = world.register_component_with_descriptor(unsafe {
114 ComponentDescriptor::new_with_layout(
115 name.to_string(),
116 StorageType::Table,
117 Layout::array::<u64>(size).unwrap(),
118 None,
119 true,
120 false,
121 ComponentCloneBehavior::Default,
122 None,
123 )
124 });
125 let Some(info) = world.components().get_info(id) else {
126 return;
127 };
128 component_names.insert(name.to_string(), id);
129 component_info.insert(id, info.clone());
130 println!("Component {} created with id: {}", name, id.index());
131 });
132 }
133 "s" => {
134 let mut to_insert_ids = Vec::new();
135 let mut to_insert_data = Vec::new();
136 rest.split(',').for_each(|component| {
137 let mut component = component.split_whitespace();
138 let Some(name) = component.next() else {
139 return;
140 };
141
142 // Get the id for the component with the given name
143 let Some(&id) = component_names.get(name) else {
144 println!("Component {name} does not exist");
145 return;
146 };
147
148 // Calculate the length for the array based on the layout created for this component id
149 let info = world.components().get_info(id).unwrap();
150 let len = info.layout().size() / size_of::<u64>();
151 let mut values: Vec<u64> = component
152 .take(len)
153 .filter_map(|value| value.parse::<u64>().ok())
154 .collect();
155 values.resize(len, 0);
156
157 // Collect the id and array to be inserted onto our entity
158 to_insert_ids.push(id);
159 to_insert_data.push(values);
160 });
161
162 let mut entity = world.spawn_empty();
163
164 // Construct an `OwningPtr` for each component in `to_insert_data`
165 let to_insert_ptr = to_owning_ptrs(&mut to_insert_data);
166
167 // SAFETY:
168 // - Component ids have been taken from the same world
169 // - Each array is created to the layout specified in the world
170 unsafe {
171 entity.insert_by_ids(&to_insert_ids, to_insert_ptr.into_iter());
172 }
173
174 println!("Entity spawned with id: {}", entity.id());
175 }
176 "q" => {
177 let mut builder = QueryBuilder::<FilteredEntityMut>::new(&mut world);
178 parse_query(rest, &mut builder, &component_names);
179 let mut query = builder.build();
180 query.iter_mut(&mut world).for_each(|filtered_entity| {
181 let terms = filtered_entity
182 .access()
183 .try_iter_access()
184 .unwrap()
185 .map(|component_access| {
186 let id = *component_access.index();
187 let ptr = filtered_entity.get_by_id(id).unwrap();
188 let info = component_info.get(&id).unwrap();
189 let len = info.layout().size() / size_of::<u64>();
190
191 // SAFETY:
192 // - All components are created with layout [u64]
193 // - len is calculated from the component descriptor
194 let data = unsafe {
195 std::slice::from_raw_parts_mut(
196 ptr.assert_unique().as_ptr().cast::<u64>(),
197 len,
198 )
199 };
200
201 // If we have write access, increment each value once
202 if matches!(component_access, ComponentAccessKind::Exclusive(_)) {
203 data.iter_mut().for_each(|data| {
204 *data += 1;
205 });
206 }
207
208 format!("{}: {:?}", info.name(), data[0..len].to_vec())
209 })
210 .collect::<Vec<_>>()
211 .join(", ");
212
213 println!("{}: {}", filtered_entity.id(), terms);
214 });
215 }
216 "e" => {
217 rest.split(',').for_each(|event| {
218 let name = event.trim();
219 if name.is_empty() {
220 return;
221 }
222
223 // Register a ComponentId for this event, no Rust type needed.
224 // SAFETY: ZST with no drop
225 let event_component_id = world.register_component_with_descriptor(unsafe {
226 ComponentDescriptor::new_with_layout(
227 format!("event:{name}"),
228 StorageType::Table,
229 Layout::new::<()>(),
230 None,
231 false,
232 false,
233 ComponentCloneBehavior::Ignore,
234 None,
235 )
236 });
237 // SAFETY: event_component_id was just registered for this event
238 let event_key = unsafe { EventKey::new(event_component_id) };
239 event_names.insert(name.to_string(), event_key);
240
241 // Build a dynamic observer that prints when the event fires.
242 let runner: ObserverRunner = |mut world, _observer, ctx, _event, _trigger| {
243 println!(" Observer fired!");
244 if let Some(mut counts) = world.get_resource_mut::<EventFireCount>() {
245 *counts.0.entry(ctx.event_key).or_insert(0) += 1;
246 }
247 };
248
249 // SAFETY: event_key was just registered, runner ignores pointers
250 let observer =
251 unsafe { Observer::with_dynamic_runner(runner).with_event_key(event_key) };
252 world.spawn(observer);
253
254 println!(
255 "Event '{name}' registered (key: {}) with a dynamic observer",
256 event_component_id.index()
257 );
258 });
259
260 // Ensure the counter resource exists.
261 world.init_resource::<EventFireCount>();
262 }
263 "t" => {
264 let name = rest.trim();
265 let Some(&event_key) = event_names.get(name) else {
266 println!(
267 "Event '{name}' does not exist. Register it first with 'event {name}'"
268 );
269 continue;
270 };
271
272 let mut event_data = ();
273 let mut trigger_data = ();
274 // SAFETY: event_key was registered in this world, both pointers are valid ZSTs
275 unsafe {
276 world.trigger_dynamic(
277 event_key,
278 PtrMut::from(&mut event_data),
279 PtrMut::from(&mut trigger_data),
280 );
281 }
282
283 let count = world
284 .get_resource::<EventFireCount>()
285 .map_or(0, |c| c.0.get(&event_key).copied().unwrap_or(0));
286 println!("Event '{name}' triggered ({count} fires)");
287 }
288 _ => continue,
289 }
290 }
291}Trait Implementations§
Source§impl<D, F> From<QueryBuilder<'_, D, F>> for QueryState<D, F>where
D: QueryData,
F: QueryFilter,
impl<D, F> From<QueryBuilder<'_, D, F>> for QueryState<D, F>where
D: QueryData,
F: QueryFilter,
Source§fn from(value: QueryBuilder<'_, D, F>) -> QueryState<D, F>
fn from(value: QueryBuilder<'_, D, F>) -> QueryState<D, F>
Auto Trait Implementations§
impl<'w, D = (), F = ()> !RefUnwindSafe for QueryBuilder<'w, D, F>
impl<'w, D = (), F = ()> !UnwindSafe for QueryBuilder<'w, D, F>
impl<'w, D, F> Freeze for QueryBuilder<'w, D, F>
impl<'w, D, F> Send for QueryBuilder<'w, D, F>
impl<'w, D, F> Sync for QueryBuilder<'w, D, F>
impl<'w, D, F> Unpin for QueryBuilder<'w, D, F>
impl<'w, D, F> UnsafeUnpin for QueryBuilder<'w, D, F>
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T ShaderType for self. When used in AsBindGroup
derives, it is safe to assume that all images in self exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<T> ConditionalSend for Twhere
T: Send,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
Source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
Source§impl<T> InitializeFromFunction<T> for T
impl<T> InitializeFromFunction<T> for T
Source§fn initialize_from_function(f: fn() -> T) -> T
fn initialize_from_function(f: fn() -> T) -> T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> IntoResult<T> for T
impl<T> IntoResult<T> for T
Source§fn into_result(self) -> Result<T, RunSystemError>
fn into_result(self) -> Result<T, RunSystemError>
Source§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
impl<T> Settings for T
Source§impl<Ret> SpawnIfAsync<(), Ret> for Ret
impl<Ret> SpawnIfAsync<(), Ret> for Ret
Source§impl<T, O> SuperFrom<T> for Owhere
O: From<T>,
impl<T, O> SuperFrom<T> for Owhere
O: From<T>,
Source§fn super_from(input: T) -> O
fn super_from(input: T) -> O
Source§impl<T, O, M> SuperInto<O, M> for Twhere
O: SuperFrom<T, M>,
impl<T, O, M> SuperInto<O, M> for Twhere
O: SuperFrom<T, M>,
Source§fn super_into(self) -> O
fn super_into(self) -> O
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.