1#![allow(
2 unused_attributes,
3 dead_code,
4 unused_imports,
5 unused_variables,
6 unused_macro_rules,
7 unused_macros,
8 unused_mut
9)]
10use core::arch;
11use itertools::Itertools;
12use quote::format_ident;
13use quote::quote;
14use quote::ToTokens;
15use std::collections::HashMap;
16use std::fs::File;
17use std::io::Write;
18use std::process::Command;
19use std::{env, fs, path::Path};
20use syn::{Fields, Item, ItemFn, Meta, PatType, PathArguments, Type};
21
22use crate::*;
23pub fn generate_default_queries(out_dir: &str) -> String {
24 let file_name = "queries.rs";
25
26 let code_rs = quote! {
27
28 use std::marker::PhantomData;
29
30
31 #[derive(Default, Debug)]
32 pub struct Query<T> {
33 phantom: PhantomData<T>,
34 }
35
36 impl<T> Clone for Query<T> {
37 fn clone(&self) -> Self {
38 Query {
39 phantom: PhantomData,
40 }
41 }
42 }
43
44 #[allow(dead_code)]
45 impl<T> Query<T> {
46 fn new() -> Query<T> {
47 Query {
48 phantom: PhantomData,
49 }
50 }
51 }
52
53 impl<'a, T: 'a + Send> Query<T>
54 {
55 pub fn iter(&self, world: &'a World) -> impl Iterator<Item = T> + 'a
56 where
57 World: QueryFrom<'a, T>,
58 {
59 world.query_from()
60 }
61 }
62 impl<'a, T: 'a + Send> Query<T>
63 {
64 pub fn par_iter(&self, world: &'a World) -> impl ParallelIterator<Item = T> + 'a
65 where
66 World: QueryFrom<'a, T>,
67 {
68 world.par_query_from()
69 }
70 }
71 impl<'a, T: 'a + Send> Query<T> {
72 pub fn iter_mut(&self, world: &'a mut World) -> impl Iterator<Item = T> + 'a
73 where
74 World: QueryMutFrom<'a, T>,
75 {
76 world.query_mut_from()
77 }
78 }
79 impl<'a, T: 'a + Send> Query<T>
80 {
81 pub fn par_iter_mut(&self, world: &'a mut World) -> impl ParallelIterator<Item = T> + 'a
82 where
83 World: QueryMutFrom<'a, T>,
84 {
85 world.par_query_mut_from()
86 }
87 }
88 impl<'a, T: 'a + Send> Query<T> {
89 pub fn get(&self, world: &'a World, entity: Entity) -> Option<T>
90 where
91 World: QueryFrom<'a, T>,
92 {
93 world.get_from(entity)
94 }
95 }
96 impl<'a, T: 'a + Send> Query<T> {
97 pub fn get_mut(&self, world: &'a mut World, entity: Entity) -> Option<T>
98 where
99 World: QueryMutFrom<'a, T>,
100 {
101 world.get_mut_from(entity)
102 }
103 }
104
105 impl<'a, T: 'a + Send> Query<T> {
107 pub fn len(&self, world: &'a World) -> usize
108 where
109 World: LenFrom<'a, T>,
110 {
111 world.len()
112 }
113 }
114
115 impl<'a, T: 'a + Send> Query<T> {
117 pub fn at_mut(&self, world: &'a mut World, index: usize) -> Option<T>
118 where
119 World: QueryMutFrom<'a, T>,
120 {
121 world.at_mut(index)
122 }
123 }
124
125 impl<'a, T: 'a + Send> Query<T> {
127 pub fn at(&self, world: &'a World, index: usize) -> Option<T>
128 where
129 World: QueryFrom<'a, T>,
130 {
131 world.at(index)
132 }
133 }
134
135
136 pub struct WithQueryMut<'a, T> {
137 query: Query<T>,
138 world: &'a mut World,
139 }
140 pub struct WithQuery<'a, T> {
141 query: Query<T>,
142 world: &'a World,
143 }
144
145 #[allow(dead_code)]
146 impl<'a, T> WithQueryMut<'a, T>
147 where World: QueryMutFrom<'a, T>,
148 World: LenFrom<'a, T>,
149 T: 'a + Send,
150 {
151 pub fn iter_mut(&'a mut self) -> impl Iterator<Item = T> + 'a {
152 self.query.iter_mut(self.world)
153 }
154 pub fn par_iter_mut(&'a mut self) -> impl ParallelIterator<Item = T> + 'a {
155 self.query.par_iter_mut(self.world)
156 }
157 pub fn get_mut(&'a mut self, entity: Entity) -> Option<T> {
158 self.query.get_mut(self.world, entity)
159 }
160 pub fn len(&'a mut self) -> usize {
161 self.query.len(self.world)
162 }
163 pub fn at_mut(&'a mut self, index: usize) -> Option<T> {
164 self.query.at_mut(self.world, index)
165 }
166 pub fn is_empty(&'a mut self) -> bool {
167 self.query.len(self.world) == 0
168 }
169 }
170
171 #[allow(dead_code)]
172 impl<'a, T> WithQuery<'a, T>
173 where World: QueryFrom<'a, T>,
174 World: LenFrom<'a, T>,
175 T: 'a + Send,
176 {
177 pub fn iter(&'a self) -> impl Iterator<Item = T> + 'a {
178 self.query.iter(self.world)
179 }
180 pub fn par_iter(&'a self) -> impl ParallelIterator<Item = T> + 'a {
181 self.query.par_iter(self.world)
182 }
183 pub fn get(&'a self, entity: Entity) -> Option<T> {
184 self.query.get(self.world, entity)
185 }
186 pub fn len(&'a self) -> usize {
187 self.query.len(self.world)
188 }
189 pub fn at(&'a self, index: usize) -> Option<T> {
190 self.query.at(self.world, index)
191 }
192 pub fn is_empty(&'a self) -> bool {
193 self.query.len(self.world) == 0
194 }
195 }
196
197 #[allow(dead_code)]
198 impl World {
199 pub fn with_query_mut<'a, T: 'a + Send>(&'a mut self, query: Query<T>) -> WithQueryMut<'a, T>
200 where
201 World: QueryMutFrom<'a, T>,
202 {
203 WithQueryMut {
204 query,
205 world: self,
206 }
207 }
208 }
209 #[allow(dead_code)]
210 impl World {
211 pub fn with_query<'a, T: 'a + Send>(&'a self, query: Query<T>) -> WithQuery<'a, T>
212 where
213 World: QueryFrom<'a, T>,
214 {
215 WithQuery {
216 query,
217 world: self,
218 }
219 }
220 }
221 };
222 write_token_stream_to_file(out_dir, file_name, &code_rs.to_string())
223}
224
225pub fn generate_world_rs(
226 out_dir: &str,
227 include_files: &mut Vec<String>,
228 collected: &CollectedData,
229) {
230 let mut world_rs = vec![];
231
232 let mut world_fields = vec![];
233
234 let mut entity_types = collected.entities.iter().map(|entity| {
235 let entity_name = &entity.name;
236 fident!(entity_name)
237 });
238
239 world_rs.push(quote! {
240 #[allow(unused_imports)]
241 use zero_ecs::*;
242 #[derive(Debug, Clone, Copy)]
243 enum EntityType {
244 #(#entity_types),*
245 }
246
247 #[allow(dead_code)]
248 #[derive(Debug, Clone, Copy)]
249 pub struct Entity {
250 entity_type: EntityType,
251 id: usize
252 }
253 #[allow(dead_code)]
254 impl World {
255 pub fn query_mut<'a, T: 'a + Send>(&'a mut self) -> impl Iterator<Item = T> + 'a
256 where
257 World: QueryMutFrom<'a, T>,
258 {
259 QueryMutFrom::<T>::query_mut_from(self)
260 }
261 pub fn par_query_mut<'a, T: 'a + Send>(&'a mut self) -> impl ParallelIterator<Item = T> + 'a
262 where
263 World: QueryMutFrom<'a, T>,
264 {
265 QueryMutFrom::<T>::par_query_mut_from(self)
266 }
267
268 pub fn get_mut<'a, T: 'a + Send>(&'a mut self, entity: Entity) -> Option<T>
269 where
270 World: QueryMutFrom<'a, T>,
271 {
272 QueryMutFrom::<T>::get_mut_from(self, entity)
273 }
274 }
275 #[allow(dead_code)]
276 impl World {
277 pub fn query<'a, T: 'a + Send>(&'a self) -> impl Iterator<Item = T> + 'a
278 where
279 World: QueryFrom<'a, T>,
280 {
281 QueryFrom::<T>::query_from(self)
282 }
283 pub fn par_query<'a, T: 'a + Send>(&'a self) -> impl ParallelIterator<Item = T> + 'a
284 where
285 World: QueryFrom<'a, T>,
286 {
287 QueryFrom::<T>::par_query_from(self)
288 }
289 pub fn get<'a, T: 'a + Send>(&'a self, entity: Entity) -> Option<T>
290 where
291 World: QueryFrom<'a, T>,
292 {
293 QueryFrom::<T>::get_from(self, entity)
294 }
295 }
296 pub trait WorldCreate<T> {
297 fn create(&mut self, e: T) -> Entity;
298 }
299 });
300
301 let mut match_destroy_rs = vec![];
302
303 for entity in collected.entities.iter() {
304 let entity_name = &entity.name;
305 let field_name = fident!(singular_to_plural(&pascal_case_to_snake_case(entity_name)));
306 let archetype_type = fident!(singular_to_plural(entity_name));
307
308 world_fields.push(quote! {
309 #field_name: #archetype_type,
310 });
311
312 let archetype_fields = entity.fields.iter().map(|field| {
313 let field_name = format_ident!("{}", singular_to_plural(&field.name));
314 let field_type = format_ident!("{}", &field.data_type);
315 quote! {
316 #field_name: Vec<#field_type>,
317 }
318 });
319
320 world_rs.push(quote! {
321
322 #[derive(Default, Debug)]
323 struct #archetype_type {
324 #(#archetype_fields)*
325 next_id: usize,
326 index_lookup: Vec<Option<usize>>,
327 }
328
329 #[allow(dead_code)]
330 impl #archetype_type {
331 fn len(&self) -> usize {
332 self.entities.len()
333 }
334 }
335 });
336
337 world_rs.push(quote! {
338 #[allow(dead_code)]
339 impl #archetype_type {
340 fn query_mut<'a, T>(&'a mut self) -> impl Iterator<Item = T> + 'a
341 where
342 #archetype_type: QueryMutFrom<'a, T>,
343 T: 'a + Send,
344 {
345 QueryMutFrom::<T>::query_mut_from(self)
346 }
347 fn par_query_mut<'a, T>(&'a mut self) -> impl ParallelIterator<Item = T> + 'a
348 where
349 #archetype_type: QueryMutFrom<'a, T>,
350 T: 'a + Send,
351 {
352 QueryMutFrom::<T>::par_query_mut_from(self)
353 }
354 fn get_mut<'a, T>(&'a mut self, entity: Entity) -> Option<T>
355 where
356 #archetype_type: QueryMutFrom<'a, T>,
357 T: 'a + Send,
358 {
359 QueryMutFrom::<T>::get_mut_from(self, entity)
360 }
361 }
362 });
363 world_rs.push(quote! {
364 #[allow(dead_code)]
365 impl #archetype_type {
366 fn query<'a, T>(&'a self) -> impl Iterator<Item = T> + 'a
367 where
368 #archetype_type: QueryFrom<'a, T>,
369 T: 'a + Send,
370 {
371 QueryFrom::<T>::query_from(self)
372 }
373 fn par_query<'a, T>(&'a self) -> impl ParallelIterator<Item = T> + 'a
374 where
375 #archetype_type: QueryFrom<'a, T>,
376 T: 'a + Send,
377 {
378 QueryFrom::<T>::par_query_from(self)
379 }
380 fn get<'a, T>(&'a self, entity: Entity) -> Option<T>
381 where
382 #archetype_type: QueryFrom<'a, T>,
383 T: 'a + Send,
384 {
385 QueryFrom::<T>::get_from(self, entity)
386 }
387 }
388 });
389
390 let push_lines = entity
391 .fields
392 .iter()
393 .filter(|e| e.data_type != "Entity")
394 .map(|field| {
395 let component_field_name = format_ident!("{}", singular_to_plural(&field.name));
396 let component_name = fident!(&field.name);
397
398 quote! {
399 self.#field_name.#component_field_name.push(e.#component_name);
400 }
401 });
402
403 let entity_name = fident!(entity_name);
404
405 world_rs.push(quote! {
406 impl WorldCreate<#entity_name> for World {
407 fn create(&mut self, e: #entity_name) -> Entity {
408 self.#field_name.index_lookup.push(Some(self.#field_name.entities.len()));
409 let entity = Entity {
410 entity_type: EntityType::#entity_name,
411 id: self.#field_name.next_id,
412 };
413 self.#field_name.entities.push(entity);
414 #(#push_lines)*
415 self.#field_name.next_id += 1;
416 entity
417 }
418 }
419 });
420
421 let pop_and_drop_code = entity.fields.iter().map(|field| {
422 let field_name = format_ident!("{}", singular_to_plural(&field.name));
423 let component_field_name = format_ident!("{}", singular_to_plural(&field.name));
424 quote! {
425 self.#component_field_name.swap(old_index, last_index);
426 self.#component_field_name.pop();
427 }
428 });
429
430 let pop_and_drop_code_copy = pop_and_drop_code.clone();
431
432 world_rs.push(quote! {
433 #[allow(dead_code)]
434 impl #archetype_type {
435 fn destroy(&mut self, entity: Entity) {
436 if let Some(&Some(old_index)) = self.index_lookup.get(entity.id) {
437 self.index_lookup[entity.id] = None;
438
439 let last_index = self.entities.len() - 1;
440
441 if old_index != last_index {
442 let last_entity = self.entities[last_index];
443
444 #(#pop_and_drop_code)*
445
446 self.index_lookup[last_entity.id] = Some(old_index);
447 } else {
448 #(#pop_and_drop_code_copy)*
449 }
450 }
451 }
452 }
453 });
454
455 match_destroy_rs.push(quote! {
456 EntityType::#entity_name => self.#field_name.destroy(entity),
457 });
458 }
459
460 world_rs.push(quote! {
461 #[allow(dead_code)]
462 impl World {
463 fn destroy(&mut self, entity: Entity) {
464 match entity.entity_type {
465 #(#match_destroy_rs)*
466 }
467 }
468 }
469 });
470
471 world_rs.push(quote! {
472 #[derive(Default, Debug)]
473 pub struct World {
474 #(#world_fields)*
475 }
476 });
477
478 let world_rs = quote! {
479 #(#world_rs)*
480 };
481
482 include_files.push(write_token_stream_to_file(
483 out_dir,
484 "world.rs",
485 &world_rs.to_string(),
486 ));
487}
488
489pub fn singular_to_plural(name: &str) -> String {
490 let last_char = name.chars().last().unwrap();
491 if last_char == 'y' {
492 format!("{}ies", &name[0..name.len() - 1])
493 } else {
494 format!("{}s", name)
495 }
496}
497pub fn pascal_case_to_snake_case(name: &str) -> String {
498 let mut result = String::new();
501 for (i, c) in name.chars().enumerate() {
502 if c.is_uppercase() {
503 if i > 0 {
504 result.push('_');
505 }
506 result.push(c.to_lowercase().next().unwrap());
507 } else {
508 result.push(c);
509 }
510 }
511 result
512}
513
514pub fn generate_queries(out_dir: &str, include_files: &mut Vec<String>, collected: &CollectedData) {
515 let mut code_rs = vec![];
516
517 code_rs.push(quote! {
518 #[allow(unused_imports)]
520 use zero_ecs::izip;
521 #[allow(unused_imports)]
522 use zero_ecs::chain;
523
524 pub trait LenFrom<'a, T>
525 where
526 T: 'a + Send
527 {
528 fn len(&'a self) -> usize;
529 fn is_empty(&'a self) -> bool {
530 self.len() == 0
531 }
532 }
533
534
535 pub trait QueryFrom<'a, T>
536 where
537 T: 'a + Send
538 {
539 fn query_from(&'a self) -> impl Iterator<Item = T>;
540 fn par_query_from(&'a self) -> impl ParallelIterator<Item = T>;
541 fn get_from(&'a self, entity: Entity) -> Option<T>;
542 fn at(&'a self, index: usize) -> Option<T>;
543 }
544 pub trait QueryMutFrom<'a, T>
545 where
546 T: 'a + Send
547 {
548 fn query_mut_from(&'a mut self) -> impl Iterator<Item = T>;
549 fn par_query_mut_from(&'a mut self) -> impl ParallelIterator<Item = T>;
550 fn get_mut_from(&'a mut self, entity: Entity) -> Option<T>;
551 fn at_mut(&'a mut self, index: usize) -> Option<T>;
552 }
553 });
554
555 for query in collected.queries.iter() {
556 let mutable = !query.mutable_fields.is_empty();
557 let matching_entities: Vec<&EntityDef> = collected
558 .entities
559 .iter()
560 .filter(|entity| {
561 let mut all_fields_present = true;
562
563 for query_field in query.mutable_fields.iter() {
564 if !entity
565 .fields
566 .iter()
567 .any(|entity_field| entity_field.data_type == *query_field)
568 {
569 all_fields_present = false;
570 break;
571 }
572 }
573 for query_field in query.const_fields.iter() {
574 if !entity
575 .fields
576 .iter()
577 .any(|entity_field| entity_field.data_type == *query_field)
578 {
579 all_fields_present = false;
580 break;
581 }
582 }
583 all_fields_present
584 })
585 .collect();
586 let mut data_types = vec![];
587
588 for field in query.mutable_fields.iter() {
589 let field_data_type = fident!(field);
590 data_types.push(quote! {
591 &'a mut #field_data_type
592 });
593 }
594 for field in query.const_fields.iter() {
595 let field_data_type = fident!(field);
596
597 data_types.push(quote! {
598 &'a #field_data_type
599 });
600 }
601
602 let mut match_get_rs = vec![];
603
604 for entity in matching_entities.iter() {
605 let entity_name = fident!(entity.name);
606
607 let mut field_quotes = vec![];
608 let mut par_field_quotes = vec![];
609 let mut get_quotes = vec![];
610
611 for field in query.mutable_fields.iter() {
612 let field_name = fident!(singular_to_plural(
613 entity
614 .fields
615 .iter()
616 .find(|f| f.data_type == *field)
617 .unwrap()
618 .name
619 .as_str()
620 ));
621
622 field_quotes.push(quote! {
623 self.#field_name.iter_mut()
624 });
625 par_field_quotes.push(quote! {
626 self.#field_name.par_iter_mut()
627 });
628 get_quotes.push(quote! {
629 self.#field_name.get_mut(index)?
630 });
631 }
632 for field in query.const_fields.iter() {
633 let field_name = fident!(singular_to_plural(
634 entity
635 .fields
636 .iter()
637 .find(|f| f.data_type == *field)
638 .unwrap()
639 .name
640 .as_str()
641 ));
642
643 field_quotes.push(quote! {
644 self.#field_name.iter()
645 });
646 par_field_quotes.push(quote! {
647 self.#field_name.par_iter()
648 });
649 get_quotes.push(quote! {
650 self.#field_name.get(index)?
651 });
652 }
653
654 let archetype_type = fident!(singular_to_plural(&entity.name));
655 let archetype_field_name =
656 fident!(singular_to_plural(&pascal_case_to_snake_case(&entity.name)));
657
658 code_rs.push(quote! {
659 #[allow(unused_parens)]
660 impl<'a> LenFrom<'a, (#(#data_types),*)> for #archetype_type {
661 fn len(&'a self) -> usize {
662 self.entities.len()
663 }
664 }
665 });
666
667 if mutable {
668 code_rs.push(quote! {
669 #[allow(unused_parens, clippy::needless_question_mark, clippy::double_parens)]
670 impl<'a> QueryMutFrom<'a, (#(#data_types),*)> for #archetype_type {
671 fn query_mut_from(&'a mut self) -> impl Iterator<Item = (#(#data_types),*)> {
672 izip!(#(#field_quotes),*)
673 }
674 fn par_query_mut_from(&'a mut self) -> impl ParallelIterator<Item = (#(#data_types),*)> {
675 izip_par!(#(#par_field_quotes),*)
676 }
677 fn get_mut_from(&'a mut self, entity: Entity) -> Option<(#(#data_types),*)> {
678 if let Some(&Some(index)) = self.index_lookup.get(entity.id) {
679 Some((#(#get_quotes),*))
680 } else {
681 None
682 }
683 }
684 fn at_mut(&'a mut self, index: usize) -> Option<(#(#data_types),*)>
685 {
686 Some((#(#get_quotes),*))
687 }
688 }
689 });
690 match_get_rs.push(quote! {
691 EntityType::#entity_name => self.#archetype_field_name.get_mut_from(entity),
692 });
693 } else {
694 code_rs.push(quote! {
695 #[allow(unused_parens, clippy::needless_question_mark, clippy::double_parens)]
696 impl<'a> QueryFrom<'a, (#(#data_types),*)> for #archetype_type {
697 fn query_from(&'a self) -> impl Iterator<Item = (#(#data_types),*)> {
698 izip!(#(#field_quotes),*)
699 }
700 fn par_query_from(&'a self) -> impl ParallelIterator<Item = (#(#data_types),*)> {
701 izip_par!(#(#par_field_quotes),*)
702 }
703 fn get_from(&'a self, entity: Entity) -> Option<(#(#data_types),*)> {
704 if let Some(&Some(index)) = self.index_lookup.get(entity.id) {
705 Some((#(#get_quotes),*))
706 } else {
707 None
708 }
709 }
710 fn at(&'a self, index: usize) -> Option<(#(#data_types),*)>
711 {
712 Some((#(#get_quotes),*))
713 }
714 }
715 });
716 match_get_rs.push(quote! {
717 EntityType::#entity_name => self.#archetype_field_name.get_from(entity),
718 });
719 }
720 }
721 let sum_args: Vec<_> = matching_entities
722 .iter()
723 .map(|entity| {
724 let property_name = format_ident!(
725 "{}",
726 singular_to_plural(&pascal_case_to_snake_case(&entity.name))
727 );
728 quote! { self.#property_name.len() }
729 })
730 .collect();
731
732 if !sum_args.is_empty() {
733 code_rs.push(quote! {
734 #[allow(unused_parens, unused_variables, unused_assignments)]
735 impl<'a> LenFrom<'a, (#(#data_types),*)> for World {
736 fn len(&'a self) -> usize {
737 sum!(#(#sum_args),*)
738 }
739 }
740 });
741 } else {
742 code_rs.push(quote! {
743 #[allow(unused_parens, unused_variables, unused_assignments)]
744 impl<'a> LenFrom<'a, (#(#data_types),*)> for World {
745 fn len(&'a self) -> usize {
746 0
747 }
748 }
749 });
750 }
751
752 if mutable {
753 let chain_args: Vec<_> = matching_entities
754 .iter()
755 .map(|entity| {
756 let property_name = format_ident!(
757 "{}",
758 singular_to_plural(&pascal_case_to_snake_case(&entity.name))
759 );
760 quote! { self.#property_name.query_mut() }
761 })
762 .collect();
763 let par_chain_args: Vec<_> = matching_entities
764 .iter()
765 .map(|entity| {
766 let property_name = format_ident!(
767 "{}",
768 singular_to_plural(&pascal_case_to_snake_case(&entity.name))
769 );
770 quote! { self.#property_name.par_query_mut() }
771 })
772 .collect();
773 let at_mut_args: Vec<_> = matching_entities
774 .iter()
775 .map(|entity| {
776 let property_name = format_ident!(
777 "{}",
778 singular_to_plural(&pascal_case_to_snake_case(&entity.name))
779 );
780 quote! {
781 {
782 let len = self.#property_name.len();
783 if index < len {
784 return self.#property_name.at_mut(index);
785 }
786 index -= len;
787 }
788 }
789 })
790 .collect();
791
792 code_rs.push(quote! {
793 #[allow(unused_parens, unused_variables, unused_assignments)]
794 impl<'a> QueryMutFrom<'a, (#(#data_types),*)> for World {
795 fn query_mut_from(&'a mut self) -> impl Iterator<Item = (#(#data_types),*)> {
796 chain!(#(#chain_args),*)
797 }
798 fn par_query_mut_from(&'a mut self) -> impl ParallelIterator<Item = (#(#data_types),*)> {
799 chain_par!(#(#par_chain_args),*)
800 }
801 #[allow(unreachable_patterns, clippy::match_single_binding)]
802 fn get_mut_from(&'a mut self, entity: Entity) -> Option<(#(#data_types),*)> {
803 match entity.entity_type {
804 #(#match_get_rs)*
805 _ => None
806 }
807 }
808 #[allow(unused_mut)]
809 fn at_mut(&'a mut self, index: usize) -> Option<(#(#data_types),*)>
810 {
811 let mut index = index;
812 #(#at_mut_args)*
813 None
814 }
815 }
816 })
817 } else {
818 let chain_args: Vec<_> = matching_entities
819 .iter()
820 .map(|entity| {
821 let property_name = format_ident!(
822 "{}",
823 singular_to_plural(&pascal_case_to_snake_case(&entity.name))
824 );
825 quote! { self.#property_name.query() }
826 })
827 .collect();
828 let par_chain_args: Vec<_> = matching_entities
829 .iter()
830 .map(|entity| {
831 let property_name = format_ident!(
832 "{}",
833 singular_to_plural(&pascal_case_to_snake_case(&entity.name))
834 );
835 quote! { self.#property_name.par_query() }
836 })
837 .collect();
838 let at_args: Vec<_> = matching_entities
839 .iter()
840 .map(|entity| {
841 let property_name = format_ident!(
842 "{}",
843 singular_to_plural(&pascal_case_to_snake_case(&entity.name))
844 );
845 quote! {
846 {
847 let len = self.#property_name.len();
848 if index < len {
849 return self.#property_name.at(index);
850 }
851 index -= len;
852 }
853 }
854 })
855 .collect();
856 code_rs.push(quote! {
857 #[allow(unused_parens, unused_variables, unused_assignments)]
858 impl<'a> QueryFrom<'a, (#(#data_types),*)> for World {
859 fn query_from(&'a self) -> impl Iterator<Item = (#(#data_types),*)> {
860 chain!(#(#chain_args),*)
861 }
862 fn par_query_from(&'a self) -> impl ParallelIterator<Item = (#(#data_types),*)> {
863 chain_par!(#(#par_chain_args),*)
864 }
865 #[allow(unreachable_patterns, clippy::match_single_binding)]
866 fn get_from(&'a self, entity: Entity) -> Option<(#(#data_types),*)> {
867 match entity.entity_type {
868 #(#match_get_rs)*
869 _ => None
870 }
871 }
872
873 #[allow(unused_mut)]
874 fn at(&'a self, index: usize) -> Option<(#(#data_types),*)>
875 {
876 let mut index = index;
877 #(#at_args)*
878 None
879 }
880 }
881 })
882 }
883 }
884
885 let code_rs = quote! {
886 #(#code_rs)*
887 };
888
889 include_files.push(write_token_stream_to_file(
890 out_dir,
891 "implementations.rs",
892 &code_rs.to_string(),
893 ));
894}
895pub fn generate_systems(out_dir: &str, include_files: &mut Vec<String>, collected: &CollectedData) {
896 let mut code_rs = vec![];
897
898 let groups: Vec<_> = collected
900 .systems
901 .iter()
902 .map(|s| &s.group)
903 .unique()
904 .collect();
905
906 for group in groups.iter() {
909 let mut calls = vec![];
910
911 enum CallParams {
912 Reference(SystemDefParamReference),
913 Value(SystemDefParamValue),
914 }
915
916 let mut call_params: HashMap<(String, String), CallParams> = HashMap::new();
917
918 for system in collected
919 .systems
920 .iter()
921 .filter(|s| &s.group == *group)
922 .sorted_by(|a, b| a.name.cmp(&b.name))
923 {
924 let mut params_rs = vec![];
925
926 for param in system.params.iter() {
927 match param {
928 SystemDefParam::Query(name) => {
929 params_rs.push(quote! {
930 Query::new(),
931 });
932 }
933 SystemDefParam::Reference(reference) => {
934 let name = fident!(reference.name);
935
936 params_rs.push(quote! {
937 #name,
938 });
939
940 let key = (reference.name.clone(), reference.ty.clone());
941 let item = CallParams::Reference(reference.clone());
942 call_params
943 .entry(key)
944 .and_modify(|e| match e {
945 CallParams::Reference(e) if reference.mutable => {
946 e.mutable = true;
947 }
948 _ => {}
949 })
950 .or_insert(item);
951 }
952 SystemDefParam::Value(value) => {
953 let name = fident!(value.name);
954
955 params_rs.push(quote! {
956 #name,
957 });
958
959 let key = (value.name.clone(), value.ty.clone());
960 let item = CallParams::Value(value.clone());
961 call_params.entry(key).insert_entry(item);
962 }
963 }
964 }
965
966 let system_function_name = fident!(&system.name);
967
968 calls.push(quote! {
969 #system_function_name(#(#params_rs)*);
970 })
971 }
972
973 let function_name = format_ident!("systems_{}", group);
974
975 let call_params: Vec<_> = call_params.values().collect();
977
978 let call_params = call_params
980 .iter()
981 .sorted_by(|a, b| match (a, b) {
982 (CallParams::Reference(a), CallParams::Reference(b)) => a.name.cmp(&b.name),
983 (CallParams::Value(a), CallParams::Value(b)) => a.name.cmp(&b.name),
984 (CallParams::Reference(a), CallParams::Value(b)) => a.name.cmp(&b.name),
985 (CallParams::Value(a), CallParams::Reference(b)) => a.name.cmp(&b.name),
986 })
987 .collect::<Vec<_>>();
988
989 let call_params_rs = call_params.iter().map(|r| match r {
990 CallParams::Reference(r) => {
991 let name = fident!(r.name);
992 let ty = fident!(r.ty);
993
994 if r.mutable {
995 quote! {
996 #name: &mut #ty
997 }
998 } else {
999 quote! {
1000
1001 #name: &#ty
1002 }
1003 }
1004 }
1005 CallParams::Value(v) => {
1006 let name = fident!(v.name);
1007 let ty = fident!(v.ty);
1008 quote! {
1009 #name: #ty
1010 }
1011 }
1012 });
1013
1014 code_rs.push(quote! {
1015 #[allow(private_interfaces)]
1016 pub fn #function_name(#(#call_params_rs),*) {
1017 #(#calls)*
1018 }
1019 })
1020 }
1021
1022 let code_rs = quote! {
1023 #(#code_rs)*
1024 };
1025
1026 include_files.push(write_token_stream_to_file(
1027 out_dir,
1028 "systems.rs",
1029 &code_rs.to_string(),
1030 ));
1031}
1032pub fn generate_copy_traits(
1033 out_dir: &str,
1034 include_files: &mut Vec<String>,
1035 collected: &CollectedData,
1036) {
1037 let mut code_rs = vec![];
1038
1039 code_rs.push(quote! {});
1040
1041 for q in collected.queries.iter() {
1042 let mut data_types = vec![];
1043
1044 for field in q.mutable_fields.iter() {
1045 let field_data_type = fident!(field);
1046 data_types.push(quote! {
1047 &mut #field_data_type
1048 });
1049 }
1050
1051 for field in q.const_fields.iter() {
1052 let field_data_type = fident!(field);
1053 data_types.push(quote! {
1054 &#field_data_type
1055 });
1056 }
1057
1058 if data_types.len() > 1 {
1059 code_rs.push(quote! {
1060 impl Copy for Query<(#(#data_types),*)> {}
1061 });
1062 } else if let Some(data_type) = data_types.first() {
1063 code_rs.push(quote! {
1064 impl Copy for Query<#data_type> {}
1065 });
1066 }
1067 }
1068
1069 let code_rs = quote! {
1070 #(#code_rs)*
1071 };
1072
1073 include_files.push(write_token_stream_to_file(
1074 out_dir,
1075 "copy_traits.rs",
1076 &code_rs.to_string(),
1077 ));
1078}