use legion::{ entity::EntityAllocator, prelude::*, storage::{ ArchetypeDescription, ComponentMeta, ComponentResourceSet, ComponentTypeId, TagMeta, TagStorage, TagTypeId, }, }; use serde::{ de::{self, DeserializeSeed, IgnoredAny, Visitor}, Deserialize, Deserializer, Serialize, Serializer, }; use std::{any::TypeId, cell::RefCell, collections::HashMap, marker::PhantomData, ptr::NonNull}; use type_uuid::TypeUuid; #[derive(TypeUuid, Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] #[uuid = "5fd8256d-db36-4fe2-8211-c7b3446e1927"] struct Pos(f32, f32, f32); #[derive(TypeUuid, Serialize, Deserialize, Clone, Copy, Debug, PartialEq)] #[uuid = "14dec17f-ae14-40a3-8e44-e487fc423287"] struct Vel(f32, f32, f32); #[derive(Clone, Copy, Debug, PartialEq)] struct Unregistered(f32, f32, f32); struct ComponentDeserializer<'de, T: Deserialize<'de>> { ptr: *mut T, _marker: PhantomData<&'de T>, } impl<'de, T: Deserialize<'de> + 'static> DeserializeSeed<'de> for ComponentDeserializer<'de, T> { type Value = (); fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { let value = >::deserialize(deserializer)?; unsafe { std::ptr::write(self.ptr, value); } Ok(()) } } struct ComponentSeqDeserializer<'a, T> { get_next_storage_fn: &'a mut dyn FnMut() -> Option<(NonNull, usize)>, _marker: PhantomData, } impl<'de, 'a, T: for<'b> Deserialize<'b> + 'static> DeserializeSeed<'de> for ComponentSeqDeserializer<'a, T> { type Value = (); fn deserialize(self, deserializer: D) -> Result where D: Deserializer<'de>, { deserializer.deserialize_seq(self) } } impl<'de, 'a, T: for<'b> Deserialize<'b> + 'static> Visitor<'de> for ComponentSeqDeserializer<'a, T> { type Value = (); fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("sequence of objects") } fn visit_seq(self, mut seq: A) -> Result where A: de::SeqAccess<'de>, { let size = seq.size_hint(); for _ in 0..size.unwrap_or(std::usize::MAX) { match (self.get_next_storage_fn)() { Some((storage_ptr, storage_len)) => { let storage_ptr = storage_ptr.as_ptr() as *mut T; for idx in 0..storage_len { let element_ptr = unsafe { storage_ptr.offset(idx as isize) }; if let None = seq.next_element_seed(ComponentDeserializer { ptr: element_ptr, _marker: PhantomData, })? { panic!( "expected {} elements in chunk but only {} found", storage_len, idx ); } } } None => { if let Some(_) = seq.next_element::()? { panic!("unexpected element when there was no storage space available"); } else { // No more elements and no more storage - that's what we want! break; } } } } Ok(()) } } #[derive(Clone)] struct TagRegistration { uuid: type_uuid::Bytes, ty: TypeId, tag_serialize_fn: fn(&TagStorage, &mut dyn FnMut(&dyn erased_serde::Serialize)), tag_deserialize_fn: fn( deserializer: &mut dyn erased_serde::Deserializer, &mut TagStorage, ) -> Result<(), erased_serde::Error>, register_tag_fn: fn(&mut ArchetypeDescription), } impl TagRegistration { fn of< T: TypeUuid + Serialize + for<'de> Deserialize<'de> + PartialEq + Clone + Send + Sync + 'static, >() -> Self { Self { uuid: T::UUID, ty: TypeId::of::(), tag_serialize_fn: |tag_storage, serialize_fn| { // it's safe because we know this is the correct type due to lookup let slice = unsafe { tag_storage.data_slice::() }; serialize_fn(&&*slice); }, tag_deserialize_fn: |deserializer, tag_storage| { // TODO implement visitor to avoid allocation of Vec let tag_vec = as Deserialize>::deserialize(deserializer)?; for tag in tag_vec { // Tag types should line up, making this safe unsafe { tag_storage.push(tag); } } Ok(()) }, register_tag_fn: |desc| { desc.register_tag::(); }, } } } #[derive(Clone)] struct ComponentRegistration { uuid: type_uuid::Bytes, ty: TypeId, comp_serialize_fn: fn(&ComponentResourceSet, &mut dyn FnMut(&dyn erased_serde::Serialize)), comp_deserialize_fn: fn( deserializer: &mut dyn erased_serde::Deserializer, get_next_storage_fn: &mut dyn FnMut() -> Option<(NonNull, usize)>, ) -> Result<(), erased_serde::Error>, register_comp_fn: fn(&mut ArchetypeDescription), } impl ComponentRegistration { fn of Deserialize<'de> + Send + Sync + 'static>() -> Self { Self { uuid: T::UUID, ty: TypeId::of::(), comp_serialize_fn: |comp_storage, serialize_fn| { // it's safe because we know this is the correct type due to lookup let slice = unsafe { comp_storage.data_slice::() }; serialize_fn(&*slice); }, comp_deserialize_fn: |deserializer, get_next_storage_fn| { let comp_seq_deser = ComponentSeqDeserializer:: { get_next_storage_fn, _marker: PhantomData, }; comp_seq_deser.deserialize(deserializer)?; Ok(()) }, register_comp_fn: |desc| { desc.register_component::(); }, } } } #[derive(Serialize, Deserialize)] struct SerializedArchetypeDescription { tag_types: Vec, component_types: Vec, } struct SerializeImpl { tag_types: HashMap, comp_types: HashMap, entity_map: RefCell>, } impl legion::ser::WorldSerializer for SerializeImpl { fn can_serialize_tag(&self, ty: &TagTypeId, _meta: &TagMeta) -> bool { self.tag_types.get(&ty.0).is_some() } fn can_serialize_component(&self, ty: &ComponentTypeId, _meta: &ComponentMeta) -> bool { self.comp_types.get(&ty.0).is_some() } fn serialize_archetype_description( &self, serializer: S, archetype_desc: &ArchetypeDescription, ) -> Result { let tags_to_serialize = archetype_desc .tags() .iter() .filter_map(|(ty, _)| self.tag_types.get(&ty.0)) .map(|reg| reg.uuid) .collect::>(); let components_to_serialize = archetype_desc .components() .iter() .filter_map(|(ty, _)| self.comp_types.get(&ty.0)) .map(|reg| reg.uuid) .collect::>(); SerializedArchetypeDescription { tag_types: tags_to_serialize, component_types: components_to_serialize, } .serialize(serializer) } fn serialize_components( &self, serializer: S, component_type: &ComponentTypeId, _component_meta: &ComponentMeta, components: &ComponentResourceSet, ) -> Result { if let Some(reg) = self.comp_types.get(&component_type.0) { let result = RefCell::new(None); let serializer = RefCell::new(Some(serializer)); { let mut result_ref = result.borrow_mut(); (reg.comp_serialize_fn)(components, &mut |serialize| { result_ref.replace(erased_serde::serialize( serialize, serializer.borrow_mut().take().unwrap(), )); }); } return result.borrow_mut().take().unwrap(); } panic!( "received unserializable type {:?}, this should be filtered by can_serialize", component_type ); } fn serialize_tags( &self, serializer: S, tag_type: &TagTypeId, _tag_meta: &TagMeta, tags: &TagStorage, ) -> Result { if let Some(reg) = self.tag_types.get(&tag_type.0) { let result = RefCell::new(None); let serializer = RefCell::new(Some(serializer)); { let mut result_ref = result.borrow_mut(); (reg.tag_serialize_fn)(tags, &mut |serialize| { result_ref.replace(erased_serde::serialize( serialize, serializer.borrow_mut().take().unwrap(), )); }); } return result.borrow_mut().take().unwrap(); } panic!( "received unserializable type {:?}, this should be filtered by can_serialize", tag_type ); } fn serialize_entities( &self, serializer: S, entities: &[Entity], ) -> Result { let mut uuid_map = self.entity_map.borrow_mut(); serializer.collect_seq(entities.iter().map(|e| { *uuid_map .entry(*e) .or_insert_with(|| *uuid::Uuid::new_v4().as_bytes()) })) } } struct DeserializeImpl { tag_types: HashMap, comp_types: HashMap, tag_types_by_uuid: HashMap, comp_types_by_uuid: HashMap, entity_map: RefCell>, } impl legion::de::WorldDeserializer for DeserializeImpl { fn deserialize_archetype_description<'de, D: Deserializer<'de>>( &self, deserializer: D, ) -> Result>::Error> { let serialized_desc = ::deserialize(deserializer)?; let mut desc = ArchetypeDescription::default(); for tag in serialized_desc.tag_types { if let Some(reg) = self.tag_types_by_uuid.get(&tag) { (reg.register_tag_fn)(&mut desc); } } for comp in serialized_desc.component_types { if let Some(reg) = self.comp_types_by_uuid.get(&comp) { (reg.register_comp_fn)(&mut desc); } } Ok(desc) } fn deserialize_components<'de, D: Deserializer<'de>>( &self, deserializer: D, component_type: &ComponentTypeId, _component_meta: &ComponentMeta, get_next_storage_fn: &mut dyn FnMut() -> Option<(NonNull, usize)>, ) -> Result<(), >::Error> { if let Some(reg) = self.comp_types.get(&component_type.0) { let mut erased = erased_serde::Deserializer::erase(deserializer); (reg.comp_deserialize_fn)(&mut erased, get_next_storage_fn) .map_err(<>::Error as serde::de::Error>::custom)?; } else { ::deserialize(deserializer)?; } Ok(()) } fn deserialize_tags<'de, D: Deserializer<'de>>( &self, deserializer: D, tag_type: &TagTypeId, _tag_meta: &TagMeta, tags: &mut TagStorage, ) -> Result<(), >::Error> { if let Some(reg) = self.tag_types.get(&tag_type.0) { let mut erased = erased_serde::Deserializer::erase(deserializer); (reg.tag_deserialize_fn)(&mut erased, tags) .map_err(<>::Error as serde::de::Error>::custom)?; } else { ::deserialize(deserializer)?; } Ok(()) } fn deserialize_entities<'de, D: Deserializer<'de>>( &self, deserializer: D, entity_allocator: &EntityAllocator, entities: &mut Vec, ) -> Result<(), >::Error> { let entity_uuids = as Deserialize>::deserialize(deserializer)?; let mut entity_map = self.entity_map.borrow_mut(); for id in entity_uuids { let entity = entity_allocator.create_entity(); entity_map.insert(id, entity); entities.push(entity); } Ok(()) } } fn main() { // create world let universe = Universe::new(); let mut world = universe.create_world(); // Pos and Vel are both serializable, so all components in this chunkset will be serialized world.insert( (), vec![ (Pos(1., 2., 3.), Vel(1., 2., 3.)), (Pos(1., 2., 3.), Vel(1., 2., 3.)), (Pos(1., 2., 3.), Vel(1., 2., 3.)), (Pos(1., 2., 3.), Vel(1., 2., 3.)), ], ); // Unserializable components are not serialized, so only the Pos components should be serialized in this chunkset for _ in 0..1000 { world.insert( (Pos(4., 5., 6.), Unregistered(4., 5., 6.)), vec![ (Pos(1., 2., 3.), Unregistered(4., 5., 6.)), (Pos(1., 2., 3.), Unregistered(4., 5., 6.)), (Pos(1., 2., 3.), Unregistered(4., 5., 6.)), (Pos(1., 2., 3.), Unregistered(4., 5., 6.)), ], ); } // Entities with no serializable components are not serialized, so this entire chunkset should be skipped in the output world.insert( (Unregistered(4., 5., 6.),), vec![(Unregistered(4., 5., 6.),), (Unregistered(4., 5., 6.),)], ); let comp_registrations = [ ComponentRegistration::of::(), ComponentRegistration::of::(), ]; let tag_registrations = [TagRegistration::of::(), TagRegistration::of::()]; use std::iter::FromIterator; let ser_helper = SerializeImpl { comp_types: HashMap::from_iter(comp_registrations.iter().map(|reg| (reg.ty, reg.clone()))), tag_types: HashMap::from_iter(tag_registrations.iter().map(|reg| (reg.ty, reg.clone()))), entity_map: RefCell::new(HashMap::new()), }; let serializable = legion::ser::serializable_world(&world, &ser_helper); let serialized_data = serde_json::to_string(&serializable).unwrap(); let de_helper = DeserializeImpl { tag_types_by_uuid: HashMap::from_iter( ser_helper .tag_types .iter() .map(|reg| (reg.1.uuid, reg.1.clone())), ), comp_types_by_uuid: HashMap::from_iter( ser_helper .comp_types .iter() .map(|reg| (reg.1.uuid, reg.1.clone())), ), tag_types: ser_helper.tag_types, comp_types: ser_helper.comp_types, // re-use the entity-uuid mapping entity_map: RefCell::new(HashMap::from_iter( ser_helper .entity_map .into_inner() .into_iter() .map(|(e, uuid)| (uuid, e)), )), }; let mut deserialized_world = universe.create_world(); let mut deserializer = serde_json::Deserializer::from_str(&serialized_data); legion::de::deserialize(&mut deserialized_world, &de_helper, &mut deserializer).unwrap(); let ser_helper = SerializeImpl { tag_types: de_helper.tag_types, comp_types: de_helper.comp_types, // re-use the entity-uuid mapping entity_map: RefCell::new(HashMap::from_iter( de_helper .entity_map .into_inner() .into_iter() .map(|(uuid, e)| (e, uuid)), )), }; let serializable = legion::ser::serializable_world(&deserialized_world, &ser_helper); let roundtrip_data = serde_json::to_string(&serializable).unwrap(); assert_eq!(roundtrip_data, serialized_data); }