1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use proc_macro2::Span;
5use quote::{format_ident, quote};
6use syn::{
7 parse::{Parse, ParseStream},
8 parse_macro_input,
9 token::Comma,
10 DeriveInput, Ident, Index, ItemFn, LitInt, Path, Result,
11};
12
13mod zengine_manifest;
14use zengine_manifest::ZENgineManifest;
15
16pub(crate) fn zengine_ecs_path() -> syn::Path {
17 ZENgineManifest::default().get_path("zengine_ecs")
18}
19
20#[proc_macro_derive(Component)]
22pub fn component_macro_derive(input: TokenStream) -> TokenStream {
23 let input = parse_macro_input!(input as DeriveInput);
24 let zengine_ecs_path: Path = crate::zengine_ecs_path();
25
26 let name = input.ident;
27 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
28
29 let expanded = quote! {
30 impl #impl_generics #zengine_ecs_path::Component for #name #ty_generics #where_clause {}
31 };
32
33 TokenStream::from(expanded)
34}
35
36#[proc_macro_derive(Resource)]
38pub fn resource_macro_derive(input: TokenStream) -> TokenStream {
39 let input = parse_macro_input!(input as DeriveInput);
40 let zengine_ecs_path: Path = crate::zengine_ecs_path();
41
42 let name = input.ident;
43 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
44
45 let expanded = quote! {
46 impl #impl_generics #zengine_ecs_path::Resource for #name #ty_generics #where_clause {}
47 };
48
49 TokenStream::from(expanded)
50}
51
52#[proc_macro_derive(UnsendableResource)]
54pub fn unsendable_resource_macro_derive(input: TokenStream) -> TokenStream {
55 let input = parse_macro_input!(input as DeriveInput);
56 let zengine_ecs_path: Path = crate::zengine_ecs_path();
57
58 let name = input.ident;
59 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
60
61 let expanded = quote! {
62 impl #impl_generics #zengine_ecs_path::UnsendableResource for #name #ty_generics #where_clause {}
63 };
64
65 TokenStream::from(expanded)
66}
67
68#[proc_macro_derive(Asset)]
70pub fn asset_macro_derive(input: TokenStream) -> TokenStream {
71 let input = parse_macro_input!(input as DeriveInput);
72 let zengine_asset_path: Path = ZENgineManifest::default().get_path("zengine_asset");
73
74 let name = input.ident;
75 let asset_counter = format_ident!("{}_COUNTER", name.to_string().to_uppercase());
76 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
77
78 let expanded = quote! {
79 static #asset_counter: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
80 impl #impl_generics #zengine_asset_path::Asset for #name #ty_generics #where_clause {
81 fn next_counter() -> u64
82 where
83 Self: Sized,
84 {
85 #asset_counter.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
86 }
87 }
88 };
89
90 TokenStream::from(expanded)
91}
92
93#[proc_macro_derive(InputType)]
95pub fn input_type_macro_derive(input: TokenStream) -> TokenStream {
96 let input = parse_macro_input!(input as DeriveInput);
97 let zengine_input_path = ZENgineManifest::default().get_path("zengine_input");
98
99 let name = input.ident;
100 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
101
102 let expanded = quote! {
103 impl #impl_generics #zengine_input_path::InputType for #name #ty_generics #where_clause {}
104 };
105
106 TokenStream::from(expanded)
107}
108
109struct AllTuples {
110 macro_ident: Ident,
111 start: usize,
112 end: usize,
113 ident: Ident,
114}
115
116impl Parse for AllTuples {
117 fn parse(input: ParseStream) -> Result<Self> {
118 let macro_ident = input.parse::<Ident>()?;
119 input.parse::<Comma>()?;
120 let start = input.parse::<LitInt>()?.base10_parse()?;
121 input.parse::<Comma>()?;
122 let end = input.parse::<LitInt>()?.base10_parse()?;
123 input.parse::<Comma>()?;
124 let ident = input.parse::<Ident>()?;
125
126 Ok(AllTuples {
127 macro_ident,
128 start,
129 end,
130 ident,
131 })
132 }
133}
134
135#[doc(hidden)]
136#[proc_macro]
137pub fn all_tuples(input: TokenStream) -> TokenStream {
138 let input = parse_macro_input!(input as AllTuples);
139 let len = input.end - input.start;
140 let mut ident_tuples = Vec::with_capacity(len);
141 for i in input.start..=input.end {
142 let ident = format_ident!("{}{}", input.ident, i);
143 ident_tuples.push(quote! {
144 #ident
145 });
146 }
147
148 let macro_ident = &input.macro_ident;
149 let invocations = (input.start..=input.end).map(|i| {
150 let ident_tuples = &ident_tuples[0..i - input.start];
151 quote! {
152 #macro_ident!(#(#ident_tuples),*);
153 }
154 });
155 TokenStream::from(quote! {
156 #(
157 #invocations
158 )*
159 })
160}
161
162#[doc(hidden)]
163#[proc_macro]
164pub fn all_tuples_with_idexes(input: TokenStream) -> TokenStream {
165 let input = parse_macro_input!(input as AllTuples);
166 let len = input.end - input.start;
167 let mut ident_tuples = Vec::with_capacity(len);
168 for i in input.start..=input.end {
169 let ident = format_ident!("{}{}", input.ident, i);
170 let position: Index = syn::Index {
171 index: i as u32,
172 span: Span::call_site(),
173 };
174 ident_tuples.push(quote! {
175 #ident => #position
176 });
177 }
178
179 let macro_ident = &input.macro_ident;
180 let invocations = (input.start..=input.end).map(|i| {
181 let ident_tuples = &ident_tuples[0..i - input.start];
182 quote! {
183 #macro_ident!(#(#ident_tuples),*);
184 }
185 });
186 TokenStream::from(quote! {
187 #(
188 #invocations
189 )*
190 })
191}
192
193#[doc(hidden)]
194#[proc_macro]
195pub fn all_positional_tuples(input: TokenStream) -> TokenStream {
196 let input = parse_macro_input!(input as AllTuples);
197 let len = input.end - input.start;
198 let mut ident_tuples = Vec::with_capacity(len);
199 for i in input.start..=input.end {
200 let position: Index = syn::Index {
201 index: i as u32,
202 span: Span::call_site(),
203 };
204 let ident = format_ident!("{}{}", input.ident, i);
205 ident_tuples.push(quote! {
206 #ident => #position
207 });
208 }
209
210 let macro_ident = &input.macro_ident;
211 let invocations = (input.start..=input.end).map(|i| {
212 let ident_tuples = &ident_tuples[0..i - input.start];
213 quote! {
214 #macro_ident!(#(#ident_tuples),*);
215 }
216 });
217
218 TokenStream::from(quote! {
219 #(
220 #invocations
221 )*
222 })
223}
224
225struct ZipInput {
226 end: usize,
227}
228
229impl Parse for ZipInput {
230 fn parse(input: ParseStream) -> Result<Self> {
231 let end = input.parse::<LitInt>()?.base10_parse()?;
232
233 Ok(ZipInput { end })
234 }
235}
236
237#[doc(hidden)]
238#[proc_macro]
239pub fn generate_zip(input: TokenStream) -> TokenStream {
240 let input = parse_macro_input!(input as ZipInput);
241 let mut expanded = quote! {};
242
243 for zip_number in 3..input.end {
244 let name = format_ident!("Zip{}", zip_number);
245
246 let identity = format_ident!("Z{}", 0_usize);
247 let identity_lower = format_ident!("z{}", 0_usize);
248
249 let mut generics_with_where = quote!( #identity: Iterator );
250 let mut generics = quote!( #identity );
251 let mut generics_args = quote!( #identity_lower: #identity );
252 for i in 1..zip_number {
253 let identity = format_ident!("Z{}", i);
254 let identity_lower = format_ident!("z{}", i);
255
256 generics_with_where.extend(quote! { , #identity: Iterator });
257 generics.extend(quote! { , #identity });
258 generics_args.extend(quote! { , #identity_lower: #identity })
259 }
260
261 let generics = quote!( < #generics > );
262 let generics_with_where = quote!( < #generics_with_where > );
263
264 let mut zip_type = quote! {};
265 for _i in 0..zip_number - 1 {
266 zip_type.extend(quote! { std::iter::Zip< });
267 }
268 zip_type.extend(quote! { Z0, Z1> });
269
270 for i in 2..zip_number {
271 let identity = format_ident!("Z{}", i);
272 zip_type.extend(quote! { , #identity > });
273 }
274
275 let identity1_lower = format_ident!("z{}", 0_usize);
276 let identity2_lower = format_ident!("z{}", 1_usize);
277 let mut zip_constructor = quote! { std::iter::zip(#identity1_lower, #identity2_lower) };
278 for i in 2..zip_number {
279 let identity_lower = format_ident!("z{}", i);
280 zip_constructor = quote! { std::iter::zip(#zip_constructor, #identity_lower) };
281 }
282
283 let mut map_constructor_args = quote! { (#identity1_lower, #identity2_lower) };
284 for i in 2..zip_number {
285 let identity_lower = format_ident!("z{}", i);
286 map_constructor_args = quote! { (#map_constructor_args, #identity_lower) };
287 }
288
289 let identity_lower = format_ident!("z{}", 0_usize);
290 let mut map_constructor_res = quote! { #identity_lower };
291 for i in 1..zip_number {
292 let identity_lower = format_ident!("z{}", i);
293 map_constructor_res.extend(quote! { , #identity_lower });
294 }
295
296 let identity = format_ident!("Z{}", 0_usize);
297 let mut iter_output = quote! { #identity ::Item };
298 for i in 1..zip_number {
299 let identity = format_ident!("Z{}", i);
300 iter_output.extend(quote! { , #identity ::Item });
301 }
302
303 let map_constructor = quote! { |#map_constructor_args| ( #map_constructor_res ) };
304
305 expanded.extend(quote! {
306 #[doc(hidden)]
307 pub struct #name #generics_with_where {
308 inner: #zip_type,
309 }
310
311 impl #generics_with_where #name #generics {
312 #[allow(clippy::too_many_arguments)]
313 pub fn new (#generics_args) -> Self {
314 Self {
315 inner: #zip_constructor
316 }
317 }
318 }
319
320 impl #generics_with_where Iterator for #name #generics {
321 type Item = (#iter_output);
322
323 #[inline(always)]
324 fn next(&mut self) -> Option<Self::Item> {
325 self.inner.next().map(#map_constructor)
326 }
327 #[inline]
328 fn size_hint(&self) -> (usize, Option<usize>) {
329 self.inner.size_hint()
330 }
331 }
332
333 });
334 }
335
336 TokenStream::from(expanded)
337}
338
339struct QueryIterInput {
340 end: usize,
341}
342
343impl Parse for QueryIterInput {
344 fn parse(input: ParseStream) -> Result<Self> {
345 let end = input.parse::<LitInt>()?.base10_parse()?;
346
347 Ok(QueryIterInput { end })
348 }
349}
350
351#[doc(hidden)]
352#[proc_macro]
353pub fn query_iter_for_tuple(input: TokenStream) -> TokenStream {
354 let input = parse_macro_input!(input as QueryIterInput);
355 let mut expanded = quote! {};
356
357 expanded.extend(quote!{
358 impl<'a, 'b, Z: QueryParameter> QueryIter<'b> for Query<'a, (Z,)>
359 where
360 <<Z as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem: QueryIter<'b>,
361 {
362 type Iter = QueryIterator<
363 <<<Z as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem as QueryIter<
364 'b,
365 >>::Iter
366 >;
367 fn iter(&'b self) -> Self::Iter {
368 QueryIterator::new(self.data.iter().map(|a| a.iter()).collect())
369 }
370 }
371 });
372
373 expanded.extend(quote!{
374 impl<'a, 'b, Z0: QueryParameter, Z1: QueryParameter> QueryIter<'b> for Query<'a, (Z0, Z1)>
375 where
376 <<Z0 as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem: QueryIter<'b>,
377 <<Z1 as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem: QueryIter<'b>,
378 {
379 type Iter = QueryIterator<
380 Zip<
381 <<<Z0 as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem as QueryIter<
382 'b,
383 >>::Iter,
384 <<<Z1 as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem as QueryIter<
385 'b,
386 >>::Iter,
387 >,
388 >;
389 fn iter(&'b self) -> Self::Iter {
390 QueryIterator::new(
391 self.data
392 .iter()
393 .map(|(z0, z1)| zip(z0.iter(), z1.iter()))
394 .collect(),
395 )
396 }
397 }
398 });
399
400 for zip_number in 3..input.end {
401 let zip_type = format_ident!("Zip{}", zip_number);
402
403 let identity = format_ident!("Z{}", 0_usize);
404 let identity_lowercase = format_ident!("z{}", 0_usize);
405 let mut generics = quote! { #identity: QueryParameter };
406 let mut tuple = quote! { #identity };
407 let mut where_clause = quote! { <<#identity as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem: QueryIter<'b> };
408 let mut zip_args = quote! { <<<#identity as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem as QueryIter<'b,>>::Iter };
409 let mut tuple_args = quote! { #identity_lowercase };
410 let mut tuple_iter = quote! { #identity_lowercase.iter() };
411 for i in 1..zip_number {
412 let identity = format_ident!("Z{}", i);
413 let identity_lowercase = format_ident!("z{}", i);
414 generics.extend(quote! { , #identity: QueryParameter });
415 tuple.extend(quote! { , #identity });
416 where_clause.extend(quote! { , <<#identity as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem: QueryIter<'b> });
417 zip_args.extend(quote! { , <<<#identity as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem as QueryIter<'b,>>::Iter });
418 tuple_args.extend(quote! { , #identity_lowercase });
419 tuple_iter.extend(quote! { , #identity_lowercase.iter() });
420 }
421
422 expanded.extend(quote! {
423 impl<'a, 'b, #generics> QueryIter<'b> for Query<'a, ( #tuple )>
424 where #where_clause
425 {
426 type Iter = QueryIterator<
427 #zip_type<#zip_args>,
428 >;
429 fn iter(&'b self) -> Self::Iter {
430 QueryIterator::new(
431 self.data
432 .iter()
433 .map(|( #tuple_args )| #zip_type::new( #tuple_iter ))
434 .collect(),
435 )
436 }
437 }
438 })
439 }
440
441 TokenStream::from(expanded)
442}
443
444#[doc(hidden)]
445#[proc_macro]
446pub fn query_iter_mut_for_tuple(input: TokenStream) -> TokenStream {
447 let input = parse_macro_input!(input as QueryIterInput);
448 let mut expanded = quote! {};
449
450 expanded.extend(quote!{
451 impl<'a, 'b, Z: QueryParameter> QueryIterMut<'b> for Query<'a, (Z,)>
452 where
453 <<Z as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem: QueryIterMut<'b>,
454 {
455 type Iter = QueryIterator<
456 <<<Z as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem as QueryIterMut<
457 'b,
458 >>::Iter
459 >;
460 fn iter_mut(&'b mut self) -> Self::Iter {
461 QueryIterator::new(self.data.iter_mut().map(|a| a.iter_mut()).collect())
462 }
463 }
464 });
465
466 expanded.extend(quote!{
467 impl<'a, 'b, Z0: QueryParameter, Z1: QueryParameter> QueryIterMut<'b> for Query<'a, (Z0, Z1)>
468 where
469 <<Z0 as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem: QueryIterMut<'b>,
470 <<Z1 as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem: QueryIterMut<'b>,
471 {
472 type Iter = QueryIterator<
473 Zip<
474 <<<Z0 as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem as QueryIterMut<
475 'b,
476 >>::Iter,
477 <<<Z1 as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem as QueryIterMut<
478 'b,
479 >>::Iter,
480 >,
481 >;
482 fn iter_mut(&'b mut self) -> Self::Iter {
483 QueryIterator::new(
484 self.data
485 .iter_mut()
486 .map(|(z0, z1)| zip(z0.iter_mut(), z1.iter_mut()))
487 .collect(),
488 )
489 }
490 }
491 });
492
493 for zip_number in 3..input.end {
494 let zip_type = format_ident!("Zip{}", zip_number);
495
496 let identity = format_ident!("Z{}", 0_usize);
497 let identity_lowercase = format_ident!("z{}", 0_usize);
498 let mut generics = quote! { #identity: QueryParameter };
499 let mut tuple = quote! { #identity };
500 let mut where_clause = quote! { <<#identity as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem: QueryIterMut<'b> };
501 let mut zip_args = quote! { <<<#identity as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem as QueryIterMut<'b,>>::Iter };
502 let mut tuple_args = quote! { #identity_lowercase };
503 let mut tuple_iter = quote! { #identity_lowercase.iter_mut() };
504 for i in 1..zip_number {
505 let identity = format_ident!("Z{}", i);
506 let identity_lowercase = format_ident!("z{}", i);
507 generics.extend(quote! { , #identity: QueryParameter });
508 tuple.extend(quote! { , #identity });
509 where_clause.extend(quote! { , <<#identity as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem: QueryIterMut<'b> });
510 zip_args.extend(quote! { , <<<#identity as QueryParameter>::Item as QueryParameterFetchFromArchetype<'a>>::ArchetypeFetchItem as QueryIterMut<'b,>>::Iter });
511 tuple_args.extend(quote! { , #identity_lowercase });
512 tuple_iter.extend(quote! { , #identity_lowercase.iter_mut() });
513 }
514
515 expanded.extend(quote! {
516 impl<'a, 'b, #generics> QueryIterMut<'b> for Query<'a, ( #tuple )>
517 where #where_clause
518 {
519 type Iter = QueryIterator<
520 #zip_type<#zip_args>,
521 >;
522 fn iter_mut(&'b mut self) -> Self::Iter {
523 QueryIterator::new(
524 self.data
525 .iter_mut()
526 .map(|( #tuple_args )| #zip_type::new( #tuple_iter ))
527 .collect(),
528 )
529 }
530 }
531 })
532 }
533
534 TokenStream::from(expanded)
535}
536
537#[proc_macro_attribute]
539pub fn zengine_main(_attr: TokenStream, item: TokenStream) -> TokenStream {
540 let input = parse_macro_input!(item as ItemFn);
541 assert!(
542 input.sig.ident == "main",
543 "`zengine_main` can only be used on a function called 'main'.",
544 );
545
546 TokenStream::from(quote! {
547 #[cfg(target_os = "android")]
548 #[cfg_attr(target_os = "android", zengine::ndk_glue::main(backtrace = "on", ndk_glue = "zengine::ndk_glue"))]
549 fn android_main() {
550 main()
551 }
552
553 #[allow(unused)]
554 #input
555 })
556}