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 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}