Skip to content

Commit

Permalink
document component clone handler priority and default cloning strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
eugineerd committed Nov 2, 2024
1 parent b4a69e1 commit b5034da
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 9 deletions.
20 changes: 13 additions & 7 deletions crates/bevy_ecs/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ pub trait Component: Send + Sync + 'static {
}

/// Called when registering this component, allowing to override clone function (or disable cloning altogether) for this component.
///
/// See [Handlers section of `EntityCloneBuilder`](crate::entity::EntityCloneBuilder#handlers) to understand how this affects handler priority.
fn get_component_clone_handler() -> ComponentCloneHandler {
ComponentCloneHandler::default()
}
Expand Down Expand Up @@ -905,6 +907,8 @@ pub struct ComponentCloneHandlers {
impl ComponentCloneHandlers {
/// Sets the default handler for this registry. All components with [`Default`](ComponentCloneHandler::Default) handler, as well as any component that does not have an
/// explicitly registered clone function will use this handler.
///
/// See [Handlers section of `EntityCloneBuilder`](crate::entity::EntityCloneBuilder#handlers) to understand how this affects handler priority.
pub fn set_default_handler(&mut self, handler: ComponentCloneFn) {
self.default_handler = handler;
}
Expand All @@ -915,6 +919,8 @@ impl ComponentCloneHandlers {
}

/// Sets a handler for a specific component.
///
/// See [Handlers section of `EntityCloneBuilder`](crate::entity::EntityCloneBuilder#handlers) to understand how this affects handler priority.
pub fn set_component_handler(
&mut self,
component_id: ComponentId,
Expand Down Expand Up @@ -1936,7 +1942,7 @@ impl RequiredComponents {
/// Can be [set](ComponentCloneHandlers::set_component_handler) as clone handler for the specific component it is implemented for.
/// It will panic if set as handler for any other component.
///
/// See [`ComponentCloneHandlers`] for more details
/// See [`ComponentCloneHandlers`] for more details.
pub fn component_clone_via_clone<C: Clone + Component>(
world: &mut World,
_component_id: ComponentId,
Expand All @@ -1954,7 +1960,7 @@ pub fn component_clone_via_clone<C: Clone + Component>(
/// Can be [set](ComponentCloneHandlers::set_component_handler) as clone handler for any registered component,
/// but only reflected components will be cloned.
///
/// See [`ComponentCloneHandlers`] for more details
/// See [`ComponentCloneHandlers`] for more details.
#[cfg(feature = "bevy_reflect")]
pub fn component_clone_via_reflect(
world: &mut World,
Expand Down Expand Up @@ -1991,17 +1997,17 @@ pub fn component_clone_via_reflect(
});
}

/// Noop implementation of component clone handler function
/// Noop implementation of component clone handler function.
///
/// See [`ComponentCloneHandlers`] for more details
/// See [`ComponentCloneHandlers`] for more details.
pub fn component_clone_ignore(
_world: &mut World,
_component_id: ComponentId,
_entity_cloner: &EntityCloner,
) {
}

/// Wrapper for components clone specialization using autoderef
/// Wrapper for components clone specialization using autoderef.
#[doc(hidden)]
pub struct ComponentCloneSpecializationWrapper<T>(PhantomData<T>);

Expand All @@ -2011,7 +2017,7 @@ impl<T> Default for ComponentCloneSpecializationWrapper<T> {
}
}

/// Base Trait for components clone specialization using autoderef
/// Base trait for components clone specialization using autoderef.
#[doc(hidden)]
pub trait ComponentCloneBase {
fn get_component_clone_handler(&self) -> ComponentCloneHandler;
Expand All @@ -2022,7 +2028,7 @@ impl<C: Component> ComponentCloneBase for ComponentCloneSpecializationWrapper<C>
}
}

/// Specialized trait for components clone specialization using autoderef
/// Specialized trait for components clone specialization using autoderef.
#[doc(hidden)]
pub trait ComponentCloneViaClone {
fn get_component_clone_handler(&self) -> ComponentCloneHandler;
Expand Down
40 changes: 38 additions & 2 deletions crates/bevy_ecs/src/entity/clone_entities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,44 @@ impl<'a> EntityCloner<'a> {
/// let entity = world.spawn(component.clone()).id();
/// let entity_clone = world.spawn_empty().id();
///
/// EntityCloneBuilder::default().clone_entity(&mut world, entity, entity_clone);
/// EntityCloneBuilder::new(&mut world).clone_entity(entity, entity_clone);
///
/// assert!(world.get::<A>(entity_clone).is_some_and(|c| *c == component));
///```
///
/// # Default cloning strategy
/// By default, all types that derive [`Component`] and implement either [`Clone`] or `Reflect` (with `ReflectComponent`) will be cloned
/// (with `Clone`-based implementation preferred in case component implements both).
///
/// It should be noted that if `Component` is implemented manually or if `Clone` implementation is conditional
/// (like when deriving `Clone` for a type with a generic parameter without `Clone` bound),
/// the component will be cloned using the [default cloning strategy](crate::component::ComponentCloneHandlers::get_default_handler).
/// To use `Clone`-based handler ([`component_clone_via_clone`](crate::component::component_clone_via_clone)) in this case it should be set manually using one
/// of the methods mentioned in the [Handlers](#handlers) section
///
/// Here's an example of how to do it using [`get_component_clone_handler`](Component::get_component_clone_handler):
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::component::{StorageType, component_clone_via_clone, ComponentCloneHandler};
/// #[derive(Clone)]
/// struct SomeComponent;
///
/// impl Component for SomeComponent {
/// const STORAGE_TYPE: StorageType = StorageType::Table;
/// fn get_component_clone_handler() -> ComponentCloneHandler {
/// ComponentCloneHandler::Custom(component_clone_via_clone::<Self>)
/// }
/// }
/// ```
///
/// # Handlers
/// `EntityCloneBuilder` clones entities by cloning components using [`handlers`](ComponentCloneHandler), and there are multiple layers
/// to decide which handler to use for which component. The overall hierarchy looks like this (priority from most to least):
/// 1. local overrides using [`override_component_clone_handler`](Self::override_component_clone_handler)
/// 2. global overrides using [`set_component_handler`](crate::component::ComponentCloneHandlers::set_component_handler)
/// 3. component-defined handler using [`get_component_clone_handler`](Component::get_component_clone_handler)
/// 4. default handler override using [`set_default_handler`](crate::component::ComponentCloneHandlers::set_default_handler)
/// 5. reflect-based or noop default clone handler depending on if `bevy_reflect` feature is enabled or not.
#[derive(Debug)]
pub struct EntityCloneBuilder<'w> {
world: &'w mut World,
Expand Down Expand Up @@ -242,7 +276,9 @@ impl<'w> EntityCloneBuilder<'w> {
}

/// Overrides the [`ComponentCloneHandler`] for a component in this builder.
/// This handler will be used to clone the component instead of the global one defined by [`ComponentCloneHandlers`]
/// This handler will be used to clone the component instead of the global one defined by [`ComponentCloneHandlers`](crate::component::ComponentCloneHandlers)
///
/// See [Handlers section of `EntityCloneBuilder`](EntityCloneBuilder#handlers) to understand how this affects handler priority.
pub fn override_component_clone_handler<T: Component>(
&mut self,
handler: ComponentCloneHandler,
Expand Down

0 comments on commit b5034da

Please sign in to comment.