apecs_derive/
lib.rs

1use proc_macro2::Span;
2use quote::quote;
3use syn::{parse_macro_input, DeriveInput, Ident, TypeTuple};
4
5#[proc_macro_derive(Edges, attributes(apecs))]
6pub fn derive_edges(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
7    let input: DeriveInput = parse_macro_input!(input);
8
9    let maybe_path = match moongraph_macros_syntax::find_path("apecs", &input) {
10        Err(e) => return e.into_compile_error().into(),
11        Ok(mp) => mp,
12    };
13
14    let path = maybe_path.unwrap_or_else(|| {
15        // UNWRAP: safe because we know this will parse
16        let path: syn::Path = syn::parse_str("apecs").unwrap();
17        path
18    });
19    moongraph_macros_syntax::derive_edges(input, path).into()
20}
21
22#[proc_macro]
23pub fn impl_isquery_tuple(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
24    let tuple: TypeTuple = parse_macro_input!(input);
25    let tys = tuple.elems.iter().collect::<Vec<_>>();
26    let nvars: Vec<Ident> = (0..tys.len())
27        .map(|n| Ident::new(&format!("n{}", n), Span::call_site()))
28        .collect();
29    let mvars: Vec<Ident> = (0..tys.len())
30        .map(|n| Ident::new(&format!("m{}", n), Span::call_site()))
31        .collect();
32    let extend_impl = tys
33        .iter()
34        .zip(nvars.iter().zip(mvars.iter()))
35        .skip(1)
36        .map(|(ty, (n, m))| {
37            quote! {
38                #ty::extend_locked_columns(#n, #m, None);
39            }
40        });
41    let query_result_zip = tys
42        .iter()
43        .fold(None, |prev, ty| {
44            Some(prev.map_or_else(
45                || quote! {#ty::QueryResult<'a>},
46                |p| {
47                    quote! {std::iter::Zip<#p, #ty::QueryResult<'a>>}
48                },
49            ))
50        })
51        .unwrap();
52    let query_result_fn_param = tys
53        .iter()
54        .fold(None, |prev, ty| {
55            Some(prev.map_or_else(
56                || quote! {#ty::QueryRow<'a>},
57                |p| quote! {(#p, #ty::QueryRow<'a>)},
58            ))
59        })
60        .unwrap();
61    let par_query_result_zip = tys
62        .iter()
63        .fold(None, |prev, ty| {
64            Some(prev.map_or_else(
65                || quote! {#ty::ParQueryResult<'a>},
66                |p| {
67                    quote! {rayon::iter::Zip<#p, #ty::ParQueryResult<'a>>}
68                },
69            ))
70        })
71        .unwrap();
72    let iter_mut_impl_zip = tys
73        .iter()
74        .zip(nvars.iter())
75        .fold(None, |prev, (ty, n)| {
76            Some(prev.map_or_else(
77                || quote! {#ty::iter_mut(#n)},
78                |p| quote! {#p.zip(#ty::iter_mut(#n))},
79            ))
80        })
81        .unwrap();
82    let iter_one_impl_zip = tys
83        .iter()
84        .zip(nvars.iter())
85        .fold(None, |prev, (ty, n)| {
86            Some(prev.map_or_else(
87                || quote! {#ty::iter_one(#n, index)},
88                |p| quote! {#p.zip(#ty::iter_one(#n, index))},
89            ))
90        })
91        .unwrap();
92    let par_iter_mut_impl_zip = tys
93        .iter()
94        .zip(nvars.iter())
95        .fold(None, |prev, (ty, n)| {
96            Some(prev.map_or_else(
97                || quote! {#ty::par_iter_mut(len, #n)},
98                |p| quote! {#p.zip(#ty::par_iter_mut(len, #n))},
99            ))
100        })
101        .unwrap();
102    let nvar_tuple_list = nvars
103        .iter()
104        .fold(None, |prev, n| {
105            Some(prev.map_or_else(|| quote! {#n}, |p| quote! {(#p, #n)}))
106        })
107        .unwrap();
108    let iter_mut_impl = quote! {
109        #iter_mut_impl_zip.map(|#nvar_tuple_list| (#(#nvars),*))
110    };
111    let iter_one_impl = quote! {
112        #iter_one_impl_zip.map(|#nvar_tuple_list| (#(#nvars),*))
113    };
114    let par_iter_mut_impl = quote! {
115        #par_iter_mut_impl_zip.map(|#nvar_tuple_list| (#(#nvars),*))
116    };
117
118    let isquery_for_tuple = quote! {
119        impl <#(#tys),*> apecs::storage::archetype::IsQuery for #tuple
120        where
121            #(#tys: IsQuery),*
122        {
123            type LockedColumns<'a> = (
124                #(#tys::LockedColumns<'a>),*
125            );
126
127            type ExtensionColumns = (
128                #(#tys::ExtensionColumns),*
129            );
130
131            type QueryResult<'a> = std::iter::Map<
132                #query_result_zip,
133                fn(
134                    #query_result_fn_param,
135                ) -> (#(#tys::QueryRow<'a>),*),
136            >;
137
138            type ParQueryResult<'a> = rayon::iter::Map<
139                #par_query_result_zip,
140                fn(
141                    #query_result_fn_param,
142                ) -> (#(#tys::QueryRow<'a>),*),
143            >;
144
145            type QueryRow<'a> = (#(#tys::QueryRow<'a>),*);
146
147            #[inline]
148            fn reads() -> Vec<TypeKey> {
149                let mut bs = vec![];
150                #(bs.extend(#tys::reads());)*
151                bs
152            }
153
154            #[inline]
155            fn writes() -> Vec<TypeKey> {
156                let mut bs = vec![];
157                #(bs.extend(#tys::writes());)*
158                bs
159            }
160
161            #[inline]
162            fn lock_columns<'t>(arch: &'t Archetype) -> Self::LockedColumns<'t> {
163                (#(#tys::lock_columns(arch)),*)
164            }
165
166            fn extend_locked_columns<'a, 'b>(
167                (#(#nvars),*): &'b mut Self::LockedColumns<'a>,
168                (#(#mvars),*): Self::ExtensionColumns,
169                output_ids: Option<(&mut Vec<usize>, &mut usize)>,
170            ) {
171                A::extend_locked_columns(n0, m0, output_ids);
172                #(#extend_impl)*
173            }
174
175            #[inline]
176            fn iter_mut<'a, 'b>(
177                (#(#nvars),*): &'b mut Self::LockedColumns<'a>
178            ) -> Self::QueryResult<'b> {
179                #iter_mut_impl
180            }
181
182            #[inline]
183            fn iter_one<'a, 'b>(
184                (#(#nvars),*): &'b mut Self::LockedColumns<'a>,
185                index: usize,
186            ) -> Self::QueryResult<'b> {
187                #iter_one_impl
188            }
189
190            #[inline]
191            fn par_iter_mut<'a, 'b>(
192                len: usize,
193                (#(#nvars),*): &'b mut Self::LockedColumns<'a>
194            ) -> Self::ParQueryResult<'b> {
195                #par_iter_mut_impl
196            }
197        }
198    };
199
200    isquery_for_tuple.into()
201}
202
203#[proc_macro]
204pub fn impl_isbundle_tuple(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
205    let tuple: TypeTuple = parse_macro_input!(input);
206    let tys = tuple.elems.iter().collect::<Vec<_>>();
207    let ns = (0..tys.len())
208        .map(|n| syn::Member::Unnamed(n.into()))
209        .collect::<Vec<_>>();
210    let isbundle_for_tuple = quote! {
211        impl <#(#tys),*> apecs::storage::archetype::IsBundle for #tuple
212        where
213            #(#tys: Send + Sync + 'static),*
214        {
215            type EntryBundle = (
216                #(Entry<#tys>),*
217            );
218            type MutBundle = (
219                #(&'static mut #tys),*
220            );
221
222            fn unordered_types() -> SmallVec<[TypeId; 4]> {
223                smallvec![
224                    #(TypeId::of::<#tys>()),*
225                ]
226            }
227
228            fn empty_vecs() -> SmallVec<[AnyVec<dyn Send + Sync + 'static>; 4]> {
229                smallvec![
230                    #(AnyVec::new::<#tys>()),*
231                ]
232            }
233
234            fn try_from_any_bundle(mut bundle: AnyBundle) -> Result<Self, BundleError> {
235                Ok((
236                    #(bundle.remove::<#tys>(&TypeId::of::<#tys>())?),*
237                ))
238            }
239
240            fn into_vecs(self) -> SmallVec<[AnyVec<dyn Send + Sync + 'static>; 4]> {
241                smallvec![
242                    #(AnyVec::wrap(self.#ns)),*
243                ]
244            }
245
246            fn into_entry_bundle(self, entity_id: usize) -> Self::EntryBundle {
247                (
248                    #(Entry::new(entity_id, self.#ns)),*
249                )
250            }
251
252            fn from_entry_bundle(entry_bundle: Self::EntryBundle) -> Self {
253                (
254                    #(entry_bundle.#ns.into_inner()),*
255                )
256            }
257
258        }
259    };
260
261    isbundle_for_tuple.into()
262}