use core::marker::PhantomData;
use crate::component::Component;
use crate::entity::{ComponentCloneCtx, SourceComponent};
pub type ComponentCloneFn = fn(&SourceComponent, &mut ComponentCloneCtx);
#[derive(Clone, Debug, Default)]
pub enum ComponentCloneBehavior {
#[default]
Default,
Ignore,
Custom(ComponentCloneFn),
}
impl ComponentCloneBehavior {
pub fn clone<C: Component + Clone>() -> Self {
Self::Custom(component_clone_via_clone::<C>)
}
#[cfg(feature = "bevy_reflect")]
pub fn reflect() -> Self {
Self::Custom(component_clone_via_reflect)
}
pub fn global_default_fn() -> ComponentCloneFn {
#[cfg(feature = "bevy_reflect")]
return component_clone_via_reflect;
#[cfg(not(feature = "bevy_reflect"))]
return component_clone_ignore;
}
pub fn resolve(&self, default: ComponentCloneFn) -> ComponentCloneFn {
match self {
ComponentCloneBehavior::Default => default,
ComponentCloneBehavior::Ignore => component_clone_ignore,
ComponentCloneBehavior::Custom(custom) => *custom,
}
}
}
pub fn component_clone_via_clone<C: Clone + Component>(
source: &SourceComponent,
ctx: &mut ComponentCloneCtx,
) {
if let Some(component) = source.read::<C>() {
ctx.write_target_component(component.clone());
}
}
#[cfg(feature = "bevy_reflect")]
pub fn component_clone_via_reflect(source: &SourceComponent, ctx: &mut ComponentCloneCtx) {
let Some(app_registry) = ctx.type_registry().cloned() else {
return;
};
let registry = app_registry.read();
let Some(source_component_reflect) = source.read_reflect(®istry) else {
return;
};
let component_info = ctx.component_info();
let type_id = component_info.type_id().unwrap();
if let Ok(mut component) = source_component_reflect.reflect_clone() {
if let Some(reflect_component) =
registry.get_type_data::<crate::reflect::ReflectComponent>(type_id)
{
reflect_component.map_entities(&mut *component, ctx.entity_mapper());
}
drop(registry);
ctx.write_target_component_reflect(component);
return;
}
if let Some(reflect_from_reflect) =
registry.get_type_data::<bevy_reflect::ReflectFromReflect>(type_id)
{
if let Some(mut component) =
reflect_from_reflect.from_reflect(source_component_reflect.as_partial_reflect())
{
if let Some(reflect_component) =
registry.get_type_data::<crate::reflect::ReflectComponent>(type_id)
{
reflect_component.map_entities(&mut *component, ctx.entity_mapper());
}
drop(registry);
ctx.write_target_component_reflect(component);
return;
}
}
if let Some(reflect_default) =
registry.get_type_data::<bevy_reflect::std_traits::ReflectDefault>(type_id)
{
let mut component = reflect_default.default();
component.apply(source_component_reflect.as_partial_reflect());
drop(registry);
ctx.write_target_component_reflect(component);
return;
}
if let Some(reflect_from_world) =
registry.get_type_data::<crate::reflect::ReflectFromWorld>(type_id)
{
use crate::{entity::EntityMapper, world::World};
let reflect_from_world = reflect_from_world.clone();
let source_component_cloned = source_component_reflect.to_dynamic();
let component_layout = component_info.layout();
let target = ctx.target();
let component_id = ctx.component_id();
drop(registry);
ctx.queue_deferred(move |world: &mut World, mapper: &mut dyn EntityMapper| {
let mut component = reflect_from_world.from_world(world);
assert_eq!(type_id, (*component).type_id());
component.apply(source_component_cloned.as_partial_reflect());
if let Some(reflect_component) = app_registry
.read()
.get_type_data::<crate::reflect::ReflectComponent>(type_id)
{
reflect_component.map_entities(&mut *component, mapper);
}
unsafe {
use alloc::boxed::Box;
use bevy_ptr::OwningPtr;
let raw_component_ptr =
core::ptr::NonNull::new_unchecked(Box::into_raw(component).cast::<u8>());
world
.entity_mut(target)
.insert_by_id(component_id, OwningPtr::new(raw_component_ptr));
if component_layout.size() > 0 {
alloc::alloc::dealloc(raw_component_ptr.as_ptr(), component_layout);
}
}
});
}
}
pub fn component_clone_ignore(_source: &SourceComponent, _ctx: &mut ComponentCloneCtx) {}
#[doc(hidden)]
pub struct DefaultCloneBehaviorSpecialization<T>(PhantomData<T>);
impl<T> Default for DefaultCloneBehaviorSpecialization<T> {
fn default() -> Self {
Self(PhantomData)
}
}
#[doc(hidden)]
pub trait DefaultCloneBehaviorBase {
fn default_clone_behavior(&self) -> ComponentCloneBehavior;
}
impl<C> DefaultCloneBehaviorBase for DefaultCloneBehaviorSpecialization<C> {
fn default_clone_behavior(&self) -> ComponentCloneBehavior {
ComponentCloneBehavior::Default
}
}
#[doc(hidden)]
pub trait DefaultCloneBehaviorViaClone {
fn default_clone_behavior(&self) -> ComponentCloneBehavior;
}
impl<C: Clone + Component> DefaultCloneBehaviorViaClone for &DefaultCloneBehaviorSpecialization<C> {
fn default_clone_behavior(&self) -> ComponentCloneBehavior {
ComponentCloneBehavior::clone::<C>()
}
}