Allow a closure to be used as a required component default (#15269)
# Objective Allow required component default values to be provided in-line. ```rust #[derive(Component)] #[require( FocusPolicy(block_focus_policy) )] struct SomeComponent; fn block_focus_policy() -> FocusPolicy { FocusPolicy::Block } ``` May now be expressed as: ```rust #[derive(Component)] #[require( FocusPolicy(|| FocusPolicy::Block) )] struct SomeComponent; ``` ## Solution Modified the #[require] proc macro to accept a closure. ## Testing Tested using my branch as a dependency, and switching between the inline closure syntax and function syntax for a bunch of different components.
This commit is contained in:
parent
20dbf790a6
commit
f0704cffa4
@ -9,7 +9,7 @@ use syn::{
|
|||||||
punctuated::Punctuated,
|
punctuated::Punctuated,
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
token::{Comma, Paren},
|
token::{Comma, Paren},
|
||||||
DeriveInput, ExprPath, Ident, LitStr, Path, Result,
|
DeriveInput, ExprClosure, ExprPath, Ident, LitStr, Path, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn derive_event(input: TokenStream) -> TokenStream {
|
pub fn derive_event(input: TokenStream) -> TokenStream {
|
||||||
@ -90,24 +90,37 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
|
|||||||
inheritance_depth + 1
|
inheritance_depth + 1
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
if let Some(func) = &require.func {
|
match &require.func {
|
||||||
register_required.push(quote! {
|
Some(RequireFunc::Path(func)) => {
|
||||||
components.register_required_components_manual::<Self, #ident>(
|
register_required.push(quote! {
|
||||||
storages,
|
components.register_required_components_manual::<Self, #ident>(
|
||||||
required_components,
|
storages,
|
||||||
|| { let x: #ident = #func().into(); x },
|
required_components,
|
||||||
inheritance_depth
|
|| { let x: #ident = #func().into(); x },
|
||||||
);
|
inheritance_depth
|
||||||
});
|
);
|
||||||
} else {
|
});
|
||||||
register_required.push(quote! {
|
}
|
||||||
components.register_required_components_manual::<Self, #ident>(
|
Some(RequireFunc::Closure(func)) => {
|
||||||
storages,
|
register_required.push(quote! {
|
||||||
required_components,
|
components.register_required_components_manual::<Self, #ident>(
|
||||||
<#ident as Default>::default,
|
storages,
|
||||||
inheritance_depth
|
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
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,7 +193,12 @@ enum StorageTy {
|
|||||||
|
|
||||||
struct Require {
|
struct Require {
|
||||||
path: Path,
|
path: Path,
|
||||||
func: Option<Path>,
|
func: Option<RequireFunc>,
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RequireFunc {
|
||||||
|
Path(Path),
|
||||||
|
Closure(ExprClosure),
|
||||||
}
|
}
|
||||||
|
|
||||||
// values for `storage` attribute
|
// values for `storage` attribute
|
||||||
@ -256,8 +274,12 @@ impl Parse for Require {
|
|||||||
let func = if input.peek(Paren) {
|
let func = if input.peek(Paren) {
|
||||||
let content;
|
let content;
|
||||||
parenthesized!(content in input);
|
parenthesized!(content in input);
|
||||||
let func = content.parse::<Path>()?;
|
if let Ok(func) = content.parse::<ExprClosure>() {
|
||||||
Some(func)
|
Some(RequireFunc::Closure(func))
|
||||||
|
} else {
|
||||||
|
let func = content.parse::<Path>()?;
|
||||||
|
Some(RequireFunc::Path(func))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -146,25 +146,33 @@ use thiserror::Error;
|
|||||||
/// assert_eq!(&C(0), world.entity(id).get::<C>().unwrap());
|
/// 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::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
/// #[derive(Component)]
|
/// #[derive(Component)]
|
||||||
/// #[require(B(init_b))]
|
/// #[require(C(init_c))]
|
||||||
/// struct A;
|
/// struct A;
|
||||||
///
|
///
|
||||||
/// #[derive(Component, PartialEq, Eq, Debug)]
|
/// #[derive(Component, PartialEq, Eq, Debug)]
|
||||||
/// struct B(usize);
|
/// #[require(C(|| C(20)))]
|
||||||
|
/// struct B;
|
||||||
///
|
///
|
||||||
/// fn init_b() -> B {
|
/// #[derive(Component, PartialEq, Eq, Debug)]
|
||||||
/// B(10)
|
/// struct C(usize);
|
||||||
|
///
|
||||||
|
/// fn init_c() -> C {
|
||||||
|
/// C(10)
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// # let mut world = World::default();
|
/// # 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();
|
/// 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,
|
/// Required components are _recursive_. This means, if a Required Component has required components,
|
||||||
@ -202,24 +210,16 @@ use thiserror::Error;
|
|||||||
/// struct X(usize);
|
/// struct X(usize);
|
||||||
///
|
///
|
||||||
/// #[derive(Component, Default)]
|
/// #[derive(Component, Default)]
|
||||||
/// #[require(X(x1))]
|
/// #[require(X(|| X(1)))]
|
||||||
/// struct Y;
|
/// struct Y;
|
||||||
///
|
///
|
||||||
/// fn x1() -> X {
|
|
||||||
/// X(1)
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// #[derive(Component)]
|
/// #[derive(Component)]
|
||||||
/// #[require(
|
/// #[require(
|
||||||
/// Y,
|
/// Y,
|
||||||
/// X(x2),
|
/// X(|| X(2)),
|
||||||
/// )]
|
/// )]
|
||||||
/// struct Z;
|
/// struct Z;
|
||||||
///
|
///
|
||||||
/// fn x2() -> X {
|
|
||||||
/// X(2)
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// # let mut world = World::default();
|
/// # let mut world = World::default();
|
||||||
/// // In this case, the x2 constructor is used for X
|
/// // In this case, the x2 constructor is used for X
|
||||||
/// let id = world.spawn(Z).id();
|
/// let id = world.spawn(Z).id();
|
||||||
|
Loading…
Reference in New Issue
Block a user