Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 44 additions & 22 deletions crates/bevy_ecs/macros/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use syn::{
punctuated::Punctuated,
spanned::Spanned,
token::{Comma, Paren},
DeriveInput, ExprPath, Ident, LitStr, Path, Result,
DeriveInput, ExprClosure, ExprPath, Ident, LitStr, Path, Result,
};

pub fn derive_event(input: TokenStream) -> TokenStream {
Expand Down Expand Up @@ -90,24 +90,37 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
inheritance_depth + 1
);
});
if let Some(func) = &require.func {
register_required.push(quote! {
components.register_required_components_manual::<Self, #ident>(
storages,
required_components,
|| { let x: #ident = #func().into(); x },
inheritance_depth
);
});
} else {
register_required.push(quote! {
components.register_required_components_manual::<Self, #ident>(
storages,
required_components,
<#ident as Default>::default,
inheritance_depth
);
});
match &require.func {
Some(RequireFunc::Path(func)) => {
register_required.push(quote! {
components.register_required_components_manual::<Self, #ident>(
storages,
required_components,
|| { let x: #ident = #func().into(); x },
inheritance_depth
);
});
}
Some(RequireFunc::Closure(func)) => {
register_required.push(quote! {
components.register_required_components_manual::<Self, #ident>(
storages,
required_components,
|| { let x: #ident = (#func)().into(); x },
inheritance_depth
);
});
}
None => {
register_required.push(quote! {
components.register_required_components_manual::<Self, #ident>(
storages,
required_components,
<#ident as Default>::default,
inheritance_depth
);
});
}
}
}
}
Expand Down Expand Up @@ -180,7 +193,12 @@ enum StorageTy {

struct Require {
path: Path,
func: Option<Path>,
func: Option<RequireFunc>,
}

enum RequireFunc {
Path(Path),
Closure(ExprClosure),
}

// values for `storage` attribute
Expand Down Expand Up @@ -256,8 +274,12 @@ impl Parse for Require {
let func = if input.peek(Paren) {
let content;
parenthesized!(content in input);
let func = content.parse::<Path>()?;
Some(func)
if let Ok(func) = content.parse::<ExprClosure>() {
Some(RequireFunc::Closure(func))
} else {
let func = content.parse::<Path>()?;
Some(RequireFunc::Path(func))
}
} else {
None
};
Expand Down
34 changes: 17 additions & 17 deletions crates/bevy_ecs/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,25 +146,33 @@ use thiserror::Error;
/// assert_eq!(&C(0), world.entity(id).get::<C>().unwrap());
/// ```
///
/// You can also define a custom constructor:
/// You can also define a custom constructor function or closure:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #[derive(Component)]
/// #[require(B(init_b))]
/// #[require(C(init_c))]
/// struct A;
///
/// #[derive(Component, PartialEq, Eq, Debug)]
/// struct B(usize);
/// #[require(C(|| C(20)))]
/// struct B;
///
/// #[derive(Component, PartialEq, Eq, Debug)]
/// struct C(usize);
///
/// fn init_b() -> B {
/// B(10)
/// fn init_c() -> C {
/// C(10)
/// }
///
/// # let mut world = World::default();
/// // This will implicitly also insert B with the init_b() constructor
/// // This will implicitly also insert C with the init_c() constructor
/// let id = world.spawn(A).id();
/// assert_eq!(&B(10), world.entity(id).get::<B>().unwrap());
/// assert_eq!(&C(10), world.entity(id).get::<C>().unwrap());
///
/// // This will implicitly also insert C with the `|| C(20)` constructor closure
/// let id = world.spawn(B).id();
/// assert_eq!(&C(20), world.entity(id).get::<C>().unwrap());
/// ```
///
/// Required components are _recursive_. This means, if a Required Component has required components,
Expand Down Expand Up @@ -202,24 +210,16 @@ use thiserror::Error;
/// struct X(usize);
///
/// #[derive(Component, Default)]
/// #[require(X(x1))]
/// #[require(X(|| X(1)))]
/// struct Y;
///
/// fn x1() -> X {
/// X(1)
/// }
///
/// #[derive(Component)]
/// #[require(
/// Y,
/// X(x2),
/// X(|| X(2)),
/// )]
/// struct Z;
///
/// fn x2() -> X {
/// X(2)
/// }
///
/// # let mut world = World::default();
/// // In this case, the x2 constructor is used for X
/// let id = world.spawn(Z).id();
Expand Down
Loading