Skip to main content

bevy_ecs/component/
clone.rs

1use core::marker::PhantomData;
2
3use crate::component::Component;
4use crate::entity::{ComponentCloneCtx, SourceComponent};
5
6/// Function type that can be used to clone a component of an entity.
7pub type ComponentCloneFn = fn(&SourceComponent, &mut ComponentCloneCtx);
8
9/// The clone behavior to use when cloning or moving a [`Component`].
10#[derive(Clone, Debug, Default)]
11pub enum ComponentCloneBehavior {
12    /// Uses the default behavior (which is passed to [`ComponentCloneBehavior::resolve`])
13    #[default]
14    Default,
15    /// Do not clone/move this component.
16    Ignore,
17    /// Uses a custom [`ComponentCloneFn`].
18    Custom(ComponentCloneFn),
19}
20
21impl ComponentCloneBehavior {
22    /// Set clone handler based on `Clone` trait.
23    ///
24    /// If set as a handler for a component that is not the same as the one used to create this handler, it will panic.
25    pub fn clone<C: Component + Clone>() -> Self {
26        Self::Custom(component_clone_via_clone::<C>)
27    }
28
29    /// Set clone handler based on `Reflect` trait.
30    #[cfg(feature = "bevy_reflect")]
31    pub fn reflect() -> Self {
32        Self::Custom(component_clone_via_reflect)
33    }
34
35    /// Returns the "global default"
36    pub fn global_default_fn() -> ComponentCloneFn {
37        #[cfg(feature = "bevy_reflect")]
38        return component_clone_via_reflect;
39        #[cfg(not(feature = "bevy_reflect"))]
40        return component_clone_ignore;
41    }
42
43    /// Resolves the [`ComponentCloneBehavior`] to a [`ComponentCloneFn`]. If [`ComponentCloneBehavior::Default`] is
44    /// specified, the given `default` function will be used.
45    pub fn resolve(&self, default: ComponentCloneFn) -> ComponentCloneFn {
46        match self {
47            ComponentCloneBehavior::Default => default,
48            ComponentCloneBehavior::Ignore => component_clone_ignore,
49            ComponentCloneBehavior::Custom(custom) => *custom,
50        }
51    }
52}
53
54/// Component [clone handler function](ComponentCloneFn) implemented using the [`Clone`] trait.
55/// Can be [set](Component::clone_behavior) as clone handler for the specific component it is implemented for.
56/// It will panic if set as handler for any other component.
57///
58pub fn component_clone_via_clone<C: Clone + Component>(
59    source: &SourceComponent,
60    ctx: &mut ComponentCloneCtx,
61) {
62    if let Some(component) = source.read::<C>() {
63        ctx.write_target_component(component.clone());
64    }
65}
66
67/// Component [clone handler function](ComponentCloneFn) implemented using reflect.
68/// Can be [set](Component::clone_behavior) as clone handler for any registered component,
69/// but only reflected components will be cloned.
70///
71/// To clone a component using this handler, the following must be true:
72/// - World has [`AppTypeRegistry`](crate::reflect::AppTypeRegistry)
73/// - Component has [`TypeId`](core::any::TypeId)
74/// - Component is registered
75/// - Component has [`ReflectFromPtr`](bevy_reflect::ReflectFromPtr) registered
76/// - Component can be cloned via [`PartialReflect::reflect_clone`] _or_ has one of the following registered: [`ReflectFromReflect`](bevy_reflect::ReflectFromReflect),
77///   [`ReflectDefault`](bevy_reflect::std_traits::ReflectDefault), [`ReflectFromWorld`](crate::reflect::ReflectFromWorld)
78///
79/// If any of the conditions is not satisfied, the component will be skipped.
80///
81/// See [`EntityClonerBuilder`](crate::entity::EntityClonerBuilder) for details.
82///
83/// [`PartialReflect::reflect_clone`]: bevy_reflect::PartialReflect::reflect_clone
84#[cfg(feature = "bevy_reflect")]
85pub fn component_clone_via_reflect(source: &SourceComponent, ctx: &mut ComponentCloneCtx) {
86    let Some(app_registry) = ctx.type_registry().cloned() else {
87        return;
88    };
89    let registry = app_registry.read();
90    let Some(source_component_reflect) = source.read_reflect(&registry) else {
91        return;
92    };
93    let component_info = ctx.component_info();
94    // checked in read_source_component_reflect
95    let type_id = component_info.type_id().unwrap();
96
97    // Try to clone using `reflect_clone`
98    if let Ok(mut component) = source_component_reflect.reflect_clone() {
99        if let Some(reflect_component) =
100            registry.get_type_data::<crate::reflect::ReflectComponent>(type_id)
101        {
102            reflect_component.map_entities(&mut *component, ctx.entity_mapper());
103        }
104        drop(registry);
105
106        ctx.write_target_component_reflect(component);
107        return;
108    }
109
110    // Try to clone using ReflectFromReflect
111    if let Some(reflect_from_reflect) =
112        registry.get_type_data::<bevy_reflect::ReflectFromReflect>(type_id)
113        && let Some(mut component) =
114            reflect_from_reflect.from_reflect(source_component_reflect.as_partial_reflect())
115    {
116        if let Some(reflect_component) =
117            registry.get_type_data::<crate::reflect::ReflectComponent>(type_id)
118        {
119            reflect_component.map_entities(&mut *component, ctx.entity_mapper());
120        }
121        drop(registry);
122
123        ctx.write_target_component_reflect(component);
124        return;
125    }
126    // Else, try to clone using ReflectDefault
127    if let Some(reflect_default) =
128        registry.get_type_data::<bevy_reflect::std_traits::ReflectDefault>(type_id)
129    {
130        let mut component = reflect_default.default();
131        component.apply(source_component_reflect.as_partial_reflect());
132        drop(registry);
133        ctx.write_target_component_reflect(component);
134        return;
135    }
136    // Otherwise, try to clone using ReflectFromWorld
137    if let Some(reflect_from_world) =
138        registry.get_type_data::<crate::reflect::ReflectFromWorld>(type_id)
139    {
140        use crate::{entity::EntityMapper, world::World};
141
142        let reflect_from_world = reflect_from_world.clone();
143        let Ok(source_component_cloned) = source_component_reflect.to_dynamic() else {
144            let component_info = ctx.component_info();
145
146            log::error!(
147                "Failed to clone source component ({}) because to_dynamic call failed. Does your component contain an opaque type that does not implement Reflect?",
148                component_info.name()
149            );
150            return;
151        };
152        let component_layout = component_info.layout();
153        let target = ctx.target();
154        let component_id = ctx.component_id();
155        drop(registry);
156        ctx.queue_deferred(move |world: &mut World, mapper: &mut dyn EntityMapper| {
157            let mut component = reflect_from_world.from_world(world);
158            assert_eq!(type_id, (*component).type_id());
159            component.apply(source_component_cloned.as_partial_reflect());
160            if let Some(reflect_component) = app_registry
161                .read()
162                .get_type_data::<crate::reflect::ReflectComponent>(type_id)
163            {
164                reflect_component.map_entities(&mut *component, mapper);
165            }
166            // SAFETY:
167            // - component_id is from the same world as target entity
168            // - component is a valid value represented by component_id
169            unsafe {
170                use alloc::boxed::Box;
171                use bevy_ptr::OwningPtr;
172
173                let raw_component_ptr =
174                    core::ptr::NonNull::new_unchecked(Box::into_raw(component).cast::<u8>());
175                world
176                    .entity_mut(target)
177                    .insert_by_id(component_id, OwningPtr::new(raw_component_ptr));
178
179                if component_layout.size() > 0 {
180                    // Ensure we don't attempt to deallocate zero-sized components
181                    alloc::alloc::dealloc(raw_component_ptr.as_ptr(), component_layout);
182                }
183            }
184        });
185    }
186}
187
188/// Noop implementation of component clone handler function.
189///
190/// See [`EntityClonerBuilder`](crate::entity::EntityClonerBuilder) for details.
191pub fn component_clone_ignore(_source: &SourceComponent, _ctx: &mut ComponentCloneCtx) {}
192
193/// Wrapper for components clone specialization using autoderef.
194#[doc(hidden)]
195pub struct DefaultCloneBehaviorSpecialization<T>(PhantomData<T>);
196
197impl<T> Default for DefaultCloneBehaviorSpecialization<T> {
198    fn default() -> Self {
199        Self(PhantomData)
200    }
201}
202
203/// Base trait for components clone specialization using autoderef.
204#[doc(hidden)]
205pub trait DefaultCloneBehaviorBase {
206    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
207}
208
209impl<C> DefaultCloneBehaviorBase for DefaultCloneBehaviorSpecialization<C> {
210    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
211        ComponentCloneBehavior::Default
212    }
213}
214
215/// Specialized trait for components clone specialization using autoderef.
216#[doc(hidden)]
217pub trait DefaultCloneBehaviorViaClone {
218    fn default_clone_behavior(&self) -> ComponentCloneBehavior;
219}
220
221impl<C: Clone + Component> DefaultCloneBehaviorViaClone for &DefaultCloneBehaviorSpecialization<C> {
222    fn default_clone_behavior(&self) -> ComponentCloneBehavior {
223        ComponentCloneBehavior::clone::<C>()
224    }
225}