use core::{any::TypeId, mem};
use bevy::prelude::*;
use bytes::Bytes;
use serde::{Serialize, de::DeserializeOwned};
use super::ctx::{SerializeCtx, WriteCtx};
use crate::postcard_utils;
pub(crate) struct UntypedRuleFns {
type_id: TypeId,
type_name: ShortName<'static>,
serialize: unsafe fn(),
deserialize: unsafe fn(),
deserialize_in_place: unsafe fn(),
consume: unsafe fn(),
}
impl UntypedRuleFns {
pub(super) unsafe fn typed<C: Component>(&self) -> RuleFns<C> {
debug_assert_eq!(
self.type_id,
TypeId::of::<C>(),
"trying to call rule functions with `{}`, but they were created with `{}`",
ShortName::of::<C>(),
self.type_name,
);
RuleFns {
serialize: unsafe { mem::transmute::<unsafe fn(), SerializeFn<C>>(self.serialize) },
deserialize: unsafe {
mem::transmute::<unsafe fn(), DeserializeFn<C>>(self.deserialize)
},
deserialize_in_place: unsafe {
mem::transmute::<unsafe fn(), DeserializeInPlaceFn<C>>(self.deserialize_in_place)
},
consume: unsafe { mem::transmute::<unsafe fn(), ConsumeFn<C>>(self.consume) },
}
}
}
impl<C: Component> From<RuleFns<C>> for UntypedRuleFns {
fn from(value: RuleFns<C>) -> Self {
Self {
type_id: TypeId::of::<C>(),
type_name: ShortName::of::<C>(),
serialize: unsafe { mem::transmute::<SerializeFn<C>, unsafe fn()>(value.serialize) },
deserialize: unsafe {
mem::transmute::<DeserializeFn<C>, unsafe fn()>(value.deserialize)
},
deserialize_in_place: unsafe {
mem::transmute::<DeserializeInPlaceFn<C>, unsafe fn()>(value.deserialize_in_place)
},
consume: unsafe { mem::transmute::<ConsumeFn<C>, unsafe fn()>(value.consume) },
}
}
}
pub struct RuleFns<C> {
serialize: SerializeFn<C>,
deserialize: DeserializeFn<C>,
deserialize_in_place: DeserializeInPlaceFn<C>,
consume: ConsumeFn<C>,
}
impl<C: Component> RuleFns<C> {
pub fn new(serialize: SerializeFn<C>, deserialize: DeserializeFn<C>) -> Self {
Self {
serialize,
deserialize,
deserialize_in_place: in_place_as_deserialize::<C>,
consume: consume_as_deserialize,
}
}
pub fn new_as<T>() -> Self
where
T: Serialize + DeserializeOwned,
C: Clone + Into<T> + From<T>,
{
Self::new(serialize_as, deserialize_as)
}
pub fn with_in_place(mut self, deserialize_in_place: DeserializeInPlaceFn<C>) -> Self {
self.deserialize_in_place = deserialize_in_place;
self
}
pub fn with_consume(mut self, consume: ConsumeFn<C>) -> Self {
self.consume = consume;
self
}
pub(super) fn serialize(
&self,
ctx: &SerializeCtx,
component: &C,
message: &mut Vec<u8>,
) -> Result<()> {
(self.serialize)(ctx, component, message)
}
pub fn deserialize(&self, ctx: &mut WriteCtx, message: &mut Bytes) -> Result<C> {
(self.deserialize)(ctx, message)
}
pub fn deserialize_in_place(
&self,
ctx: &mut WriteCtx,
component: &mut C,
message: &mut Bytes,
) -> Result<()> {
(self.deserialize_in_place)(self.deserialize, ctx, component, message)
}
pub(super) fn consume(&self, ctx: &mut WriteCtx, message: &mut Bytes) -> Result<()> {
(self.consume)(self.deserialize, ctx, message)
}
}
impl<C: Component + Serialize + DeserializeOwned> Default for RuleFns<C> {
fn default() -> Self {
Self::new(default_serialize::<C>, default_deserialize::<C>)
}
}
pub type SerializeFn<C> = fn(&SerializeCtx, &C, &mut Vec<u8>) -> Result<()>;
pub type DeserializeFn<C> = fn(&mut WriteCtx, &mut Bytes) -> Result<C>;
pub type DeserializeInPlaceFn<C> =
fn(DeserializeFn<C>, &mut WriteCtx, &mut C, &mut Bytes) -> Result<()>;
pub type ConsumeFn<C> = fn(DeserializeFn<C>, &mut WriteCtx, &mut Bytes) -> Result<()>;
pub fn default_serialize<C: Component + Serialize>(
_ctx: &SerializeCtx,
component: &C,
message: &mut Vec<u8>,
) -> Result<()> {
postcard_utils::to_extend_mut(component, message)?;
Ok(())
}
pub fn default_deserialize<C: Component + DeserializeOwned>(
ctx: &mut WriteCtx,
message: &mut Bytes,
) -> Result<C> {
let mut component: C = postcard_utils::from_buf(message)?;
C::map_entities(&mut component, ctx);
Ok(component)
}
pub fn in_place_as_deserialize<C: Component>(
deserialize: DeserializeFn<C>,
ctx: &mut WriteCtx,
component: &mut C,
message: &mut Bytes,
) -> Result<()> {
*component = (deserialize)(ctx, message)?;
Ok(())
}
pub fn consume_as_deserialize<C: Component>(
deserialize: DeserializeFn<C>,
ctx: &mut WriteCtx,
message: &mut Bytes,
) -> Result<()> {
ctx.ignore_mapping = true;
(deserialize)(ctx, message)?;
ctx.ignore_mapping = false;
Ok(())
}
pub fn serialize_as<C: Component + Clone + Into<T>, T: Serialize>(
_ctx: &SerializeCtx,
component: &C,
message: &mut Vec<u8>,
) -> Result<()> {
let serializable = component.clone().into();
postcard_utils::to_extend_mut(&serializable, message)?;
Ok(())
}
pub fn deserialize_as<C: Component + From<T>, T: DeserializeOwned>(
ctx: &mut WriteCtx,
message: &mut Bytes,
) -> Result<C> {
let deserialized: T = postcard_utils::from_buf(message)?;
let mut component = deserialized.into();
C::map_entities(&mut component, ctx);
Ok(component)
}