Skip to content

Commit

Permalink
Switch serialization to bincode. Apply PR fix suggestions.
Browse files Browse the repository at this point in the history
  • Loading branch information
kaphula committed Oct 18, 2024
1 parent d216379 commit c0bec92
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 111 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/target
**/*.rs.bk
Cargo.lock
.idea
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
204 changes: 95 additions & 109 deletions examples/serialize_to_disk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ComponentId>,
}
// We need to implement a context type for the hecs serialization process:
#[derive(Default)]
pub struct SaveContext {
pub components: Vec<ComponentId>,
}

// 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<ColumnBatchType, A::Error>
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::<ComponentA>();
}
ComponentId::TestComponent2 => {
batch.add::<ComponentB>();
}
#[cfg(feature = "column-serialize")]
impl DeserializeContext for SaveContext {
fn deserialize_component_ids<'de, A>(&mut self, mut seq: A) -> Result<ColumnBatchType, A::Error>
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::<ComponentA>();
}
ComponentId::ComponentB => {
batch.add::<ComponentB>();
}
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::<ComponentA, _>(entity_count, &mut seq, batch)?;
}
ComponentId::TestComponent2 => {
deserialize_column::<ComponentB, _>(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::<ComponentA, _>(entity_count, &mut seq, batch)?;
}
ComponentId::ComponentB => {
deserialize_column::<ComponentB, _>(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::<ComponentA>() || t == TypeId::of::<ComponentB>())
.count()
}
impl SerializeContext for SaveContext {
fn component_count(&self, archetype: &Archetype) -> usize {
archetype
.component_types()
.filter(|&t| t == TypeId::of::<ComponentA>() || t == TypeId::of::<ComponentB>())
.count()
}

fn serialize_component_ids<S: serde::ser::SerializeTuple>(
&mut self,
archetype: &Archetype,
mut out: S,
) -> Result<S::Ok, S::Error> {
try_serialize_id::<ComponentA, _, _>(
archetype,
&ComponentId::TestComponent1,
&mut out,
)?;
try_serialize_id::<ComponentB, _, _>(
archetype,
&ComponentId::TestComponent2,
&mut out,
)?;
out.end()
}
fn serialize_component_ids<S: serde::ser::SerializeTuple>(
&mut self,
archetype: &Archetype,
mut out: S,
) -> Result<S::Ok, S::Error> {
try_serialize_id::<ComponentA, _, _>(archetype, &ComponentId::ComponentA, &mut out)?;
try_serialize_id::<ComponentB, _, _>(archetype, &ComponentId::ComponentB, &mut out)?;
out.end()
}

fn serialize_components<S: serde::ser::SerializeTuple>(
&mut self,
archetype: &Archetype,
mut out: S,
) -> Result<S::Ok, S::Error> {
try_serialize::<ComponentA, _>(archetype, &mut out)?;
try_serialize::<ComponentB, _>(archetype, &mut out)?;
out.end()
}
fn serialize_components<S: serde::ser::SerializeTuple>(
&mut self,
archetype: &Archetype,
mut out: S,
) -> Result<S::Ok, S::Error> {
try_serialize::<ComponentA, _>(archetype, &mut out)?;
try_serialize::<ComponentB, _>(archetype, &mut out)?;
out.end()
}
}

use serialize_to_disk_example::*;
pub fn main() {
// initialize world:
let mut world = World::new();
Expand All @@ -149,21 +134,22 @@ pub fn main() {

// serialize and save our world to disk:
let mut buffer: Vec<u8> = 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
Expand Down

0 comments on commit c0bec92

Please sign in to comment.