use serde::ser::{Serialize, SerializeMap, Serializer};
use super::{
archetypes::ser::ArchetypeLayoutSerializer, entities::ser::EntitiesLayoutSerializer,
EntitySerializer, UnknownType, WorldField,
};
use crate::{
internals::{query::filter::LayoutFilter, storage::component::ComponentTypeId, world::World},
serialize::set_entity_serializer,
storage::{ArchetypeIndex, UnknownComponentStorage},
};
pub trait WorldSerializer {
type TypeId: Serialize + Ord;
fn map_id(&self, type_id: ComponentTypeId) -> Result<Self::TypeId, UnknownType>;
unsafe fn serialize_component<S: Serializer>(
&self,
ty: ComponentTypeId,
ptr: *const u8,
serializer: S,
) -> Result<S::Ok, S::Error>;
unsafe fn serialize_component_slice<S: Serializer>(
&self,
ty: ComponentTypeId,
storage: &dyn UnknownComponentStorage,
archetype: ArchetypeIndex,
serializer: S,
) -> Result<S::Ok, S::Error>;
}
pub struct SerializableWorld<'a, F: LayoutFilter, W: WorldSerializer, E: EntitySerializer> {
world: &'a World,
filter: F,
world_serializer: &'a W,
entity_serializer: &'a E,
}
impl<'a, F: LayoutFilter, W: WorldSerializer, E: EntitySerializer> SerializableWorld<'a, F, W, E> {
pub(crate) fn new(
world: &'a World,
filter: F,
world_serializer: &'a W,
entity_serializer: &'a E,
) -> Self {
Self {
world,
filter,
world_serializer,
entity_serializer,
}
}
}
impl<'a, F: LayoutFilter, W: WorldSerializer, E: EntitySerializer> Serialize
for SerializableWorld<'a, F, W, E>
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serialize_world(
serializer,
self.world,
&self.filter,
self.world_serializer,
self.entity_serializer,
)
}
}
fn serialize_world<S, F, W, E>(
serializer: S,
world: &World,
filter: &F,
world_serializer: &W,
entity_serializer: &E,
) -> Result<S::Ok, S::Error>
where
S: Serializer,
F: LayoutFilter,
W: WorldSerializer,
E: EntitySerializer,
{
let human_readable = serializer.is_human_readable();
let mut root = serializer.serialize_map(Some(1))?;
let mut hoist = core::cell::Cell::new(None);
let hoist_ref = &mut hoist;
let root_ref = &mut root;
set_entity_serializer(entity_serializer, || {
let result = if human_readable {
root_ref.serialize_entry(
&WorldField::Entities,
&EntitiesLayoutSerializer {
world_serializer,
world,
filter,
},
)
} else {
root_ref.serialize_entry(
&WorldField::Packed,
&ArchetypeLayoutSerializer {
world_serializer,
world,
filter,
},
)
};
hoist_ref.set(Some(result));
});
hoist.into_inner().unwrap()?;
root.end()
}