use core::{any::TypeId, mem};
use bevy::{
ecs::component::{Immutable, Mutable},
prelude::*,
};
use bytes::Bytes;
use super::ctx::{RemoveCtx, WriteCtx};
use crate::{prelude::*, shared::replication::deferred_entity::DeferredEntity};
#[derive(Clone, Copy)]
pub(super) struct UntypedReceiveFns {
type_id: TypeId,
type_name: ShortName<'static>,
write: unsafe fn(),
remove: RemoveFn,
}
impl UntypedReceiveFns {
pub(super) fn default_fns<C: Component<Mutability: MutWrite<C>>>() -> Self {
Self::new(C::Mutability::default_write_fn(), default_remove::<C>)
}
pub(super) fn new<C: Component>(write: WriteFn<C>, remove: RemoveFn) -> Self {
Self {
type_id: TypeId::of::<C>(),
type_name: ShortName::of::<C>(),
write: unsafe { mem::transmute::<WriteFn<C>, unsafe fn()>(write) },
remove,
}
}
pub(super) unsafe fn write<C: Component>(
&self,
ctx: &mut WriteCtx,
rule_fns: &RuleFns<C>,
entity: &mut DeferredEntity,
message: &mut Bytes,
) -> Result<()> {
debug_assert_eq!(
self.type_id,
TypeId::of::<C>(),
"trying to call a receive write function with `{}`, but it was created with `{}`",
ShortName::of::<C>(),
self.type_name,
);
let write: WriteFn<C> = unsafe { mem::transmute(self.write) };
(write)(ctx, rule_fns, entity, message)
}
pub(super) fn remove(&self, ctx: &mut RemoveCtx, entity: &mut DeferredEntity) {
(self.remove)(ctx, entity);
}
}
pub trait MutWrite<C: Component> {
fn default_write_fn() -> WriteFn<C>;
}
impl<C: Component<Mutability = Self>> MutWrite<C> for Mutable {
fn default_write_fn() -> WriteFn<C> {
default_write::<C>
}
}
impl<C: Component<Mutability = Self>> MutWrite<C> for Immutable {
fn default_write_fn() -> WriteFn<C> {
default_insert_write::<C>
}
}
pub type WriteFn<C> = fn(&mut WriteCtx, &RuleFns<C>, &mut DeferredEntity, &mut Bytes) -> Result<()>;
pub type RemoveFn = fn(&mut RemoveCtx, &mut DeferredEntity);
pub fn default_write<C: Component<Mutability = Mutable>>(
ctx: &mut WriteCtx,
rule_fns: &RuleFns<C>,
entity: &mut DeferredEntity,
message: &mut Bytes,
) -> Result<()> {
if let Some(mut component) = entity.get_mut::<C>() {
rule_fns.deserialize_in_place(ctx, &mut *component, message)?;
} else {
let component: C = rule_fns.deserialize(ctx, message)?;
entity.insert(component);
}
Ok(())
}
pub fn write_if_neq<C: Component<Mutability = Mutable> + PartialEq>(
ctx: &mut WriteCtx,
rule_fns: &RuleFns<C>,
entity: &mut DeferredEntity,
message: &mut Bytes,
) -> Result<()> {
let component: C = rule_fns.deserialize(ctx, message)?;
if let Some(mut current) = entity.get_mut::<C>() {
if *current != component {
*current = component;
}
} else {
entity.insert(component);
}
Ok(())
}
pub fn default_insert_write<C: Component>(
ctx: &mut WriteCtx,
rule_fns: &RuleFns<C>,
entity: &mut DeferredEntity,
message: &mut Bytes,
) -> Result<()> {
let component: C = rule_fns.deserialize(ctx, message)?;
entity.insert(component);
Ok(())
}
pub fn default_remove<C: Component>(_ctx: &mut RemoveCtx, entity: &mut DeferredEntity) {
entity.remove::<C>();
}