zero_ecs_build/
code_generation.rs

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        // implement len
106        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 at_mut
116        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 at
126        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    // This function formats SomeString to some_string
499
500    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        //use zero_ecs::ParallelIterator;
519        #[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    // distinct groups
899    let groups: Vec<_> = collected
900        .systems
901        .iter()
902        .map(|s| &s.group)
903        .unique()
904        .collect();
905
906    //debug!("{:?}", groups);
907
908    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        // get values of call_params, ignoring the key
976        let call_params: Vec<_> = call_params.values().collect();
977
978        // order call_params by name
979        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}