use bevy::{prelude::*, ptr::Ptr};
use bytes::Bytes;
use super::{
ctx::{RemoveCtx, SerializeCtx, WriteCtx},
receive_fns::{MutWrite, UntypedReceiveFns},
rule_fns::UntypedRuleFns,
};
use crate::shared::replication::{
deferred_entity::DeferredEntity,
receive_markers::{EntityMarkers, ReceiveMarkerIndex, ReceiveMarkers},
};
pub(crate) struct ComponentFns {
serialize: UntypedSerializeFn,
write: UntypedWriteFn,
consume: UntypedConsumeFn,
receive: UntypedReceiveFns,
markers: Vec<Option<UntypedReceiveFns>>,
}
impl ComponentFns {
pub(super) fn new<C: Component<Mutability: MutWrite<C>>>(marker_slots: usize) -> Self {
Self {
serialize: untyped_serialize::<C>,
write: untyped_write::<C>,
consume: untyped_consume::<C>,
receive: UntypedReceiveFns::default_fns::<C>(),
markers: vec![None; marker_slots],
}
}
pub(super) fn add_marker_slot(&mut self, marker_id: ReceiveMarkerIndex) {
self.markers.insert(*marker_id, None);
}
pub(super) unsafe fn set_marker_fns(
&mut self,
marker_id: ReceiveMarkerIndex,
receive_fns: UntypedReceiveFns,
) {
let fns = self
.markers
.get_mut(*marker_id)
.unwrap_or_else(|| panic!("receive fns should have a slot for {marker_id:?}"));
debug_assert!(
fns.is_none(),
"function for {marker_id:?} can't be set twice"
);
*fns = Some(receive_fns);
}
pub(super) unsafe fn set_receive_fns(&mut self, receive_fns: UntypedReceiveFns) {
self.receive = receive_fns;
}
pub(crate) unsafe fn serialize(
&self,
ctx: &SerializeCtx,
rule_fns: &UntypedRuleFns,
ptr: Ptr,
message: &mut Vec<u8>,
) -> Result<()> {
unsafe { (self.serialize)(ctx, rule_fns, ptr, message) }
}
pub(crate) unsafe fn write(
&self,
ctx: &mut WriteCtx,
rule_fns: &UntypedRuleFns,
entity_markers: &EntityMarkers,
entity: &mut DeferredEntity,
message: &mut Bytes,
) -> Result<()> {
let receive_fns = self
.markers
.iter()
.zip(entity_markers.markers())
.filter(|&(_, contains)| *contains)
.find_map(|(&fns, _)| fns)
.unwrap_or(self.receive);
unsafe { (self.write)(ctx, &receive_fns, rule_fns, entity, message) }
}
pub(crate) unsafe fn consume_or_write(
&self,
ctx: &mut WriteCtx,
rule_fns: &UntypedRuleFns,
entity_markers: &EntityMarkers,
receive_markers: &ReceiveMarkers,
entity: &mut DeferredEntity,
message: &mut Bytes,
) -> Result<()> {
if let Some(receive_fns) = self
.markers
.iter()
.zip(entity_markers.markers())
.zip(receive_markers.iter_require_history())
.filter(|&((_, contains), _)| *contains)
.find_map(|((&fns, _), need_history)| fns.map(|fns| (fns, need_history)))
.and_then(|(fns, need_history)| need_history.then_some(fns))
{
unsafe { (self.write)(ctx, &receive_fns, rule_fns, entity, message) }
} else {
unsafe { (self.consume)(ctx, rule_fns, message) }
}
}
pub(crate) fn remove(
&self,
ctx: &mut RemoveCtx,
entity_markers: &EntityMarkers,
entity: &mut DeferredEntity,
) {
let receive_fns = self
.markers
.iter()
.zip(entity_markers.markers())
.filter(|&(_, contains)| *contains)
.find_map(|(&fns, _)| fns)
.unwrap_or(self.receive);
receive_fns.remove(ctx, entity)
}
}
type UntypedSerializeFn =
unsafe fn(&SerializeCtx, &UntypedRuleFns, Ptr, &mut Vec<u8>) -> Result<()>;
type UntypedWriteFn = unsafe fn(
&mut WriteCtx,
&UntypedReceiveFns,
&UntypedRuleFns,
&mut DeferredEntity,
&mut Bytes,
) -> Result<()>;
type UntypedConsumeFn = unsafe fn(&mut WriteCtx, &UntypedRuleFns, &mut Bytes) -> Result<()>;
unsafe fn untyped_serialize<C: Component>(
ctx: &SerializeCtx,
rule_fns: &UntypedRuleFns,
ptr: Ptr,
message: &mut Vec<u8>,
) -> Result<()> {
unsafe {
let rule_fns = rule_fns.typed::<C>();
rule_fns.serialize(ctx, ptr.deref::<C>(), message)
}
}
unsafe fn untyped_write<C: Component>(
ctx: &mut WriteCtx,
receive_fns: &UntypedReceiveFns,
rule_fns: &UntypedRuleFns,
entity: &mut DeferredEntity,
message: &mut Bytes,
) -> Result<()> {
unsafe { receive_fns.write::<C>(ctx, &rule_fns.typed::<C>(), entity, message) }
}
unsafe fn untyped_consume<C: Component>(
ctx: &mut WriteCtx,
rule_fns: &UntypedRuleFns,
message: &mut Bytes,
) -> Result<()> {
unsafe { rule_fns.typed::<C>().consume(ctx, message) }
}