bevy_ecs_macros/
lib.rs

1//! Macros for deriving ECS traits.
2
3#![cfg_attr(docsrs, feature(doc_cfg))]
4
5extern crate proc_macro;
6
7mod component;
8mod event;
9mod message;
10mod query_data;
11mod query_filter;
12mod world_query;
13
14use crate::{
15    component::map_entities, query_data::derive_query_data_impl,
16    query_filter::derive_query_filter_impl,
17};
18use bevy_macro_utils::{derive_label, ensure_no_collision, get_struct_fields, BevyManifest};
19use proc_macro::TokenStream;
20use proc_macro2::{Ident, Span};
21use quote::{format_ident, quote, ToTokens};
22use syn::{
23    parse_macro_input, parse_quote, punctuated::Punctuated, spanned::Spanned, token::Comma,
24    ConstParam, Data, DataStruct, DeriveInput, GenericParam, Index, TypeParam,
25};
26
27enum BundleFieldKind {
28    Component,
29    Ignore,
30}
31
32const BUNDLE_ATTRIBUTE_NAME: &str = "bundle";
33const BUNDLE_ATTRIBUTE_IGNORE_NAME: &str = "ignore";
34const BUNDLE_ATTRIBUTE_NO_FROM_COMPONENTS: &str = "ignore_from_components";
35
36#[derive(Debug)]
37struct BundleAttributes {
38    impl_from_components: bool,
39}
40
41impl Default for BundleAttributes {
42    fn default() -> Self {
43        Self {
44            impl_from_components: true,
45        }
46    }
47}
48
49/// Implement the `Bundle` trait.
50#[proc_macro_derive(Bundle, attributes(bundle))]
51pub fn derive_bundle(input: TokenStream) -> TokenStream {
52    let ast = parse_macro_input!(input as DeriveInput);
53    let ecs_path = bevy_ecs_path();
54
55    let mut errors = vec![];
56
57    let mut attributes = BundleAttributes::default();
58
59    for attr in &ast.attrs {
60        if attr.path().is_ident(BUNDLE_ATTRIBUTE_NAME) {
61            let parsing = attr.parse_nested_meta(|meta| {
62                if meta.path.is_ident(BUNDLE_ATTRIBUTE_NO_FROM_COMPONENTS) {
63                    attributes.impl_from_components = false;
64                    return Ok(());
65                }
66
67                Err(meta.error(format!("Invalid bundle container attribute. Allowed attributes: `{BUNDLE_ATTRIBUTE_NO_FROM_COMPONENTS}`")))
68            });
69
70            if let Err(error) = parsing {
71                errors.push(error.into_compile_error());
72            }
73        }
74    }
75
76    let named_fields = match get_struct_fields(&ast.data, "derive(Bundle)") {
77        Ok(fields) => fields,
78        Err(e) => return e.into_compile_error().into(),
79    };
80
81    let mut field_kind = Vec::with_capacity(named_fields.len());
82
83    for field in named_fields {
84        let mut kind = BundleFieldKind::Component;
85
86        for attr in field
87            .attrs
88            .iter()
89            .filter(|a| a.path().is_ident(BUNDLE_ATTRIBUTE_NAME))
90        {
91            if let Err(error) = attr.parse_nested_meta(|meta| {
92                if meta.path.is_ident(BUNDLE_ATTRIBUTE_IGNORE_NAME) {
93                    kind = BundleFieldKind::Ignore;
94                    Ok(())
95                } else {
96                    Err(meta.error(format!(
97                        "Invalid bundle attribute. Use `{BUNDLE_ATTRIBUTE_IGNORE_NAME}`"
98                    )))
99                }
100            }) {
101                return error.into_compile_error().into();
102            }
103        }
104
105        field_kind.push(kind);
106    }
107
108    let field = named_fields
109        .iter()
110        .map(|field| field.ident.as_ref())
111        .collect::<Vec<_>>();
112
113    let field_type = named_fields
114        .iter()
115        .map(|field| &field.ty)
116        .collect::<Vec<_>>();
117
118    let mut active_field_types = Vec::new();
119    let mut active_field_tokens = Vec::new();
120    let mut active_field_alias: Vec<proc_macro2::TokenStream> = Vec::new();
121    let mut inactive_field_tokens = Vec::new();
122    for (((i, field_type), field_kind), field) in field_type
123        .iter()
124        .enumerate()
125        .zip(field_kind.iter())
126        .zip(field.iter())
127    {
128        let field_alias = format_ident!("field_{}", i).to_token_stream();
129        let field_tokens = match field {
130            Some(field) => field.to_token_stream(),
131            None => Index::from(i).to_token_stream(),
132        };
133        match field_kind {
134            BundleFieldKind::Component => {
135                active_field_types.push(field_type);
136                active_field_alias.push(field_alias);
137                active_field_tokens.push(field_tokens);
138            }
139
140            BundleFieldKind::Ignore => inactive_field_tokens.push(field_tokens),
141        }
142    }
143    let generics = ast.generics;
144    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
145    let struct_name = &ast.ident;
146
147    let bundle_impl = quote! {
148        // SAFETY:
149        // - ComponentId is returned in field-definition-order. [get_components] uses field-definition-order
150        // - `Bundle::get_components` is exactly once for each member. Rely's on the Component -> Bundle implementation to properly pass
151        //   the correct `StorageType` into the callback.
152        #[allow(deprecated)]
153        unsafe impl #impl_generics #ecs_path::bundle::Bundle for #struct_name #ty_generics #where_clause {
154            fn component_ids(
155                components: &mut #ecs_path::component::ComponentsRegistrator,
156                ids: &mut impl FnMut(#ecs_path::component::ComponentId)
157            ) {
158                #(<#active_field_types as #ecs_path::bundle::Bundle>::component_ids(components, ids);)*
159            }
160
161            fn get_component_ids(
162                components: &#ecs_path::component::Components,
163                ids: &mut impl FnMut(Option<#ecs_path::component::ComponentId>)
164            ) {
165                #(<#active_field_types as #ecs_path::bundle::Bundle>::get_component_ids(components, &mut *ids);)*
166            }
167        }
168    };
169
170    let dynamic_bundle_impl = quote! {
171        impl #impl_generics #ecs_path::bundle::DynamicBundle for #struct_name #ty_generics #where_clause {
172            type Effect = ();
173            #[allow(unused_variables)]
174            #[inline]
175            unsafe fn get_components(
176                ptr: #ecs_path::ptr::MovingPtr<'_, Self>,
177                func: &mut impl FnMut(#ecs_path::component::StorageType, #ecs_path::ptr::OwningPtr<'_>)
178            ) {
179                use #ecs_path::__macro_exports::DebugCheckedUnwrap;
180
181                #ecs_path::ptr::deconstruct_moving_ptr!({
182                    let #struct_name { #(#active_field_tokens: #active_field_alias,)* #(#inactive_field_tokens: _,)* } = ptr;
183                });
184                #(
185                    <#active_field_types as #ecs_path::bundle::DynamicBundle>::get_components(
186                        #active_field_alias,
187                        func
188                    );
189                )*
190            }
191
192            #[allow(unused_variables)]
193            #[inline]
194            unsafe fn apply_effect(
195                ptr: #ecs_path::ptr::MovingPtr<'_, core::mem::MaybeUninit<Self>>,
196                func: &mut #ecs_path::world::EntityWorldMut<'_>,
197            ) {
198            }
199        }
200    };
201
202    let from_components_impl = attributes.impl_from_components.then(|| quote! {
203        // SAFETY:
204        // - ComponentId is returned in field-definition-order. [from_components] uses field-definition-order
205        #[allow(deprecated)]
206        unsafe impl #impl_generics #ecs_path::bundle::BundleFromComponents for #struct_name #ty_generics #where_clause {
207            #[allow(unused_variables, non_snake_case)]
208            unsafe fn from_components<__T, __F>(ctx: &mut __T, func: &mut __F) -> Self
209            where
210                __F: FnMut(&mut __T) -> #ecs_path::ptr::OwningPtr<'_>
211            {
212                Self {
213                    #(#active_field_tokens: <#active_field_types as #ecs_path::bundle::BundleFromComponents>::from_components(ctx, &mut *func),)*
214                    #(#inactive_field_tokens: ::core::default::Default::default(),)*
215                }
216            }
217        }
218    });
219
220    let attribute_errors = &errors;
221
222    TokenStream::from(quote! {
223        #(#attribute_errors)*
224        #bundle_impl
225        #from_components_impl
226        #dynamic_bundle_impl
227    })
228}
229
230/// Implement the `MapEntities` trait.
231#[proc_macro_derive(MapEntities, attributes(entities))]
232pub fn derive_map_entities(input: TokenStream) -> TokenStream {
233    let ast = parse_macro_input!(input as DeriveInput);
234    let ecs_path = bevy_ecs_path();
235
236    let map_entities_impl = map_entities(
237        &ast.data,
238        &ecs_path,
239        Ident::new("self", Span::call_site()),
240        false,
241        false,
242        None,
243    );
244
245    let struct_name = &ast.ident;
246    let (impl_generics, type_generics, where_clause) = &ast.generics.split_for_impl();
247    TokenStream::from(quote! {
248        impl #impl_generics #ecs_path::entity::MapEntities for #struct_name #type_generics #where_clause {
249            fn map_entities<M: #ecs_path::entity::EntityMapper>(&mut self, mapper: &mut M) {
250                #map_entities_impl
251            }
252        }
253    })
254}
255
256/// Implement `SystemParam` to use a struct as a parameter in a system
257#[proc_macro_derive(SystemParam, attributes(system_param))]
258pub fn derive_system_param(input: TokenStream) -> TokenStream {
259    let token_stream = input.clone();
260    let ast = parse_macro_input!(input as DeriveInput);
261    let Data::Struct(DataStruct {
262        fields: field_definitions,
263        ..
264    }) = ast.data
265    else {
266        return syn::Error::new(
267            ast.span(),
268            "Invalid `SystemParam` type: expected a `struct`",
269        )
270        .into_compile_error()
271        .into();
272    };
273    let path = bevy_ecs_path();
274
275    let mut field_locals = Vec::new();
276    let mut field_names = Vec::new();
277    let mut fields = Vec::new();
278    let mut field_types = Vec::new();
279    let mut field_messages = Vec::new();
280    for (i, field) in field_definitions.iter().enumerate() {
281        field_locals.push(format_ident!("f{i}"));
282        let i = Index::from(i);
283        let field_value = field
284            .ident
285            .as_ref()
286            .map(|f| quote! { #f })
287            .unwrap_or_else(|| quote! { #i });
288        field_names.push(format!("::{field_value}"));
289        fields.push(field_value);
290        field_types.push(&field.ty);
291        let mut field_message = None;
292        for meta in field
293            .attrs
294            .iter()
295            .filter(|a| a.path().is_ident("system_param"))
296        {
297            if let Err(e) = meta.parse_nested_meta(|nested| {
298                if nested.path.is_ident("validation_message") {
299                    field_message = Some(nested.value()?.parse()?);
300                    Ok(())
301                } else {
302                    Err(nested.error("Unsupported attribute"))
303                }
304            }) {
305                return e.into_compile_error().into();
306            }
307        }
308        field_messages.push(field_message.unwrap_or_else(|| quote! { err.message }));
309    }
310
311    let generics = ast.generics;
312
313    // Emit an error if there's any unrecognized lifetime names.
314    for lt in generics.lifetimes() {
315        let ident = &lt.lifetime.ident;
316        let w = format_ident!("w");
317        let s = format_ident!("s");
318        if ident != &w && ident != &s {
319            return syn::Error::new_spanned(
320                lt,
321                r#"invalid lifetime name: expected `'w` or `'s`
322 'w -- refers to data stored in the World.
323 's -- refers to data stored in the SystemParam's state.'"#,
324            )
325            .into_compile_error()
326            .into();
327        }
328    }
329
330    let (_impl_generics, ty_generics, where_clause) = generics.split_for_impl();
331
332    let lifetimeless_generics: Vec<_> = generics
333        .params
334        .iter()
335        .filter(|g| !matches!(g, GenericParam::Lifetime(_)))
336        .collect();
337
338    let shadowed_lifetimes: Vec<_> = generics.lifetimes().map(|_| quote!('_)).collect();
339
340    let mut punctuated_generics = Punctuated::<_, Comma>::new();
341    punctuated_generics.extend(lifetimeless_generics.iter().map(|g| match g {
342        GenericParam::Type(g) => GenericParam::Type(TypeParam {
343            default: None,
344            ..g.clone()
345        }),
346        GenericParam::Const(g) => GenericParam::Const(ConstParam {
347            default: None,
348            ..g.clone()
349        }),
350        _ => unreachable!(),
351    }));
352
353    let mut punctuated_generic_idents = Punctuated::<_, Comma>::new();
354    punctuated_generic_idents.extend(lifetimeless_generics.iter().map(|g| match g {
355        GenericParam::Type(g) => &g.ident,
356        GenericParam::Const(g) => &g.ident,
357        _ => unreachable!(),
358    }));
359
360    let punctuated_generics_no_bounds: Punctuated<_, Comma> = lifetimeless_generics
361        .iter()
362        .map(|&g| match g.clone() {
363            GenericParam::Type(mut g) => {
364                g.bounds.clear();
365                GenericParam::Type(g)
366            }
367            g => g,
368        })
369        .collect();
370
371    let mut tuple_types: Vec<_> = field_types.iter().map(|x| quote! { #x }).collect();
372    let mut tuple_patterns: Vec<_> = field_locals.iter().map(|x| quote! { #x }).collect();
373
374    // If the number of fields exceeds the 16-parameter limit,
375    // fold the fields into tuples of tuples until we are below the limit.
376    const LIMIT: usize = 16;
377    while tuple_types.len() > LIMIT {
378        let end = Vec::from_iter(tuple_types.drain(..LIMIT));
379        tuple_types.push(parse_quote!( (#(#end,)*) ));
380
381        let end = Vec::from_iter(tuple_patterns.drain(..LIMIT));
382        tuple_patterns.push(parse_quote!( (#(#end,)*) ));
383    }
384
385    // Create a where clause for the `ReadOnlySystemParam` impl.
386    // Ensure that each field implements `ReadOnlySystemParam`.
387    let mut read_only_generics = generics.clone();
388    let read_only_where_clause = read_only_generics.make_where_clause();
389    for field_type in &field_types {
390        read_only_where_clause
391            .predicates
392            .push(syn::parse_quote!(#field_type: #path::system::ReadOnlySystemParam));
393    }
394
395    let fields_alias =
396        ensure_no_collision(format_ident!("__StructFieldsAlias"), token_stream.clone());
397
398    let struct_name = &ast.ident;
399    let state_struct_visibility = &ast.vis;
400    let state_struct_name = ensure_no_collision(format_ident!("FetchState"), token_stream);
401
402    let mut builder_name = None;
403    for meta in ast
404        .attrs
405        .iter()
406        .filter(|a| a.path().is_ident("system_param"))
407    {
408        if let Err(e) = meta.parse_nested_meta(|nested| {
409            if nested.path.is_ident("builder") {
410                builder_name = Some(format_ident!("{struct_name}Builder"));
411                Ok(())
412            } else {
413                Err(nested.error("Unsupported attribute"))
414            }
415        }) {
416            return e.into_compile_error().into();
417        }
418    }
419
420    let builder = builder_name.map(|builder_name| {
421        let builder_type_parameters: Vec<_> = (0..fields.len()).map(|i| format_ident!("B{i}")).collect();
422        let builder_doc_comment = format!("A [`SystemParamBuilder`] for a [`{struct_name}`].");
423        let builder_struct = quote! {
424            #[doc = #builder_doc_comment]
425            struct #builder_name<#(#builder_type_parameters,)*> {
426                #(#fields: #builder_type_parameters,)*
427            }
428        };
429        let lifetimes: Vec<_> = generics.lifetimes().collect();
430        let generic_struct = quote!{ #struct_name <#(#lifetimes,)* #punctuated_generic_idents> };
431        let builder_impl = quote!{
432            // SAFETY: This delegates to the `SystemParamBuilder` for tuples.
433            unsafe impl<
434                #(#lifetimes,)*
435                #(#builder_type_parameters: #path::system::SystemParamBuilder<#field_types>,)*
436                #punctuated_generics
437            > #path::system::SystemParamBuilder<#generic_struct> for #builder_name<#(#builder_type_parameters,)*>
438                #where_clause
439            {
440                fn build(self, world: &mut #path::world::World) -> <#generic_struct as #path::system::SystemParam>::State {
441                    let #builder_name { #(#fields: #field_locals,)* } = self;
442                    #state_struct_name {
443                        state: #path::system::SystemParamBuilder::build((#(#tuple_patterns,)*), world)
444                    }
445                }
446            }
447        };
448        (builder_struct, builder_impl)
449    });
450    let (builder_struct, builder_impl) = builder.unzip();
451
452    TokenStream::from(quote! {
453        // We define the FetchState struct in an anonymous scope to avoid polluting the user namespace.
454        // The struct can still be accessed via SystemParam::State, e.g. MessageReaderState can be accessed via
455        // <MessageReader<'static, 'static, T> as SystemParam>::State
456        const _: () = {
457            // Allows rebinding the lifetimes of each field type.
458            type #fields_alias <'w, 's, #punctuated_generics_no_bounds> = (#(#tuple_types,)*);
459
460            #[doc(hidden)]
461            #state_struct_visibility struct #state_struct_name <#(#lifetimeless_generics,)*>
462            #where_clause {
463                state: <#fields_alias::<'static, 'static, #punctuated_generic_idents> as #path::system::SystemParam>::State,
464            }
465
466            unsafe impl<#punctuated_generics> #path::system::SystemParam for
467                #struct_name <#(#shadowed_lifetimes,)* #punctuated_generic_idents> #where_clause
468            {
469                type State = #state_struct_name<#punctuated_generic_idents>;
470                type Item<'w, 's> = #struct_name #ty_generics;
471
472                fn init_state(world: &mut #path::world::World) -> Self::State {
473                    #state_struct_name {
474                        state: <#fields_alias::<'_, '_, #punctuated_generic_idents> as #path::system::SystemParam>::init_state(world),
475                    }
476                }
477
478                fn init_access(state: &Self::State, system_meta: &mut #path::system::SystemMeta, component_access_set: &mut #path::query::FilteredAccessSet, world: &mut #path::world::World) {
479                    <#fields_alias::<'_, '_, #punctuated_generic_idents> as #path::system::SystemParam>::init_access(&state.state, system_meta, component_access_set, world);
480                }
481
482                fn apply(state: &mut Self::State, system_meta: &#path::system::SystemMeta, world: &mut #path::world::World) {
483                    <#fields_alias::<'_, '_, #punctuated_generic_idents> as #path::system::SystemParam>::apply(&mut state.state, system_meta, world);
484                }
485
486                fn queue(state: &mut Self::State, system_meta: &#path::system::SystemMeta, world: #path::world::DeferredWorld) {
487                    <#fields_alias::<'_, '_, #punctuated_generic_idents> as #path::system::SystemParam>::queue(&mut state.state, system_meta, world);
488                }
489
490                #[inline]
491                unsafe fn validate_param<'w, 's>(
492                    state: &'s mut Self::State,
493                    _system_meta: &#path::system::SystemMeta,
494                    _world: #path::world::unsafe_world_cell::UnsafeWorldCell<'w>,
495                ) -> Result<(), #path::system::SystemParamValidationError> {
496                    let #state_struct_name { state: (#(#tuple_patterns,)*) } = state;
497                    #(
498                        <#field_types as #path::system::SystemParam>::validate_param(#field_locals, _system_meta, _world)
499                            .map_err(|err| #path::system::SystemParamValidationError::new::<Self>(err.skipped, #field_messages, #field_names))?;
500                    )*
501                    Result::Ok(())
502                }
503
504                #[inline]
505                unsafe fn get_param<'w, 's>(
506                    state: &'s mut Self::State,
507                    system_meta: &#path::system::SystemMeta,
508                    world: #path::world::unsafe_world_cell::UnsafeWorldCell<'w>,
509                    change_tick: #path::component::Tick,
510                ) -> Self::Item<'w, 's> {
511                    let (#(#tuple_patterns,)*) = <
512                        (#(#tuple_types,)*) as #path::system::SystemParam
513                    >::get_param(&mut state.state, system_meta, world, change_tick);
514                    #struct_name {
515                        #(#fields: #field_locals,)*
516                    }
517                }
518            }
519
520            // Safety: Each field is `ReadOnlySystemParam`, so this can only read from the `World`
521            unsafe impl<'w, 's, #punctuated_generics> #path::system::ReadOnlySystemParam for #struct_name #ty_generics #read_only_where_clause {}
522
523            #builder_impl
524        };
525
526        #builder_struct
527    })
528}
529
530/// Implement `QueryData` to use a struct as a data parameter in a query
531#[proc_macro_derive(QueryData, attributes(query_data))]
532pub fn derive_query_data(input: TokenStream) -> TokenStream {
533    derive_query_data_impl(input)
534}
535
536/// Implement `QueryFilter` to use a struct as a filter parameter in a query
537#[proc_macro_derive(QueryFilter, attributes(query_filter))]
538pub fn derive_query_filter(input: TokenStream) -> TokenStream {
539    derive_query_filter_impl(input)
540}
541
542/// Derive macro generating an impl of the trait `ScheduleLabel`.
543///
544/// This does not work for unions.
545#[proc_macro_derive(ScheduleLabel)]
546pub fn derive_schedule_label(input: TokenStream) -> TokenStream {
547    let input = parse_macro_input!(input as DeriveInput);
548    let mut trait_path = bevy_ecs_path();
549    trait_path.segments.push(format_ident!("schedule").into());
550    trait_path
551        .segments
552        .push(format_ident!("ScheduleLabel").into());
553    derive_label(input, "ScheduleLabel", &trait_path)
554}
555
556/// Derive macro generating an impl of the trait `SystemSet`.
557///
558/// This does not work for unions.
559#[proc_macro_derive(SystemSet)]
560pub fn derive_system_set(input: TokenStream) -> TokenStream {
561    let input = parse_macro_input!(input as DeriveInput);
562    let mut trait_path = bevy_ecs_path();
563    trait_path.segments.push(format_ident!("schedule").into());
564    trait_path.segments.push(format_ident!("SystemSet").into());
565    derive_label(input, "SystemSet", &trait_path)
566}
567
568pub(crate) fn bevy_ecs_path() -> syn::Path {
569    BevyManifest::shared().get_path("bevy_ecs")
570}
571
572/// Implement the `Event` trait.
573#[proc_macro_derive(Event, attributes(event))]
574pub fn derive_event(input: TokenStream) -> TokenStream {
575    event::derive_event(input)
576}
577
578/// Cheat sheet for derive syntax,
579/// see full explanation on `EntityEvent` trait docs.
580///
581/// ```ignore
582/// #[derive(EntityEvent)]
583/// /// Enable propagation, which defaults to using the ChildOf component
584/// #[entity_event(propagate)]
585/// /// Enable propagation using the given Traversal implementation
586/// #[entity_event(propagate = &'static ChildOf)]
587/// /// Always propagate
588/// #[entity_event(auto_propagate)]
589/// struct MyEvent;
590/// ```
591#[proc_macro_derive(EntityEvent, attributes(entity_event, event_target))]
592pub fn derive_entity_event(input: TokenStream) -> TokenStream {
593    event::derive_entity_event(input)
594}
595
596/// Implement the `Message` trait.
597#[proc_macro_derive(Message)]
598pub fn derive_message(input: TokenStream) -> TokenStream {
599    message::derive_message(input)
600}
601
602/// Implement the `Resource` trait.
603#[proc_macro_derive(Resource)]
604pub fn derive_resource(input: TokenStream) -> TokenStream {
605    component::derive_resource(input)
606}
607
608/// Cheat sheet for derive syntax,
609/// see full explanation and examples on the `Component` trait doc.
610///
611/// ## Immutability
612/// ```ignore
613/// #[derive(Component)]
614/// #[component(immutable)]
615/// struct MyComponent;
616/// ```
617///
618/// ## Sparse instead of table-based storage
619/// ```ignore
620/// #[derive(Component)]
621/// #[component(storage = "SparseSet")]
622/// struct MyComponent;
623/// ```
624///
625/// ## Required Components
626///
627/// ```ignore
628/// #[derive(Component)]
629/// #[require(
630///     // `Default::default()`
631///     A,
632///     // tuple structs
633///     B(1),
634///     // named-field structs
635///     C {
636///         x: 1,
637///         ..default()
638///     },
639///     // unit structs/variants
640///     D::One,
641///     // associated consts
642///     E::ONE,
643///     // constructors
644///     F::new(1),
645///     // arbitrary expressions
646///     G = make(1, 2, 3)
647/// )]
648/// struct MyComponent;
649/// ```
650///
651/// ## Relationships
652/// ```ignore
653/// #[derive(Component)]
654/// #[relationship(relationship_target = Children)]
655/// pub struct ChildOf {
656///     // Marking the field is not necessary if there is only one.
657///     #[relationship]
658///     pub parent: Entity,
659///     internal: u8,
660/// };
661///
662/// #[derive(Component)]
663/// #[relationship_target(relationship = ChildOf)]
664/// pub struct Children(Vec<Entity>);
665/// ```
666///
667/// On despawn, also despawn all related entities:
668/// ```ignore
669/// #[derive(Component)]
670/// #[relationship_target(relationship_target = Children, linked_spawn)]
671/// pub struct Children(Vec<Entity>);
672/// ```
673///
674/// ## Hooks
675/// ```ignore
676/// #[derive(Component)]
677/// #[component(hook_name = function)]
678/// struct MyComponent;
679/// ```
680/// where `hook_name` is `on_add`, `on_insert`, `on_replace` or `on_remove`;  
681/// `function` can be either a path, e.g. `some_function::<Self>`,
682/// or a function call that returns a function that can be turned into
683/// a `ComponentHook`, e.g. `get_closure("Hi!")`.
684///
685/// ## Ignore this component when cloning an entity
686/// ```ignore
687/// #[derive(Component)]
688/// #[component(clone_behavior = Ignore)]
689/// struct MyComponent;
690/// ```
691#[proc_macro_derive(
692    Component,
693    attributes(component, require, relationship, relationship_target, entities)
694)]
695pub fn derive_component(input: TokenStream) -> TokenStream {
696    component::derive_component(input)
697}
698
699/// Implement the `FromWorld` trait.
700#[proc_macro_derive(FromWorld, attributes(from_world))]
701pub fn derive_from_world(input: TokenStream) -> TokenStream {
702    let bevy_ecs_path = bevy_ecs_path();
703    let ast = parse_macro_input!(input as DeriveInput);
704    let name = ast.ident;
705    let (impl_generics, ty_generics, where_clauses) = ast.generics.split_for_impl();
706
707    let (fields, variant_ident) = match &ast.data {
708        Data::Struct(data) => (&data.fields, None),
709        Data::Enum(data) => {
710            match data.variants.iter().find(|variant| {
711                variant
712                    .attrs
713                    .iter()
714                    .any(|attr| attr.path().is_ident("from_world"))
715            }) {
716                Some(variant) => (&variant.fields, Some(&variant.ident)),
717                None => {
718                    return syn::Error::new(
719                        Span::call_site(),
720                        "No variant found with the `#[from_world]` attribute",
721                    )
722                    .into_compile_error()
723                    .into();
724                }
725            }
726        }
727        Data::Union(_) => {
728            return syn::Error::new(
729                Span::call_site(),
730                "#[derive(FromWorld)]` does not support unions",
731            )
732            .into_compile_error()
733            .into();
734        }
735    };
736
737    let field_init_expr = quote!(#bevy_ecs_path::world::FromWorld::from_world(world));
738    let members = fields.members();
739
740    let field_initializers = match variant_ident {
741        Some(variant_ident) => quote!( Self::#variant_ident {
742            #(#members: #field_init_expr),*
743        }),
744        None => quote!( Self {
745            #(#members: #field_init_expr),*
746        }),
747    };
748
749    TokenStream::from(quote! {
750            impl #impl_generics #bevy_ecs_path::world::FromWorld for #name #ty_generics #where_clauses {
751                fn from_world(world: &mut #bevy_ecs_path::world::World) -> Self {
752                    #field_initializers
753                }
754            }
755    })
756}