From 1834ce0ddb7e37b8370c230964af945f7920c07c Mon Sep 17 00:00:00 2001 From: kaphula Date: Fri, 18 Oct 2024 02:53:27 +0300 Subject: [PATCH 1/7] Add serialization example. --- .gitignore | 1 + Cargo.toml | 1 + examples/serialize_to_disk.rs | 177 ++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 examples/serialize_to_disk.rs diff --git a/.gitignore b/.gitignore index 69369904..d889fbf5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target **/*.rs.bk Cargo.lock +.idea diff --git a/Cargo.toml b/Cargo.toml index c040a710..cc8c347a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ rand = "0.8.3" trybuild = "1.0.23" serde = { version = "1.0.117", features = ["derive"] } serde_test = "1.0.117" +serde_json = "1.0.117" [[bench]] name = "bench" diff --git a/examples/serialize_to_disk.rs b/examples/serialize_to_disk.rs new file mode 100644 index 00000000..1d964644 --- /dev/null +++ b/examples/serialize_to_disk.rs @@ -0,0 +1,177 @@ +//! This example demonstrates how to save [hecs::World] instance +//! to disk and load it back to memory using serialization. It can be useful for implementing +//! a save mechanism for a game. +//! +//! The example creates a sample `World`, serializes it, saves it to disk as `saved_world.world` file, +//! loads it back from the disk, deserializes the loaded world data and validates that component +//! data of the worlds match. +//! +//! Run this example from crate root with: +//! `cargo run --example serialize_to_disk --features "column-serialize"` + +#[cfg(feature = "column-serialize")] +mod serialize_to_disk_example { + use std::any::TypeId; + pub use std::fs::File; + pub use std::io::{BufReader, Write}; + pub use std::path::Path; + pub use serde::{Deserialize, Serialize}; + pub use hecs::{Archetype, ColumnBatchBuilder, ColumnBatchType, World}; + pub use hecs::serialize::column::{deserialize_column, try_serialize, try_serialize_id, DeserializeContext, SerializeContext}; + + + // Identifiers for the components we want to include in the serialization process: + #[derive(Serialize, Deserialize)] + enum ComponentId { + TestComponent1, + TestComponent2, + } + + // We need to implement a context type for the hecs serialization process: + #[derive(Default)] + pub struct SaveContext { + pub components: Vec, + } + + + // Components of our world. + // Only Serialize and Deserialize derives are necessary. + #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] + pub struct ComponentA { + pub data: usize, + } + + #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] + pub struct ComponentB { + pub some_other_data: String, + } + + #[cfg(feature = "column-serialize")] + impl DeserializeContext for SaveContext { + fn deserialize_component_ids<'de, A>( + &mut self, + mut seq: A, + ) -> Result + where + A: serde::de::SeqAccess<'de>, + { + self.components.clear(); // Discard data from the previous archetype + let mut batch = ColumnBatchType::new(); + while let Some(id) = seq.next_element()? { + match id { + ComponentId::TestComponent1 => { + batch.add::(); + } + ComponentId::TestComponent2 => { + batch.add::(); + } + } + self.components.push(id); + } + Ok(batch) + } + + fn deserialize_components<'de, A>( + &mut self, + entity_count: u32, + mut seq: A, + batch: &mut ColumnBatchBuilder, + ) -> Result<(), A::Error> + where + A: serde::de::SeqAccess<'de>, + { + // Decode component data in the order that the component IDs appeared + for component in &self.components { + match *component { + ComponentId::TestComponent1 => { + deserialize_column::(entity_count, &mut seq, batch)?; + } + ComponentId::TestComponent2 => { + deserialize_column::(entity_count, &mut seq, batch)?; + } + } + } + Ok(()) + } + } + + impl SerializeContext for SaveContext { + fn component_count(&self, archetype: &Archetype) -> usize { + archetype.component_types() + .filter(|&t| t == TypeId::of::() || t == TypeId::of::()) + .count() + } + + fn serialize_component_ids( + &mut self, + archetype: &Archetype, + mut out: S, + ) -> Result { + try_serialize_id::(archetype, &ComponentId::TestComponent1, &mut out)?; + try_serialize_id::(archetype, &ComponentId::TestComponent2, &mut out)?; + out.end() + } + + fn serialize_components( + &mut self, + archetype: &Archetype, + mut out: S, + ) -> Result { + try_serialize::(archetype, &mut out)?; + try_serialize::(archetype, &mut out)?; + out.end() + } + } +} + +use serialize_to_disk_example::*; +pub fn main() { + + // initialize world: + let mut world = World::new(); + let input_data1 = ComponentA { data: 42 }; + let input_data2 = ComponentB { some_other_data: "Hello".to_string() }; + world.spawn((input_data1.clone(),)); + world.spawn((input_data2.clone(),)); + + let save_file_name = "saved_world.world"; + let mut context = SaveContext::default(); + + // serialize and save our world to disk: + let mut buffer: Vec = Vec::new(); + let mut serializer = serde_json::Serializer::new(buffer); + hecs::serialize::column::serialize(&world, &mut context, &mut serializer); + let path = Path::new(save_file_name); + let mut file = match File::create(&path) { + Err(why) => panic!("couldn't create {}: {}", path.display(), why), + Ok(file) => file, + }; + file.write(&serializer.into_inner()) + .expect(&format!("Failed to write file: {}", save_file_name)); + println!("Saved world \'{}\' to disk.", path.display()); + + + // load our world from disk and deserialize it back as world: + let open = File::open(path).expect("not found!"); + let reader = BufReader::new(open); + let mut deserializer = serde_json::Deserializer::from_reader(reader); + match hecs::serialize::column::deserialize(&mut context, &mut deserializer) { + Ok(world) => { + // we loaded world from disk successfully, let us confirm that its data is still + // the same: + println!("Loaded world \'{}\' from disk.", path.display()); + + print!("Validating world data... "); + for (e, (t)) in &mut world.query::<(&ComponentA)>() { + assert_eq!(t, &input_data1); + } + for (e, (t)) in &mut world.query::<(&ComponentB)>() { + assert_eq!(t, &input_data2); + } + println!("Ok!"); + } + Err(err) => { + println!("Failed to deserialize world: {}", err); + } + } +} From d2163796fb59af8a4f78fd362d55861f4ff17d15 Mon Sep 17 00:00:00 2001 From: kaphula Date: Fri, 18 Oct 2024 02:58:06 +0300 Subject: [PATCH 2/7] Run cargo fmt. --- examples/serialize_to_disk.rs | 323 +++++++++++++++++----------------- 1 file changed, 166 insertions(+), 157 deletions(-) diff --git a/examples/serialize_to_disk.rs b/examples/serialize_to_disk.rs index 1d964644..1487b8a5 100644 --- a/examples/serialize_to_disk.rs +++ b/examples/serialize_to_disk.rs @@ -11,167 +11,176 @@ #[cfg(feature = "column-serialize")] mod serialize_to_disk_example { - use std::any::TypeId; - pub use std::fs::File; - pub use std::io::{BufReader, Write}; - pub use std::path::Path; - pub use serde::{Deserialize, Serialize}; - pub use hecs::{Archetype, ColumnBatchBuilder, ColumnBatchType, World}; - pub use hecs::serialize::column::{deserialize_column, try_serialize, try_serialize_id, DeserializeContext, SerializeContext}; - - - // Identifiers for the components we want to include in the serialization process: - #[derive(Serialize, Deserialize)] - enum ComponentId { - TestComponent1, - TestComponent2, - } - - // We need to implement a context type for the hecs serialization process: - #[derive(Default)] - pub struct SaveContext { - pub components: Vec, - } - - - // Components of our world. - // Only Serialize and Deserialize derives are necessary. - #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] - pub struct ComponentA { - pub data: usize, - } - - #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] - pub struct ComponentB { - pub some_other_data: String, - } - - #[cfg(feature = "column-serialize")] - impl DeserializeContext for SaveContext { - fn deserialize_component_ids<'de, A>( - &mut self, - mut seq: A, - ) -> Result - where - A: serde::de::SeqAccess<'de>, - { - self.components.clear(); // Discard data from the previous archetype - let mut batch = ColumnBatchType::new(); - while let Some(id) = seq.next_element()? { - match id { - ComponentId::TestComponent1 => { - batch.add::(); - } - ComponentId::TestComponent2 => { - batch.add::(); - } + pub use hecs::serialize::column::{ + deserialize_column, try_serialize, try_serialize_id, DeserializeContext, SerializeContext, + }; + pub use hecs::{Archetype, ColumnBatchBuilder, ColumnBatchType, World}; + pub use serde::{Deserialize, Serialize}; + use std::any::TypeId; + pub use std::fs::File; + pub use std::io::{BufReader, Write}; + pub use std::path::Path; + + // Identifiers for the components we want to include in the serialization process: + #[derive(Serialize, Deserialize)] + enum ComponentId { + TestComponent1, + TestComponent2, + } + + // We need to implement a context type for the hecs serialization process: + #[derive(Default)] + pub struct SaveContext { + pub components: Vec, + } + + // Components of our world. + // Only Serialize and Deserialize derives are necessary. + #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] + pub struct ComponentA { + pub data: usize, + } + + #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] + pub struct ComponentB { + pub some_other_data: String, + } + + #[cfg(feature = "column-serialize")] + impl DeserializeContext for SaveContext { + fn deserialize_component_ids<'de, A>( + &mut self, + mut seq: A, + ) -> Result + where + A: serde::de::SeqAccess<'de>, + { + self.components.clear(); // Discard data from the previous archetype + let mut batch = ColumnBatchType::new(); + while let Some(id) = seq.next_element()? { + match id { + ComponentId::TestComponent1 => { + batch.add::(); + } + ComponentId::TestComponent2 => { + batch.add::(); + } + } + self.components.push(id); } - self.components.push(id); - } - Ok(batch) - } - - fn deserialize_components<'de, A>( - &mut self, - entity_count: u32, - mut seq: A, - batch: &mut ColumnBatchBuilder, - ) -> Result<(), A::Error> - where - A: serde::de::SeqAccess<'de>, - { - // Decode component data in the order that the component IDs appeared - for component in &self.components { - match *component { - ComponentId::TestComponent1 => { - deserialize_column::(entity_count, &mut seq, batch)?; - } - ComponentId::TestComponent2 => { - deserialize_column::(entity_count, &mut seq, batch)?; - } + Ok(batch) + } + + fn deserialize_components<'de, A>( + &mut self, + entity_count: u32, + mut seq: A, + batch: &mut ColumnBatchBuilder, + ) -> Result<(), A::Error> + where + A: serde::de::SeqAccess<'de>, + { + // Decode component data in the order that the component IDs appeared + for component in &self.components { + match *component { + ComponentId::TestComponent1 => { + deserialize_column::(entity_count, &mut seq, batch)?; + } + ComponentId::TestComponent2 => { + deserialize_column::(entity_count, &mut seq, batch)?; + } + } } - } - Ok(()) - } - } - - impl SerializeContext for SaveContext { - fn component_count(&self, archetype: &Archetype) -> usize { - archetype.component_types() - .filter(|&t| t == TypeId::of::() || t == TypeId::of::()) - .count() - } - - fn serialize_component_ids( - &mut self, - archetype: &Archetype, - mut out: S, - ) -> Result { - try_serialize_id::(archetype, &ComponentId::TestComponent1, &mut out)?; - try_serialize_id::(archetype, &ComponentId::TestComponent2, &mut out)?; - out.end() - } - - fn serialize_components( - &mut self, - archetype: &Archetype, - mut out: S, - ) -> Result { - try_serialize::(archetype, &mut out)?; - try_serialize::(archetype, &mut out)?; - out.end() - } - } + Ok(()) + } + } + + impl SerializeContext for SaveContext { + fn component_count(&self, archetype: &Archetype) -> usize { + archetype + .component_types() + .filter(|&t| t == TypeId::of::() || t == TypeId::of::()) + .count() + } + + fn serialize_component_ids( + &mut self, + archetype: &Archetype, + mut out: S, + ) -> Result { + try_serialize_id::( + archetype, + &ComponentId::TestComponent1, + &mut out, + )?; + try_serialize_id::( + archetype, + &ComponentId::TestComponent2, + &mut out, + )?; + out.end() + } + + fn serialize_components( + &mut self, + archetype: &Archetype, + mut out: S, + ) -> Result { + try_serialize::(archetype, &mut out)?; + try_serialize::(archetype, &mut out)?; + out.end() + } + } } use serialize_to_disk_example::*; pub fn main() { - - // initialize world: - let mut world = World::new(); - let input_data1 = ComponentA { data: 42 }; - let input_data2 = ComponentB { some_other_data: "Hello".to_string() }; - world.spawn((input_data1.clone(),)); - world.spawn((input_data2.clone(),)); - - let save_file_name = "saved_world.world"; - let mut context = SaveContext::default(); - - // serialize and save our world to disk: - let mut buffer: Vec = Vec::new(); - let mut serializer = serde_json::Serializer::new(buffer); - hecs::serialize::column::serialize(&world, &mut context, &mut serializer); - let path = Path::new(save_file_name); - let mut file = match File::create(&path) { - Err(why) => panic!("couldn't create {}: {}", path.display(), why), - Ok(file) => file, - }; - file.write(&serializer.into_inner()) - .expect(&format!("Failed to write file: {}", save_file_name)); - println!("Saved world \'{}\' to disk.", path.display()); - - - // load our world from disk and deserialize it back as world: - let open = File::open(path).expect("not found!"); - let reader = BufReader::new(open); - let mut deserializer = serde_json::Deserializer::from_reader(reader); - match hecs::serialize::column::deserialize(&mut context, &mut deserializer) { - Ok(world) => { - // we loaded world from disk successfully, let us confirm that its data is still - // the same: - println!("Loaded world \'{}\' from disk.", path.display()); - - print!("Validating world data... "); - for (e, (t)) in &mut world.query::<(&ComponentA)>() { - assert_eq!(t, &input_data1); - } - for (e, (t)) in &mut world.query::<(&ComponentB)>() { - assert_eq!(t, &input_data2); - } - println!("Ok!"); - } - Err(err) => { - println!("Failed to deserialize world: {}", err); - } - } + // initialize world: + let mut world = World::new(); + let input_data1 = ComponentA { data: 42 }; + let input_data2 = ComponentB { + some_other_data: "Hello".to_string(), + }; + world.spawn((input_data1.clone(),)); + world.spawn((input_data2.clone(),)); + + let save_file_name = "saved_world.world"; + let mut context = SaveContext::default(); + + // serialize and save our world to disk: + let mut buffer: Vec = Vec::new(); + let mut serializer = serde_json::Serializer::new(buffer); + hecs::serialize::column::serialize(&world, &mut context, &mut serializer); + let path = Path::new(save_file_name); + let mut file = match File::create(&path) { + Err(why) => panic!("couldn't create {}: {}", path.display(), why), + Ok(file) => file, + }; + file.write(&serializer.into_inner()) + .expect(&format!("Failed to write file: {}", save_file_name)); + println!("Saved world \'{}\' to disk.", path.display()); + + // load our world from disk and deserialize it back as world: + let open = File::open(path).expect("not found!"); + let reader = BufReader::new(open); + let mut deserializer = serde_json::Deserializer::from_reader(reader); + match hecs::serialize::column::deserialize(&mut context, &mut deserializer) { + Ok(world) => { + // we loaded world from disk successfully, let us confirm that its data is still + // the same: + println!("Loaded world \'{}\' from disk.", path.display()); + + print!("Validating world data... "); + for (e, (t)) in &mut world.query::<(&ComponentA)>() { + assert_eq!(t, &input_data1); + } + for (e, (t)) in &mut world.query::<(&ComponentB)>() { + assert_eq!(t, &input_data2); + } + println!("Ok!"); + } + Err(err) => { + println!("Failed to deserialize world: {}", err); + } + } } From c0bec92736ee54091735cb0fdb2d99a2e5eb087c Mon Sep 17 00:00:00 2001 From: kaphula Date: Sat, 19 Oct 2024 00:42:06 +0300 Subject: [PATCH 3/7] Switch serialization to bincode. Apply PR fix suggestions. --- .gitignore | 1 - Cargo.toml | 2 +- examples/serialize_to_disk.rs | 204 ++++++++++++++++------------------ 3 files changed, 96 insertions(+), 111 deletions(-) diff --git a/.gitignore b/.gitignore index d889fbf5..69369904 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ /target **/*.rs.bk Cargo.lock -.idea diff --git a/Cargo.toml b/Cargo.toml index cc8c347a..43efa383 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ rand = "0.8.3" trybuild = "1.0.23" serde = { version = "1.0.117", features = ["derive"] } serde_test = "1.0.117" -serde_json = "1.0.117" +bincode = "1.3.3" [[bench]] name = "bench" diff --git a/examples/serialize_to_disk.rs b/examples/serialize_to_disk.rs index 1487b8a5..d3e7eaf4 100644 --- a/examples/serialize_to_disk.rs +++ b/examples/serialize_to_disk.rs @@ -9,131 +9,116 @@ //! Run this example from crate root with: //! `cargo run --example serialize_to_disk --features "column-serialize"` -#[cfg(feature = "column-serialize")] -mod serialize_to_disk_example { - pub use hecs::serialize::column::{ - deserialize_column, try_serialize, try_serialize_id, DeserializeContext, SerializeContext, - }; - pub use hecs::{Archetype, ColumnBatchBuilder, ColumnBatchType, World}; - pub use serde::{Deserialize, Serialize}; - use std::any::TypeId; - pub use std::fs::File; - pub use std::io::{BufReader, Write}; - pub use std::path::Path; +use hecs::serialize::column::{ + deserialize_column, try_serialize, try_serialize_id, DeserializeContext, SerializeContext, +}; +use hecs::{Archetype, ColumnBatchBuilder, ColumnBatchType, World}; +use serde::{Deserialize, Serialize, Serializer}; +use std::any::TypeId; +use std::fs::File; +use std::io::{BufReader, Write}; +use std::path::Path; - // Identifiers for the components we want to include in the serialization process: - #[derive(Serialize, Deserialize)] - enum ComponentId { - TestComponent1, - TestComponent2, - } +// Identifiers for the components we want to include in the serialization process: +#[derive(Serialize, Deserialize)] +enum ComponentId { + ComponentA, + ComponentB, +} - // We need to implement a context type for the hecs serialization process: - #[derive(Default)] - pub struct SaveContext { - pub components: Vec, - } +// We need to implement a context type for the hecs serialization process: +#[derive(Default)] +pub struct SaveContext { + pub components: Vec, +} - // Components of our world. - // Only Serialize and Deserialize derives are necessary. - #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] - pub struct ComponentA { - pub data: usize, - } +// Components of our world. +// Only Serialize and Deserialize derives are necessary. +#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] +pub struct ComponentA { + pub data: usize, +} - #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] - pub struct ComponentB { - pub some_other_data: String, - } +#[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] +pub struct ComponentB { + pub some_other_data: String, +} - #[cfg(feature = "column-serialize")] - impl DeserializeContext for SaveContext { - fn deserialize_component_ids<'de, A>( - &mut self, - mut seq: A, - ) -> Result - where - A: serde::de::SeqAccess<'de>, - { - self.components.clear(); // Discard data from the previous archetype - let mut batch = ColumnBatchType::new(); - while let Some(id) = seq.next_element()? { - match id { - ComponentId::TestComponent1 => { - batch.add::(); - } - ComponentId::TestComponent2 => { - batch.add::(); - } +#[cfg(feature = "column-serialize")] +impl DeserializeContext for SaveContext { + fn deserialize_component_ids<'de, A>(&mut self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + self.components.clear(); // Discard data from the previous archetype + let mut batch = ColumnBatchType::new(); + while let Some(id) = seq.next_element()? { + match id { + ComponentId::ComponentA => { + batch.add::(); + } + ComponentId::ComponentB => { + batch.add::(); } - self.components.push(id); } - Ok(batch) + self.components.push(id); } + Ok(batch) + } - fn deserialize_components<'de, A>( - &mut self, - entity_count: u32, - mut seq: A, - batch: &mut ColumnBatchBuilder, - ) -> Result<(), A::Error> - where - A: serde::de::SeqAccess<'de>, - { - // Decode component data in the order that the component IDs appeared - for component in &self.components { - match *component { - ComponentId::TestComponent1 => { - deserialize_column::(entity_count, &mut seq, batch)?; - } - ComponentId::TestComponent2 => { - deserialize_column::(entity_count, &mut seq, batch)?; - } + fn deserialize_components<'de, A>( + &mut self, + entity_count: u32, + mut seq: A, + batch: &mut ColumnBatchBuilder, + ) -> Result<(), A::Error> + where + A: serde::de::SeqAccess<'de>, + { + // Decode component data in the order that the component IDs appeared + for component in &self.components { + match *component { + ComponentId::ComponentA => { + deserialize_column::(entity_count, &mut seq, batch)?; + } + ComponentId::ComponentB => { + deserialize_column::(entity_count, &mut seq, batch)?; } } - Ok(()) } + Ok(()) } +} - impl SerializeContext for SaveContext { - fn component_count(&self, archetype: &Archetype) -> usize { - archetype - .component_types() - .filter(|&t| t == TypeId::of::() || t == TypeId::of::()) - .count() - } +impl SerializeContext for SaveContext { + fn component_count(&self, archetype: &Archetype) -> usize { + archetype + .component_types() + .filter(|&t| t == TypeId::of::() || t == TypeId::of::()) + .count() + } - fn serialize_component_ids( - &mut self, - archetype: &Archetype, - mut out: S, - ) -> Result { - try_serialize_id::( - archetype, - &ComponentId::TestComponent1, - &mut out, - )?; - try_serialize_id::( - archetype, - &ComponentId::TestComponent2, - &mut out, - )?; - out.end() - } + fn serialize_component_ids( + &mut self, + archetype: &Archetype, + mut out: S, + ) -> Result { + try_serialize_id::(archetype, &ComponentId::ComponentA, &mut out)?; + try_serialize_id::(archetype, &ComponentId::ComponentB, &mut out)?; + out.end() + } - fn serialize_components( - &mut self, - archetype: &Archetype, - mut out: S, - ) -> Result { - try_serialize::(archetype, &mut out)?; - try_serialize::(archetype, &mut out)?; - out.end() - } + fn serialize_components( + &mut self, + archetype: &Archetype, + mut out: S, + ) -> Result { + try_serialize::(archetype, &mut out)?; + try_serialize::(archetype, &mut out)?; + out.end() } } -use serialize_to_disk_example::*; pub fn main() { // initialize world: let mut world = World::new(); @@ -149,21 +134,22 @@ pub fn main() { // serialize and save our world to disk: let mut buffer: Vec = Vec::new(); - let mut serializer = serde_json::Serializer::new(buffer); + let options = bincode::options(); + let mut serializer = bincode::Serializer::new(&mut buffer, options); hecs::serialize::column::serialize(&world, &mut context, &mut serializer); let path = Path::new(save_file_name); let mut file = match File::create(&path) { Err(why) => panic!("couldn't create {}: {}", path.display(), why), Ok(file) => file, }; - file.write(&serializer.into_inner()) + file.write(&buffer) .expect(&format!("Failed to write file: {}", save_file_name)); println!("Saved world \'{}\' to disk.", path.display()); // load our world from disk and deserialize it back as world: let open = File::open(path).expect("not found!"); let reader = BufReader::new(open); - let mut deserializer = serde_json::Deserializer::from_reader(reader); + let mut deserializer = bincode::Deserializer::with_reader(reader, options); match hecs::serialize::column::deserialize(&mut context, &mut deserializer) { Ok(world) => { // we loaded world from disk successfully, let us confirm that its data is still From 29d9a0a040143d11afb35d66dd1805f188093e65 Mon Sep 17 00:00:00 2001 From: kaphula Date: Sat, 19 Oct 2024 01:11:24 +0300 Subject: [PATCH 4/7] Separate serialization save contexts. --- examples/serialize_to_disk.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/examples/serialize_to_disk.rs b/examples/serialize_to_disk.rs index d3e7eaf4..25800e1a 100644 --- a/examples/serialize_to_disk.rs +++ b/examples/serialize_to_disk.rs @@ -26,10 +26,12 @@ enum ComponentId { ComponentB, } -// We need to implement a context type for the hecs serialization process: +// We need to implement context types for the hecs serialization process: #[derive(Default)] -pub struct SaveContext { - pub components: Vec, +pub struct SaveContextSerialize {} +#[derive(Default)] +pub struct SaveContextDeserialize { + pub components: Vec, } // Components of our world. @@ -45,7 +47,7 @@ pub struct ComponentB { } #[cfg(feature = "column-serialize")] -impl DeserializeContext for SaveContext { +impl DeserializeContext for SaveContextDeserialize { fn deserialize_component_ids<'de, A>(&mut self, mut seq: A) -> Result where A: serde::de::SeqAccess<'de>, @@ -90,7 +92,7 @@ impl DeserializeContext for SaveContext { } } -impl SerializeContext for SaveContext { +impl SerializeContext for SaveContextSerialize { fn component_count(&self, archetype: &Archetype) -> usize { archetype .component_types() @@ -130,13 +132,12 @@ pub fn main() { world.spawn((input_data2.clone(),)); let save_file_name = "saved_world.world"; - let mut context = SaveContext::default(); // serialize and save our world to disk: let mut buffer: Vec = Vec::new(); let options = bincode::options(); let mut serializer = bincode::Serializer::new(&mut buffer, options); - hecs::serialize::column::serialize(&world, &mut context, &mut serializer); + hecs::serialize::column::serialize(&world, &mut SaveContextSerialize::default(), &mut serializer); let path = Path::new(save_file_name); let mut file = match File::create(&path) { Err(why) => panic!("couldn't create {}: {}", path.display(), why), @@ -150,7 +151,7 @@ pub fn main() { let open = File::open(path).expect("not found!"); let reader = BufReader::new(open); let mut deserializer = bincode::Deserializer::with_reader(reader, options); - match hecs::serialize::column::deserialize(&mut context, &mut deserializer) { + match hecs::serialize::column::deserialize(&mut SaveContextDeserialize::default(), &mut deserializer) { Ok(world) => { // we loaded world from disk successfully, let us confirm that its data is still // the same: From 00cc00483ed95d0cab2c0aa3d9c71906f2a22415 Mon Sep 17 00:00:00 2001 From: kaphula Date: Sat, 19 Oct 2024 01:30:15 +0300 Subject: [PATCH 5/7] Add required example features to Cargo.toml. --- Cargo.toml | 5 +++++ examples/serialize_to_disk.rs | 34 +++++++++++++++++++++------------- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 43efa383..8c43fd9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,3 +53,8 @@ debug = true [workspace] members = ["macros", "tests/no-std-test-crates/macros"] + + +[[example]] +name = "serialize_to_disk" +required-features = ["column-serialize"] diff --git a/examples/serialize_to_disk.rs b/examples/serialize_to_disk.rs index 25800e1a..d1004549 100644 --- a/examples/serialize_to_disk.rs +++ b/examples/serialize_to_disk.rs @@ -13,7 +13,7 @@ use hecs::serialize::column::{ deserialize_column, try_serialize, try_serialize_id, DeserializeContext, SerializeContext, }; use hecs::{Archetype, ColumnBatchBuilder, ColumnBatchType, World}; -use serde::{Deserialize, Serialize, Serializer}; +use serde::{Deserialize, Serialize}; use std::any::TypeId; use std::fs::File; use std::io::{BufReader, Write}; @@ -28,22 +28,22 @@ enum ComponentId { // We need to implement context types for the hecs serialization process: #[derive(Default)] -pub struct SaveContextSerialize {} +struct SaveContextSerialize {} #[derive(Default)] -pub struct SaveContextDeserialize { - pub components: Vec, +struct SaveContextDeserialize { + components: Vec, } // Components of our world. // Only Serialize and Deserialize derives are necessary. #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] -pub struct ComponentA { - pub data: usize, +struct ComponentA { + data: usize, } #[derive(Serialize, Deserialize, Eq, PartialEq, Debug, Clone)] -pub struct ComponentB { - pub some_other_data: String, +struct ComponentB { + some_other_data: String, } #[cfg(feature = "column-serialize")] @@ -121,7 +121,7 @@ impl SerializeContext for SaveContextSerialize { } } -pub fn main() { +fn main() { // initialize world: let mut world = World::new(); let input_data1 = ComponentA { data: 42 }; @@ -137,7 +137,12 @@ pub fn main() { let mut buffer: Vec = Vec::new(); let options = bincode::options(); let mut serializer = bincode::Serializer::new(&mut buffer, options); - hecs::serialize::column::serialize(&world, &mut SaveContextSerialize::default(), &mut serializer); + hecs::serialize::column::serialize( + &world, + &mut SaveContextSerialize::default(), + &mut serializer, + ) + .expect("Failed to serialize"); let path = Path::new(save_file_name); let mut file = match File::create(&path) { Err(why) => panic!("couldn't create {}: {}", path.display(), why), @@ -151,17 +156,20 @@ pub fn main() { let open = File::open(path).expect("not found!"); let reader = BufReader::new(open); let mut deserializer = bincode::Deserializer::with_reader(reader, options); - match hecs::serialize::column::deserialize(&mut SaveContextDeserialize::default(), &mut deserializer) { + match hecs::serialize::column::deserialize( + &mut SaveContextDeserialize::default(), + &mut deserializer, + ) { Ok(world) => { // we loaded world from disk successfully, let us confirm that its data is still // the same: println!("Loaded world \'{}\' from disk.", path.display()); print!("Validating world data... "); - for (e, (t)) in &mut world.query::<(&ComponentA)>() { + for (_, t) in &mut world.query::<&ComponentA>() { assert_eq!(t, &input_data1); } - for (e, (t)) in &mut world.query::<(&ComponentB)>() { + for (_, t) in &mut world.query::<&ComponentB>() { assert_eq!(t, &input_data2); } println!("Ok!"); From e96ea49dbdf1b921f340b4f5e2f62620d138a4f8 Mon Sep 17 00:00:00 2001 From: kaphula Date: Sat, 19 Oct 2024 01:31:25 +0300 Subject: [PATCH 6/7] Remove stray cfg. --- examples/serialize_to_disk.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/serialize_to_disk.rs b/examples/serialize_to_disk.rs index d1004549..75b1f85b 100644 --- a/examples/serialize_to_disk.rs +++ b/examples/serialize_to_disk.rs @@ -46,7 +46,6 @@ struct ComponentB { some_other_data: String, } -#[cfg(feature = "column-serialize")] impl DeserializeContext for SaveContextDeserialize { fn deserialize_component_ids<'de, A>(&mut self, mut seq: A) -> Result where From 87ffaea9f6dc3dc40f38a23d9aba320702203d59 Mon Sep 17 00:00:00 2001 From: kaphula Date: Sat, 19 Oct 2024 01:46:32 +0300 Subject: [PATCH 7/7] Add assert to verify world contains entities after deserialization. --- examples/serialize_to_disk.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/serialize_to_disk.rs b/examples/serialize_to_disk.rs index 75b1f85b..4107a823 100644 --- a/examples/serialize_to_disk.rs +++ b/examples/serialize_to_disk.rs @@ -163,8 +163,8 @@ fn main() { // we loaded world from disk successfully, let us confirm that its data is still // the same: println!("Loaded world \'{}\' from disk.", path.display()); - print!("Validating world data... "); + assert_eq!(world.len(), 2); for (_, t) in &mut world.query::<&ComponentA>() { assert_eq!(t, &input_data1); }