1#![allow(missing_docs, reason = "Not all docs are written yet, see #3492.")]
3#![cfg_attr(docsrs, feature(doc_auto_cfg))]
4
5extern crate proc_macro;
6
7mod component;
8mod query_data;
9mod query_filter;
10mod states;
11mod world_query;
12
13use crate::{query_data::derive_query_data_impl, query_filter::derive_query_filter_impl};
14use bevy_macro_utils::{derive_label, ensure_no_collision, get_struct_fields, BevyManifest};
15use proc_macro::TokenStream;
16use proc_macro2::Span;
17use proc_macro2::TokenStream as TokenStream2;
18use quote::{format_ident, quote};
19use syn::{
20 parse_macro_input, parse_quote, punctuated::Punctuated, spanned::Spanned, token::Comma,
21 ConstParam, DeriveInput, GenericParam, Ident, Index, TypeParam,
22};
23
24enum BundleFieldKind {
25 Component,
26 Ignore,
27}
28
29const BUNDLE_ATTRIBUTE_NAME: &str = "bundle";
30const BUNDLE_ATTRIBUTE_IGNORE_NAME: &str = "ignore";
31
32#[proc_macro_derive(Bundle, attributes(bundle))]
33pub fn derive_bundle(input: TokenStream) -> TokenStream {
34 let ast = parse_macro_input!(input as DeriveInput);
35 let ecs_path = bevy_ecs_path();
36
37 let named_fields = match get_struct_fields(&ast.data) {
38 Ok(fields) => fields,
39 Err(e) => return e.into_compile_error().into(),
40 };
41
42 let mut field_kind = Vec::with_capacity(named_fields.len());
43
44 for field in named_fields {
45 for attr in field
46 .attrs
47 .iter()
48 .filter(|a| a.path().is_ident(BUNDLE_ATTRIBUTE_NAME))
49 {
50 if let Err(error) = attr.parse_nested_meta(|meta| {
51 if meta.path.is_ident(BUNDLE_ATTRIBUTE_IGNORE_NAME) {
52 field_kind.push(BundleFieldKind::Ignore);
53 Ok(())
54 } else {
55 Err(meta.error(format!(
56 "Invalid bundle attribute. Use `{BUNDLE_ATTRIBUTE_IGNORE_NAME}`"
57 )))
58 }
59 }) {
60 return error.into_compile_error().into();
61 }
62 }
63
64 field_kind.push(BundleFieldKind::Component);
65 }
66
67 let field = named_fields
68 .iter()
69 .map(|field| field.ident.as_ref())
70 .collect::<Vec<_>>();
71
72 let field_type = named_fields
73 .iter()
74 .map(|field| &field.ty)
75 .collect::<Vec<_>>();
76
77 let mut field_component_ids = Vec::new();
78 let mut field_get_component_ids = Vec::new();
79 let mut field_get_components = Vec::new();
80 let mut field_from_components = Vec::new();
81 let mut field_required_components = Vec::new();
82 for (((i, field_type), field_kind), field) in field_type
83 .iter()
84 .enumerate()
85 .zip(field_kind.iter())
86 .zip(field.iter())
87 {
88 match field_kind {
89 BundleFieldKind::Component => {
90 field_component_ids.push(quote! {
91 <#field_type as #ecs_path::bundle::Bundle>::component_ids(components, storages, &mut *ids);
92 });
93 field_required_components.push(quote! {
94 <#field_type as #ecs_path::bundle::Bundle>::register_required_components(components, storages, required_components);
95 });
96 field_get_component_ids.push(quote! {
97 <#field_type as #ecs_path::bundle::Bundle>::get_component_ids(components, &mut *ids);
98 });
99 match field {
100 Some(field) => {
101 field_get_components.push(quote! {
102 self.#field.get_components(&mut *func);
103 });
104 field_from_components.push(quote! {
105 #field: <#field_type as #ecs_path::bundle::Bundle>::from_components(ctx, &mut *func),
106 });
107 }
108 None => {
109 let index = Index::from(i);
110 field_get_components.push(quote! {
111 self.#index.get_components(&mut *func);
112 });
113 field_from_components.push(quote! {
114 #index: <#field_type as #ecs_path::bundle::Bundle>::from_components(ctx, &mut *func),
115 });
116 }
117 }
118 }
119
120 BundleFieldKind::Ignore => {
121 field_from_components.push(quote! {
122 #field: ::core::default::Default::default(),
123 });
124 }
125 }
126 }
127 let generics = ast.generics;
128 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
129 let struct_name = &ast.ident;
130
131 TokenStream::from(quote! {
132 unsafe impl #impl_generics #ecs_path::bundle::Bundle for #struct_name #ty_generics #where_clause {
137 fn component_ids(
138 components: &mut #ecs_path::component::Components,
139 storages: &mut #ecs_path::storage::Storages,
140 ids: &mut impl FnMut(#ecs_path::component::ComponentId)
141 ){
142 #(#field_component_ids)*
143 }
144
145 fn get_component_ids(
146 components: &#ecs_path::component::Components,
147 ids: &mut impl FnMut(Option<#ecs_path::component::ComponentId>)
148 ){
149 #(#field_get_component_ids)*
150 }
151
152 #[allow(unused_variables, non_snake_case)]
153 unsafe fn from_components<__T, __F>(ctx: &mut __T, func: &mut __F) -> Self
154 where
155 __F: FnMut(&mut __T) -> #ecs_path::ptr::OwningPtr<'_>
156 {
157 Self{
158 #(#field_from_components)*
159 }
160 }
161
162 fn register_required_components(
163 components: &mut #ecs_path::component::Components,
164 storages: &mut #ecs_path::storage::Storages,
165 required_components: &mut #ecs_path::component::RequiredComponents
166 ){
167 #(#field_required_components)*
168 }
169 }
170
171 impl #impl_generics #ecs_path::bundle::DynamicBundle for #struct_name #ty_generics #where_clause {
172 #[allow(unused_variables)]
173 #[inline]
174 fn get_components(
175 self,
176 func: &mut impl FnMut(#ecs_path::component::StorageType, #ecs_path::ptr::OwningPtr<'_>)
177 ) {
178 #(#field_get_components)*
179 }
180 }
181 })
182}
183
184fn derive_visit_entities_base(
185 input: TokenStream,
186 trait_name: TokenStream2,
187 gen_methods: impl FnOnce(Vec<TokenStream2>) -> TokenStream2,
188) -> TokenStream {
189 let ast = parse_macro_input!(input as DeriveInput);
190 let ecs_path = bevy_ecs_path();
191
192 let named_fields = match get_struct_fields(&ast.data) {
193 Ok(fields) => fields,
194 Err(e) => return e.into_compile_error().into(),
195 };
196
197 let field = named_fields
198 .iter()
199 .filter_map(|field| {
200 if let Some(attr) = field
201 .attrs
202 .iter()
203 .find(|a| a.path().is_ident("visit_entities"))
204 {
205 let ignore = attr.parse_nested_meta(|meta| {
206 if meta.path.is_ident("ignore") {
207 Ok(())
208 } else {
209 Err(meta.error("Invalid visit_entities attribute. Use `ignore`"))
210 }
211 });
212 return match ignore {
213 Ok(()) => None,
214 Err(e) => Some(Err(e)),
215 };
216 }
217 Some(Ok(field))
218 })
219 .map(|res| res.map(|field| field.ident.as_ref()))
220 .collect::<Result<Vec<_>, _>>();
221
222 let field = match field {
223 Ok(field) => field,
224 Err(e) => return e.into_compile_error().into(),
225 };
226
227 if field.is_empty() {
228 return syn::Error::new(
229 ast.span(),
230 format!("Invalid `{}` type: at least one field", trait_name),
231 )
232 .into_compile_error()
233 .into();
234 }
235
236 let field_access = field
237 .iter()
238 .enumerate()
239 .map(|(n, f)| {
240 if let Some(ident) = f {
241 quote! {
242 self.#ident
243 }
244 } else {
245 let idx = Index::from(n);
246 quote! {
247 self.#idx
248 }
249 }
250 })
251 .collect::<Vec<_>>();
252
253 let methods = gen_methods(field_access);
254
255 let generics = ast.generics;
256 let (impl_generics, ty_generics, _) = generics.split_for_impl();
257 let struct_name = &ast.ident;
258
259 TokenStream::from(quote! {
260 impl #impl_generics #ecs_path::entity:: #trait_name for #struct_name #ty_generics {
261 #methods
262 }
263 })
264}
265
266#[proc_macro_derive(VisitEntitiesMut, attributes(visit_entities))]
267pub fn derive_visit_entities_mut(input: TokenStream) -> TokenStream {
268 derive_visit_entities_base(input, quote! { VisitEntitiesMut }, |field| {
269 quote! {
270 fn visit_entities_mut<F: FnMut(&mut Entity)>(&mut self, mut f: F) {
271 #(#field.visit_entities_mut(&mut f);)*
272 }
273 }
274 })
275}
276
277#[proc_macro_derive(VisitEntities, attributes(visit_entities))]
278pub fn derive_visit_entities(input: TokenStream) -> TokenStream {
279 derive_visit_entities_base(input, quote! { VisitEntities }, |field| {
280 quote! {
281 fn visit_entities<F: FnMut(Entity)>(&self, mut f: F) {
282 #(#field.visit_entities(&mut f);)*
283 }
284 }
285 })
286}
287
288fn get_idents(fmt_string: fn(usize) -> String, count: usize) -> Vec<Ident> {
289 (0..count)
290 .map(|i| Ident::new(&fmt_string(i), Span::call_site()))
291 .collect::<Vec<Ident>>()
292}
293
294#[proc_macro]
295pub fn impl_param_set(_input: TokenStream) -> TokenStream {
296 let mut tokens = TokenStream::new();
297 let max_params = 8;
298 let params = get_idents(|i| format!("P{i}"), max_params);
299 let metas = get_idents(|i| format!("m{i}"), max_params);
300 let mut param_fn_muts = Vec::new();
301 for (i, param) in params.iter().enumerate() {
302 let fn_name = Ident::new(&format!("p{i}"), Span::call_site());
303 let index = Index::from(i);
304 let ordinal = match i {
305 1 => "1st".to_owned(),
306 2 => "2nd".to_owned(),
307 3 => "3rd".to_owned(),
308 x => format!("{x}th"),
309 };
310 let comment =
311 format!("Gets exclusive access to the {ordinal} parameter in this [`ParamSet`].");
312 param_fn_muts.push(quote! {
313 #[doc = #comment]
314 pub fn #fn_name<'a>(&'a mut self) -> SystemParamItem<'a, 'a, #param> {
316 unsafe {
320 #param::get_param(&mut self.param_states.#index, &self.system_meta, self.world, self.change_tick)
321 }
322 }
323 });
324 }
325
326 for param_count in 1..=max_params {
327 let param = ¶ms[0..param_count];
328 let meta = &metas[0..param_count];
329 let param_fn_mut = ¶m_fn_muts[0..param_count];
330 tokens.extend(TokenStream::from(quote! {
331 unsafe impl<'w, 's, #(#param,)*> ReadOnlySystemParam for ParamSet<'w, 's, (#(#param,)*)>
333 where #(#param: ReadOnlySystemParam,)*
334 { }
335
336 unsafe impl<'_w, '_s, #(#param: SystemParam,)*> SystemParam for ParamSet<'_w, '_s, (#(#param,)*)>
339 {
340 type State = (#(#param::State,)*);
341 type Item<'w, 's> = ParamSet<'w, 's, (#(#param,)*)>;
342
343 #[allow(non_snake_case)]
345 fn init_state(world: &mut World, system_meta: &mut SystemMeta) -> Self::State {
346 #(
347 let mut #meta = system_meta.clone();
349 #meta.component_access_set.clear();
350 #meta.archetype_component_access.clear();
351 #param::init_state(world, &mut #meta);
352 let #param = #param::init_state(world, &mut system_meta.clone());
354 )*
355 if false #(|| !#meta.is_send())* {
357 system_meta.set_non_send();
358 }
359 #(
360 system_meta
361 .component_access_set
362 .extend(#meta.component_access_set);
363 system_meta
364 .archetype_component_access
365 .extend(&#meta.archetype_component_access);
366 )*
367 (#(#param,)*)
368 }
369
370 unsafe fn new_archetype(state: &mut Self::State, archetype: &Archetype, system_meta: &mut SystemMeta) {
371 unsafe { <(#(#param,)*) as SystemParam>::new_archetype(state, archetype, system_meta); }
373 }
374
375 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
376 <(#(#param,)*) as SystemParam>::apply(state, system_meta, world);
377 }
378
379 fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
380 <(#(#param,)*) as SystemParam>::queue(state, system_meta, world.reborrow());
381 }
382
383 #[inline]
384 unsafe fn validate_param<'w, 's>(
385 state: &'s Self::State,
386 system_meta: &SystemMeta,
387 world: UnsafeWorldCell<'w>,
388 ) -> bool {
389 <(#(#param,)*) as SystemParam>::validate_param(state, system_meta, world)
390 }
391
392 #[inline]
393 unsafe fn get_param<'w, 's>(
394 state: &'s mut Self::State,
395 system_meta: &SystemMeta,
396 world: UnsafeWorldCell<'w>,
397 change_tick: Tick,
398 ) -> Self::Item<'w, 's> {
399 ParamSet {
400 param_states: state,
401 system_meta: system_meta.clone(),
402 world,
403 change_tick,
404 }
405 }
406 }
407
408 impl<'w, 's, #(#param: SystemParam,)*> ParamSet<'w, 's, (#(#param,)*)>
409 {
410 #(#param_fn_mut)*
411 }
412 }));
413 }
414
415 tokens
416}
417
418#[proc_macro_derive(SystemParam, attributes(system_param))]
420pub fn derive_system_param(input: TokenStream) -> TokenStream {
421 let token_stream = input.clone();
422 let ast = parse_macro_input!(input as DeriveInput);
423 let syn::Data::Struct(syn::DataStruct {
424 fields: field_definitions,
425 ..
426 }) = ast.data
427 else {
428 return syn::Error::new(
429 ast.span(),
430 "Invalid `SystemParam` type: expected a `struct`",
431 )
432 .into_compile_error()
433 .into();
434 };
435 let path = bevy_ecs_path();
436
437 let mut field_locals = Vec::new();
438 let mut fields = Vec::new();
439 let mut field_types = Vec::new();
440 for (i, field) in field_definitions.iter().enumerate() {
441 field_locals.push(format_ident!("f{i}"));
442 let i = Index::from(i);
443 fields.push(
444 field
445 .ident
446 .as_ref()
447 .map(|f| quote! { #f })
448 .unwrap_or_else(|| quote! { #i }),
449 );
450 field_types.push(&field.ty);
451 }
452
453 let generics = ast.generics;
454
455 for lt in generics.lifetimes() {
457 let ident = <.lifetime.ident;
458 let w = format_ident!("w");
459 let s = format_ident!("s");
460 if ident != &w && ident != &s {
461 return syn::Error::new_spanned(
462 lt,
463 r#"invalid lifetime name: expected `'w` or `'s`
464 'w -- refers to data stored in the World.
465 's -- refers to data stored in the SystemParam's state.'"#,
466 )
467 .into_compile_error()
468 .into();
469 }
470 }
471
472 let (_impl_generics, ty_generics, where_clause) = generics.split_for_impl();
473
474 let lifetimeless_generics: Vec<_> = generics
475 .params
476 .iter()
477 .filter(|g| !matches!(g, GenericParam::Lifetime(_)))
478 .collect();
479
480 let shadowed_lifetimes: Vec<_> = generics.lifetimes().map(|_| quote!('_)).collect();
481
482 let mut punctuated_generics = Punctuated::<_, Comma>::new();
483 punctuated_generics.extend(lifetimeless_generics.iter().map(|g| match g {
484 GenericParam::Type(g) => GenericParam::Type(TypeParam {
485 default: None,
486 ..g.clone()
487 }),
488 GenericParam::Const(g) => GenericParam::Const(ConstParam {
489 default: None,
490 ..g.clone()
491 }),
492 _ => unreachable!(),
493 }));
494
495 let mut punctuated_generic_idents = Punctuated::<_, Comma>::new();
496 punctuated_generic_idents.extend(lifetimeless_generics.iter().map(|g| match g {
497 GenericParam::Type(g) => &g.ident,
498 GenericParam::Const(g) => &g.ident,
499 _ => unreachable!(),
500 }));
501
502 let punctuated_generics_no_bounds: Punctuated<_, Comma> = lifetimeless_generics
503 .iter()
504 .map(|&g| match g.clone() {
505 GenericParam::Type(mut g) => {
506 g.bounds.clear();
507 GenericParam::Type(g)
508 }
509 g => g,
510 })
511 .collect();
512
513 let mut tuple_types: Vec<_> = field_types.iter().map(|x| quote! { #x }).collect();
514 let mut tuple_patterns: Vec<_> = field_locals.iter().map(|x| quote! { #x }).collect();
515
516 const LIMIT: usize = 16;
519 while tuple_types.len() > LIMIT {
520 let end = Vec::from_iter(tuple_types.drain(..LIMIT));
521 tuple_types.push(parse_quote!( (#(#end,)*) ));
522
523 let end = Vec::from_iter(tuple_patterns.drain(..LIMIT));
524 tuple_patterns.push(parse_quote!( (#(#end,)*) ));
525 }
526
527 let mut read_only_generics = generics.clone();
530 let read_only_where_clause = read_only_generics.make_where_clause();
531 for field_type in &field_types {
532 read_only_where_clause
533 .predicates
534 .push(syn::parse_quote!(#field_type: #path::system::ReadOnlySystemParam));
535 }
536
537 let fields_alias =
538 ensure_no_collision(format_ident!("__StructFieldsAlias"), token_stream.clone());
539
540 let struct_name = &ast.ident;
541 let state_struct_visibility = &ast.vis;
542 let state_struct_name = ensure_no_collision(format_ident!("FetchState"), token_stream);
543
544 let mut builder_name = None;
545 for meta in ast
546 .attrs
547 .iter()
548 .filter(|a| a.path().is_ident("system_param"))
549 {
550 if let Err(e) = meta.parse_nested_meta(|nested| {
551 if nested.path.is_ident("builder") {
552 builder_name = Some(format_ident!("{struct_name}Builder"));
553 Ok(())
554 } else {
555 Err(nested.error("Unsupported attribute"))
556 }
557 }) {
558 return e.into_compile_error().into();
559 }
560 }
561
562 let builder = builder_name.map(|builder_name| {
563 let builder_type_parameters: Vec<_> = (0..fields.len()).map(|i| format_ident!("B{i}")).collect();
564 let builder_doc_comment = format!("A [`SystemParamBuilder`] for a [`{struct_name}`].");
565 let builder_struct = quote! {
566 #[doc = #builder_doc_comment]
567 struct #builder_name<#(#builder_type_parameters,)*> {
568 #(#fields: #builder_type_parameters,)*
569 }
570 };
571 let lifetimes: Vec<_> = generics.lifetimes().collect();
572 let generic_struct = quote!{ #struct_name <#(#lifetimes,)* #punctuated_generic_idents> };
573 let builder_impl = quote!{
574 unsafe impl<
576 #(#lifetimes,)*
577 #(#builder_type_parameters: #path::system::SystemParamBuilder<#field_types>,)*
578 #punctuated_generics
579 > #path::system::SystemParamBuilder<#generic_struct> for #builder_name<#(#builder_type_parameters,)*>
580 #where_clause
581 {
582 fn build(self, world: &mut #path::world::World, meta: &mut #path::system::SystemMeta) -> <#generic_struct as #path::system::SystemParam>::State {
583 let #builder_name { #(#fields: #field_locals,)* } = self;
584 #state_struct_name {
585 state: #path::system::SystemParamBuilder::build((#(#tuple_patterns,)*), world, meta)
586 }
587 }
588 }
589 };
590 (builder_struct, builder_impl)
591 });
592 let (builder_struct, builder_impl) = builder.unzip();
593
594 TokenStream::from(quote! {
595 const _: () = {
599 type #fields_alias <'w, 's, #punctuated_generics_no_bounds> = (#(#tuple_types,)*);
601
602 #[doc(hidden)]
603 #state_struct_visibility struct #state_struct_name <#(#lifetimeless_generics,)*>
604 #where_clause {
605 state: <#fields_alias::<'static, 'static, #punctuated_generic_idents> as #path::system::SystemParam>::State,
606 }
607
608 unsafe impl<#punctuated_generics> #path::system::SystemParam for
609 #struct_name <#(#shadowed_lifetimes,)* #punctuated_generic_idents> #where_clause
610 {
611 type State = #state_struct_name<#punctuated_generic_idents>;
612 type Item<'w, 's> = #struct_name #ty_generics;
613
614 fn init_state(world: &mut #path::world::World, system_meta: &mut #path::system::SystemMeta) -> Self::State {
615 #state_struct_name {
616 state: <#fields_alias::<'_, '_, #punctuated_generic_idents> as #path::system::SystemParam>::init_state(world, system_meta),
617 }
618 }
619
620 unsafe fn new_archetype(state: &mut Self::State, archetype: &#path::archetype::Archetype, system_meta: &mut #path::system::SystemMeta) {
621 unsafe { <#fields_alias::<'_, '_, #punctuated_generic_idents> as #path::system::SystemParam>::new_archetype(&mut state.state, archetype, system_meta) }
623 }
624
625 fn apply(state: &mut Self::State, system_meta: &#path::system::SystemMeta, world: &mut #path::world::World) {
626 <#fields_alias::<'_, '_, #punctuated_generic_idents> as #path::system::SystemParam>::apply(&mut state.state, system_meta, world);
627 }
628
629 fn queue(state: &mut Self::State, system_meta: &#path::system::SystemMeta, world: #path::world::DeferredWorld) {
630 <#fields_alias::<'_, '_, #punctuated_generic_idents> as #path::system::SystemParam>::queue(&mut state.state, system_meta, world);
631 }
632
633 #[inline]
634 unsafe fn validate_param<'w, 's>(
635 state: &'s Self::State,
636 system_meta: &#path::system::SystemMeta,
637 world: #path::world::unsafe_world_cell::UnsafeWorldCell<'w>,
638 ) -> bool {
639 <(#(#tuple_types,)*) as #path::system::SystemParam>::validate_param(&state.state, system_meta, world)
640 }
641
642 #[inline]
643 unsafe fn get_param<'w, 's>(
644 state: &'s mut Self::State,
645 system_meta: &#path::system::SystemMeta,
646 world: #path::world::unsafe_world_cell::UnsafeWorldCell<'w>,
647 change_tick: #path::component::Tick,
648 ) -> Self::Item<'w, 's> {
649 let (#(#tuple_patterns,)*) = <
650 (#(#tuple_types,)*) as #path::system::SystemParam
651 >::get_param(&mut state.state, system_meta, world, change_tick);
652 #struct_name {
653 #(#fields: #field_locals,)*
654 }
655 }
656 }
657
658 unsafe impl<'w, 's, #punctuated_generics> #path::system::ReadOnlySystemParam for #struct_name #ty_generics #read_only_where_clause {}
660
661 #builder_impl
662 };
663
664 #builder_struct
665 })
666}
667
668#[proc_macro_derive(QueryData, attributes(query_data))]
670pub fn derive_query_data(input: TokenStream) -> TokenStream {
671 derive_query_data_impl(input)
672}
673
674#[proc_macro_derive(QueryFilter, attributes(query_filter))]
676pub fn derive_query_filter(input: TokenStream) -> TokenStream {
677 derive_query_filter_impl(input)
678}
679
680#[proc_macro_derive(ScheduleLabel)]
684pub fn derive_schedule_label(input: TokenStream) -> TokenStream {
685 let input = parse_macro_input!(input as DeriveInput);
686 let mut trait_path = bevy_ecs_path();
687 trait_path.segments.push(format_ident!("schedule").into());
688 let mut dyn_eq_path = trait_path.clone();
689 trait_path
690 .segments
691 .push(format_ident!("ScheduleLabel").into());
692 dyn_eq_path.segments.push(format_ident!("DynEq").into());
693 derive_label(input, "ScheduleLabel", &trait_path, &dyn_eq_path)
694}
695
696#[proc_macro_derive(SystemSet)]
700pub fn derive_system_set(input: TokenStream) -> TokenStream {
701 let input = parse_macro_input!(input as DeriveInput);
702 let mut trait_path = bevy_ecs_path();
703 trait_path.segments.push(format_ident!("schedule").into());
704 let mut dyn_eq_path = trait_path.clone();
705 trait_path.segments.push(format_ident!("SystemSet").into());
706 dyn_eq_path.segments.push(format_ident!("DynEq").into());
707 derive_label(input, "SystemSet", &trait_path, &dyn_eq_path)
708}
709
710pub(crate) fn bevy_ecs_path() -> syn::Path {
711 BevyManifest::default().get_path("bevy_ecs")
712}
713
714#[proc_macro_derive(Event)]
715pub fn derive_event(input: TokenStream) -> TokenStream {
716 component::derive_event(input)
717}
718
719#[proc_macro_derive(Resource)]
720pub fn derive_resource(input: TokenStream) -> TokenStream {
721 component::derive_resource(input)
722}
723
724#[proc_macro_derive(Component, attributes(component, require))]
725pub fn derive_component(input: TokenStream) -> TokenStream {
726 component::derive_component(input)
727}
728
729#[proc_macro_derive(States)]
730pub fn derive_states(input: TokenStream) -> TokenStream {
731 states::derive_states(input)
732}
733
734#[proc_macro_derive(SubStates, attributes(source))]
735pub fn derive_substates(input: TokenStream) -> TokenStream {
736 states::derive_substates(input)
737}