Derive clone_behavior
for Components
(#18811)
Allow Derive(Component) to specify a clone_behavior ```rust #[derive(Component)] #[component(clone_behavior = Ignore)] MyComponent; ```
This commit is contained in:
parent
b19f644c2f
commit
60cdefd128
@ -251,6 +251,8 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
|
|||||||
|
|
||||||
let clone_behavior = if relationship_target.is_some() {
|
let clone_behavior = if relationship_target.is_some() {
|
||||||
quote!(#bevy_ecs_path::component::ComponentCloneBehavior::Custom(#bevy_ecs_path::relationship::clone_relationship_target::<Self>))
|
quote!(#bevy_ecs_path::component::ComponentCloneBehavior::Custom(#bevy_ecs_path::relationship::clone_relationship_target::<Self>))
|
||||||
|
} else if let Some(behavior) = attrs.clone_behavior {
|
||||||
|
quote!(#bevy_ecs_path::component::ComponentCloneBehavior::#behavior)
|
||||||
} else {
|
} else {
|
||||||
quote!(
|
quote!(
|
||||||
use #bevy_ecs_path::component::{DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone};
|
use #bevy_ecs_path::component::{DefaultCloneBehaviorBase, DefaultCloneBehaviorViaClone};
|
||||||
@ -396,6 +398,7 @@ pub const ON_REMOVE: &str = "on_remove";
|
|||||||
pub const ON_DESPAWN: &str = "on_despawn";
|
pub const ON_DESPAWN: &str = "on_despawn";
|
||||||
|
|
||||||
pub const IMMUTABLE: &str = "immutable";
|
pub const IMMUTABLE: &str = "immutable";
|
||||||
|
pub const CLONE_BEHAVIOR: &str = "clone_behavior";
|
||||||
|
|
||||||
/// All allowed attribute value expression kinds for component hooks
|
/// All allowed attribute value expression kinds for component hooks
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -458,6 +461,7 @@ struct Attrs {
|
|||||||
relationship: Option<Relationship>,
|
relationship: Option<Relationship>,
|
||||||
relationship_target: Option<RelationshipTarget>,
|
relationship_target: Option<RelationshipTarget>,
|
||||||
immutable: bool,
|
immutable: bool,
|
||||||
|
clone_behavior: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
@ -496,6 +500,7 @@ fn parse_component_attr(ast: &DeriveInput) -> Result<Attrs> {
|
|||||||
relationship: None,
|
relationship: None,
|
||||||
relationship_target: None,
|
relationship_target: None,
|
||||||
immutable: false,
|
immutable: false,
|
||||||
|
clone_behavior: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut require_paths = HashSet::new();
|
let mut require_paths = HashSet::new();
|
||||||
@ -531,6 +536,9 @@ fn parse_component_attr(ast: &DeriveInput) -> Result<Attrs> {
|
|||||||
} else if nested.path.is_ident(IMMUTABLE) {
|
} else if nested.path.is_ident(IMMUTABLE) {
|
||||||
attrs.immutable = true;
|
attrs.immutable = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
} else if nested.path.is_ident(CLONE_BEHAVIOR) {
|
||||||
|
attrs.clone_behavior = Some(nested.value()?.parse()?);
|
||||||
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(nested.error("Unsupported attribute"))
|
Err(nested.error("Unsupported attribute"))
|
||||||
}
|
}
|
||||||
@ -560,6 +568,13 @@ fn parse_component_attr(ast: &DeriveInput) -> Result<Attrs> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if attrs.relationship_target.is_some() && attrs.clone_behavior.is_some() {
|
||||||
|
return Err(syn::Error::new(
|
||||||
|
attrs.clone_behavior.span(),
|
||||||
|
"A Relationship Target already has its own clone behavior, please remove `clone_behavior = ...`",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Ok(attrs)
|
Ok(attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,6 +418,21 @@ use thiserror::Error;
|
|||||||
/// println!("{message}");
|
/// println!("{message}");
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # Setting the clone behavior
|
||||||
|
///
|
||||||
|
/// You can specify how the [`Component`] is cloned when deriving it.
|
||||||
|
///
|
||||||
|
/// Your options are the functions and variants of [`ComponentCloneBehavior`]
|
||||||
|
/// See [Handlers section of `EntityClonerBuilder`](crate::entity::EntityClonerBuilder#handlers) to understand how this affects handler priority.
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_ecs::prelude::*;
|
||||||
|
///
|
||||||
|
/// #[derive(Component)]
|
||||||
|
/// #[component(clone_behavior = Ignore)]
|
||||||
|
/// struct MyComponent;
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Implementing the trait for foreign types
|
/// # Implementing the trait for foreign types
|
||||||
|
@ -324,16 +324,10 @@ impl<'a, 'b> ComponentCloneCtx<'a, 'b> {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use bevy_ecs::prelude::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
/// # use bevy_ecs::component::{StorageType, ComponentCloneBehavior, Mutable};
|
/// # use bevy_ecs::component::{StorageType, ComponentCloneBehavior, Mutable};
|
||||||
/// #[derive(Clone)]
|
/// #[derive(Clone, Component)]
|
||||||
|
/// #[component(clone_behavior = clone::<Self>())]
|
||||||
/// struct SomeComponent;
|
/// struct SomeComponent;
|
||||||
///
|
///
|
||||||
/// impl Component for SomeComponent {
|
|
||||||
/// const STORAGE_TYPE: StorageType = StorageType::Table;
|
|
||||||
/// type Mutability = Mutable;
|
|
||||||
/// fn clone_behavior() -> ComponentCloneBehavior {
|
|
||||||
/// ComponentCloneBehavior::clone::<Self>()
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Clone Behaviors
|
/// # Clone Behaviors
|
||||||
|
@ -2751,4 +2751,27 @@ mod tests {
|
|||||||
)]
|
)]
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct MyEntitiesTuple(#[entities] Vec<Entity>, #[entities] Entity, usize);
|
struct MyEntitiesTuple(#[entities] Vec<Entity>, #[entities] Entity, usize);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn clone_entities() {
|
||||||
|
use crate::entity::{ComponentCloneCtx, SourceComponent};
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
#[component(clone_behavior = Ignore)]
|
||||||
|
struct IgnoreClone;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
#[component(clone_behavior = Default)]
|
||||||
|
struct DefaultClone;
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
#[component(clone_behavior = Custom(custom_clone))]
|
||||||
|
struct CustomClone;
|
||||||
|
|
||||||
|
#[derive(Component, Clone)]
|
||||||
|
#[component(clone_behavior = clone::<Self>())]
|
||||||
|
struct CloneFunction;
|
||||||
|
|
||||||
|
fn custom_clone(_source: &SourceComponent, _ctx: &mut ComponentCloneCtx) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use bevy_app::Plugin;
|
use bevy_app::Plugin;
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::component::{ComponentCloneBehavior, Mutable, StorageType};
|
|
||||||
use bevy_ecs::entity::EntityHash;
|
use bevy_ecs::entity::EntityHash;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Component,
|
component::Component,
|
||||||
@ -127,7 +126,8 @@ pub struct SyncToRenderWorld;
|
|||||||
/// Component added on the main world entities that are synced to the Render World in order to keep track of the corresponding render world entity.
|
/// Component added on the main world entities that are synced to the Render World in order to keep track of the corresponding render world entity.
|
||||||
///
|
///
|
||||||
/// Can also be used as a newtype wrapper for render world entities.
|
/// Can also be used as a newtype wrapper for render world entities.
|
||||||
#[derive(Deref, Copy, Clone, Debug, Eq, Hash, PartialEq)]
|
#[derive(Deref, Copy, Clone, Debug, Eq, Hash, PartialEq, Component)]
|
||||||
|
#[component(clone_behavior = Ignore)]
|
||||||
pub struct RenderEntity(Entity);
|
pub struct RenderEntity(Entity);
|
||||||
impl RenderEntity {
|
impl RenderEntity {
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -136,16 +136,6 @@ impl RenderEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for RenderEntity {
|
|
||||||
const STORAGE_TYPE: StorageType = StorageType::Table;
|
|
||||||
|
|
||||||
type Mutability = Mutable;
|
|
||||||
|
|
||||||
fn clone_behavior() -> ComponentCloneBehavior {
|
|
||||||
ComponentCloneBehavior::Ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Entity> for RenderEntity {
|
impl From<Entity> for RenderEntity {
|
||||||
fn from(entity: Entity) -> Self {
|
fn from(entity: Entity) -> Self {
|
||||||
RenderEntity(entity)
|
RenderEntity(entity)
|
||||||
|
Loading…
Reference in New Issue
Block a user