use super::{
Allocator,
Location,
Slot,
};
use crate::{
archetypes::Archetypes,
entity,
registry::Registry,
};
use alloc::{
format,
vec,
vec::Vec,
};
use core::{
fmt,
marker::PhantomData,
};
use serde::{
de,
de::{
DeserializeSeed,
MapAccess,
SeqAccess,
Visitor,
},
ser::{
SerializeSeq,
SerializeStruct,
},
Deserialize,
Deserializer,
Serialize,
Serializer,
};
struct SerializeFree<'a, R>(&'a Allocator<R>)
where
R: Registry;
impl<R> Serialize for SerializeFree<'_, R>
where
R: Registry,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(self.0.free.len()))?;
for index in &self.0.free {
seq.serialize_element(&entity::Identifier {
index: *index,
generation: unsafe { self.0.slots.get_unchecked(*index) }.generation,
})?;
}
seq.end()
}
}
impl<R> Serialize for Allocator<R>
where
R: Registry,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut r#struct = serializer.serialize_struct("Allocator", 2)?;
r#struct.serialize_field("length", &self.slots.len())?;
r#struct.serialize_field("free", &SerializeFree(self))?;
r#struct.end()
}
}
#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
pub(crate) struct DeserializeAllocator<'a, R>
where
R: Registry,
{
archetypes: &'a Archetypes<R>,
}
impl<'a, R> DeserializeAllocator<'a, R>
where
R: Registry,
{
pub(crate) fn new(archetypes: &'a Archetypes<R>) -> Self {
Self { archetypes }
}
}
impl<'de, R> DeserializeSeed<'de> for DeserializeAllocator<'_, R>
where
R: Registry,
{
type Value = Allocator<R>;
fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: Deserializer<'de>,
{
enum Field {
Length,
Free,
}
impl<'de> Deserialize<'de> for Field {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct FieldVisitor;
impl<'de> Visitor<'de> for FieldVisitor {
type Value = Field;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("`length` or `free`")
}
fn visit_str<E>(self, value: &str) -> Result<Field, E>
where
E: de::Error,
{
match value {
"length" => Ok(Field::Length),
"free" => Ok(Field::Free),
_ => Err(de::Error::unknown_field(value, FIELDS)),
}
}
}
deserializer.deserialize_identifier(FieldVisitor)
}
}
struct DeserializeAllocatorVisitor<'a, R>
where
R: Registry,
{
archetypes: &'a Archetypes<R>,
}
impl<'de, R> Visitor<'de> for DeserializeAllocatorVisitor<'_, R>
where
R: Registry,
{
type Value = Allocator<R>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("serialized Allocator")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let length = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let free = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
Allocator::from_serialized_parts(length, free, self.archetypes, PhantomData)
}
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
where
V: MapAccess<'de>,
{
let mut length = None;
let mut free = None;
while let Some(key) = map.next_key()? {
match key {
Field::Length => {
if length.is_some() {
return Err(de::Error::duplicate_field("length"));
}
length = Some(map.next_value()?);
}
Field::Free => {
if free.is_some() {
return Err(de::Error::duplicate_field("free"));
}
free = Some(map.next_value()?);
}
}
}
Allocator::from_serialized_parts(
length.ok_or_else(|| de::Error::missing_field("length"))?,
free.ok_or_else(|| de::Error::missing_field("free"))?,
self.archetypes,
PhantomData,
)
}
}
const FIELDS: &[&str] = &["length", "free"];
deserializer.deserialize_struct(
"Allocator",
FIELDS,
DeserializeAllocatorVisitor {
archetypes: self.archetypes,
},
)
}
}
impl<R> Allocator<R>
where
R: Registry,
{
fn from_serialized_parts<E>(
length: usize,
free: Vec<entity::Identifier>,
archetypes: &Archetypes<R>,
_deserializer: PhantomData<E>,
) -> Result<Self, E>
where
E: de::Error,
{
let mut slots = vec![None; length];
for entity_identifier in &free {
let slot = slots.get_mut(entity_identifier.index).ok_or_else(|| {
de::Error::custom(format!(
"freed entity index {} is out of bounds",
entity_identifier.index
))
})?;
match slot {
Some(_) => Err(de::Error::custom(format!(
"duplicate freed entity index {}",
entity_identifier.index
))),
None => {
*slot = Some(Slot {
generation: entity_identifier.generation,
location: None,
});
Ok(())
}
}?;
}
for archetype in archetypes.iter() {
for (i, entity_identifier) in archetype.entity_identifiers().enumerate() {
let slot = slots.get_mut(entity_identifier.index).ok_or_else(|| {
de::Error::custom(format!(
"archetype entity index {} is out of bounds",
entity_identifier.index
))
})?;
match slot {
Some(_) => Err(de::Error::custom(format!(
"duplicate archetype entity index {}",
entity_identifier.index
))),
None => {
*slot = Some(Slot {
generation: entity_identifier.generation,
location: Some(Location {
identifier: unsafe { archetype.identifier() },
index: i,
}),
});
Ok(())
}
}?;
}
}
for (i, slot) in slots.iter().enumerate() {
if slot.is_none() {
return Err(de::Error::custom(format!("missing entity index {i}")));
}
}
Ok(Self {
slots: slots
.into_iter()
.map(|slot| {
unsafe { slot.unwrap_unchecked() }
})
.collect(),
free: free
.into_iter()
.map(|entity_identifier| entity_identifier.index)
.collect(),
})
}
}
#[cfg(test)]
mod tests {
use super::{
Allocator,
DeserializeAllocator,
Location,
};
use crate::{
archetype,
archetype::Archetype,
archetypes::Archetypes,
entity,
Registry,
};
use alloc::vec;
use claims::{
assert_err_eq,
assert_ok,
assert_ok_eq,
};
use core::fmt::Debug;
use serde::{
de::{
DeserializeSeed,
Error as _,
},
Serialize,
};
use serde_assert::{
de::Error,
ser::SerializeStructAs,
Deserializer,
Serializer,
Token,
Tokens,
};
use serde_derive::{
Deserialize,
Serialize,
};
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
struct A;
#[derive(Debug, Deserialize, Eq, PartialEq, Serialize)]
struct B;
type Registry = Registry!(A, B);
#[test]
fn serialize_deserialize_empty() {
let allocator = Allocator::new();
let serializer = Serializer::builder().build();
let tokens = assert_ok_eq!(
allocator.serialize(&serializer),
Tokens(vec![
Token::Struct {
name: "Allocator",
len: 2,
},
Token::Field("length"),
Token::U64(0),
Token::Field("free"),
Token::Seq { len: Some(0) },
Token::SeqEnd,
Token::StructEnd,
])
);
let mut deserializer = Deserializer::builder().tokens(tokens).build();
assert_ok_eq!(
DeserializeAllocator::new(&Archetypes::<Registry>::new())
.deserialize(&mut deserializer),
allocator
);
}
#[test]
fn serialize_deserialize_with_values() {
let mut allocator = Allocator::new();
let archetype_identifier = unsafe { archetype::Identifier::<Registry>::new(vec![3]) };
let entity_identifier = allocator.allocate(Location {
identifier: unsafe { archetype_identifier.as_ref() },
index: 0,
});
unsafe { allocator.free_unchecked(entity_identifier) };
allocator.allocate(Location {
identifier: unsafe { archetype_identifier.as_ref() },
index: 0,
});
allocator.allocate(Location {
identifier: unsafe { archetype_identifier.as_ref() },
index: 1,
});
let entity_identifier = allocator.allocate(Location {
identifier: unsafe { archetype_identifier.as_ref() },
index: 2,
});
unsafe { allocator.free_unchecked(entity_identifier) };
let entity_identifier = allocator.allocate(Location {
identifier: unsafe { archetype_identifier.as_ref() },
index: 2,
});
unsafe { allocator.free_unchecked(entity_identifier) };
let serializer = Serializer::builder().build();
let tokens = assert_ok_eq!(
allocator.serialize(&serializer),
Tokens(vec![
Token::Struct {
name: "Allocator",
len: 2,
},
Token::Field("length"),
Token::U64(3),
Token::Field("free"),
Token::Seq { len: Some(1) },
Token::Struct {
name: "Identifier",
len: 2,
},
Token::Field("index"),
Token::U64(2),
Token::Field("generation"),
Token::U64(1),
Token::StructEnd,
Token::SeqEnd,
Token::StructEnd,
])
);
let mut deserializer = Deserializer::builder().tokens(tokens).build();
let archetypes = {
let mut archetypes = Archetypes::<Registry>::new();
let mut allocator = Allocator::new();
let mut archetype =
Archetype::new(unsafe { archetype::Identifier::<Registry>::new(vec![3]) });
unsafe {
let entity_identifier = archetype.push(entity!(A, B), &mut allocator); archetype.remove_row_unchecked(entity_identifier.index, &mut allocator); allocator.free_unchecked(entity_identifier);
archetype.push(entity!(A, B), &mut allocator); archetype.push(entity!(A, B), &mut allocator); let entity_identifier = archetype.push(entity!(A, B), &mut allocator); archetype.remove_row_unchecked(entity_identifier.index, &mut allocator); allocator.free_unchecked(entity_identifier);
let entity_identifier = archetype.push(entity!(A, B), &mut allocator); archetype.remove_row_unchecked(entity_identifier.index, &mut allocator); allocator.free_unchecked(entity_identifier);
}
assert_ok!(archetypes.insert(archetype));
archetypes
};
assert_ok_eq!(
DeserializeAllocator::new(&archetypes).deserialize(&mut deserializer),
allocator
);
}
#[test]
fn serialize_deserialize_from_seq() {
let mut allocator = Allocator::new();
let archetype_identifier = unsafe { archetype::Identifier::<Registry>::new(vec![3]) };
let entity_identifier = allocator.allocate(Location {
identifier: unsafe { archetype_identifier.as_ref() },
index: 0,
});
unsafe { allocator.free_unchecked(entity_identifier) };
allocator.allocate(Location {
identifier: unsafe { archetype_identifier.as_ref() },
index: 0,
});
allocator.allocate(Location {
identifier: unsafe { archetype_identifier.as_ref() },
index: 1,
});
let entity_identifier = allocator.allocate(Location {
identifier: unsafe { archetype_identifier.as_ref() },
index: 2,
});
unsafe { allocator.free_unchecked(entity_identifier) };
let entity_identifier = allocator.allocate(Location {
identifier: unsafe { archetype_identifier.as_ref() },
index: 2,
});
unsafe { allocator.free_unchecked(entity_identifier) };
let serializer = Serializer::builder()
.serialize_struct_as(SerializeStructAs::Seq)
.build();
let tokens = assert_ok_eq!(
allocator.serialize(&serializer),
Tokens(vec![
Token::Seq { len: Some(2) },
Token::U64(3),
Token::Seq { len: Some(1) },
Token::Seq { len: Some(2) },
Token::U64(2),
Token::U64(1),
Token::SeqEnd,
Token::SeqEnd,
Token::SeqEnd,
])
);
let mut deserializer = Deserializer::builder().tokens(tokens).build();
let archetypes = {
let mut archetypes = Archetypes::<Registry>::new();
let mut allocator = Allocator::new();
let mut archetype =
Archetype::new(unsafe { archetype::Identifier::<Registry>::new(vec![3]) });
unsafe {
let entity_identifier = archetype.push(entity!(A, B), &mut allocator); archetype.remove_row_unchecked(entity_identifier.index, &mut allocator); allocator.free_unchecked(entity_identifier);
archetype.push(entity!(A, B), &mut allocator); archetype.push(entity!(A, B), &mut allocator); let entity_identifier = archetype.push(entity!(A, B), &mut allocator); archetype.remove_row_unchecked(entity_identifier.index, &mut allocator); allocator.free_unchecked(entity_identifier);
let entity_identifier = archetype.push(entity!(A, B), &mut allocator); archetype.remove_row_unchecked(entity_identifier.index, &mut allocator); allocator.free_unchecked(entity_identifier);
}
assert_ok!(archetypes.insert(archetype));
archetypes
};
assert_ok_eq!(
DeserializeAllocator::new(&archetypes).deserialize(&mut deserializer),
allocator
);
}
#[test]
fn deserialize_missing_field_length() {
let mut deserializer = Deserializer::builder()
.tokens(Tokens(vec![
Token::Struct {
name: "Allocator",
len: 2,
},
Token::Field("free"),
Token::Seq { len: Some(0) },
Token::SeqEnd,
Token::StructEnd,
]))
.build();
assert_err_eq!(
DeserializeAllocator::new(&Archetypes::<Registry>::new())
.deserialize(&mut deserializer),
Error::missing_field("length")
);
}
#[test]
fn deserialize_missing_field_free() {
let mut deserializer = Deserializer::builder()
.tokens(Tokens(vec![
Token::Struct {
name: "Allocator",
len: 2,
},
Token::Field("length"),
Token::U64(0),
Token::StructEnd,
]))
.build();
assert_err_eq!(
DeserializeAllocator::new(&Archetypes::<Registry>::new())
.deserialize(&mut deserializer),
Error::missing_field("free")
);
}
#[test]
fn deserialize_duplicate_field_length() {
let mut deserializer = Deserializer::builder()
.tokens(Tokens(vec![
Token::Struct {
name: "Allocator",
len: 2,
},
Token::Field("length"),
Token::U64(0),
Token::Field("free"),
Token::Seq { len: Some(0) },
Token::SeqEnd,
Token::Field("length"),
Token::U64(0),
]))
.build();
assert_err_eq!(
DeserializeAllocator::new(&Archetypes::<Registry>::new())
.deserialize(&mut deserializer),
Error::duplicate_field("length")
);
}
#[test]
fn deserialize_duplicate_field_free() {
let mut deserializer = Deserializer::builder()
.tokens(Tokens(vec![
Token::Struct {
name: "Allocator",
len: 2,
},
Token::Field("free"),
Token::Seq { len: Some(0) },
Token::SeqEnd,
Token::Field("length"),
Token::U64(0),
Token::Field("free"),
Token::Seq { len: Some(0) },
]))
.build();
assert_err_eq!(
DeserializeAllocator::new(&Archetypes::<Registry>::new())
.deserialize(&mut deserializer),
Error::duplicate_field("free")
);
}
#[test]
fn deserialize_out_of_bounds_free_index() {
let mut deserializer = Deserializer::builder()
.tokens(Tokens(vec![
Token::Struct {
name: "Allocator",
len: 2,
},
Token::Field("length"),
Token::U64(0),
Token::Field("free"),
Token::Seq { len: Some(1) },
Token::Struct {
name: "Identifier",
len: 2,
},
Token::Field("index"),
Token::U64(42),
Token::Field("generation"),
Token::U64(0),
Token::StructEnd,
Token::SeqEnd,
Token::StructEnd,
]))
.build();
assert_err_eq!(
DeserializeAllocator::new(&Archetypes::<Registry>::new())
.deserialize(&mut deserializer),
Error::custom("freed entity index 42 is out of bounds")
);
}
#[test]
fn deserialize_duplicate_free_index() {
let mut deserializer = Deserializer::builder()
.tokens(Tokens(vec![
Token::Struct {
name: "Allocator",
len: 2,
},
Token::Field("length"),
Token::U64(1),
Token::Field("free"),
Token::Seq { len: Some(2) },
Token::Struct {
name: "Identifier",
len: 2,
},
Token::Field("index"),
Token::U64(0),
Token::Field("generation"),
Token::U64(0),
Token::StructEnd,
Token::Struct {
name: "Identifier",
len: 2,
},
Token::Field("index"),
Token::U64(0),
Token::Field("generation"),
Token::U64(1),
Token::StructEnd,
Token::SeqEnd,
Token::StructEnd,
]))
.build();
assert_err_eq!(
DeserializeAllocator::new(&Archetypes::<Registry>::new())
.deserialize(&mut deserializer),
Error::custom("duplicate freed entity index 0")
);
}
#[test]
fn deserialize_out_of_bounds_archetype_index() {
let archetypes = {
let mut archetypes = Archetypes::<Registry>::new();
let mut allocator = Allocator::new();
let mut archetype =
Archetype::new(unsafe { archetype::Identifier::<Registry>::new(vec![3]) });
unsafe {
archetype.push(entity!(A, B), &mut allocator);
}
assert_ok!(archetypes.insert(archetype));
archetypes
};
let mut deserializer = Deserializer::builder()
.tokens(Tokens(vec![
Token::Struct {
name: "Allocator",
len: 2,
},
Token::Field("length"),
Token::U64(0),
Token::Field("free"),
Token::Seq { len: Some(0) },
Token::SeqEnd,
Token::StructEnd,
]))
.build();
assert_err_eq!(
DeserializeAllocator::new(&archetypes).deserialize(&mut deserializer),
Error::custom("archetype entity index 0 is out of bounds")
);
}
#[test]
fn deserialize_duplicate_archetype_index() {
let archetypes = {
let mut archetypes = Archetypes::<Registry>::new();
let mut allocator = Allocator::new();
let mut archetype =
Archetype::new(unsafe { archetype::Identifier::<Registry>::new(vec![3]) });
unsafe {
archetype.push(entity!(A, B), &mut allocator);
}
assert_ok!(archetypes.insert(archetype));
archetypes
};
let mut deserializer = Deserializer::builder()
.tokens(Tokens(vec![
Token::Struct {
name: "Allocator",
len: 2,
},
Token::Field("length"),
Token::U64(1),
Token::Field("free"),
Token::Seq { len: Some(1) },
Token::Struct {
name: "Identifier",
len: 2,
},
Token::Field("index"),
Token::U64(0),
Token::Field("generation"),
Token::U64(0),
Token::StructEnd,
Token::SeqEnd,
Token::StructEnd,
]))
.build();
assert_err_eq!(
DeserializeAllocator::new(&archetypes).deserialize(&mut deserializer),
Error::custom("duplicate archetype entity index 0")
);
}
#[test]
fn deserialize_missing_index() {
let mut deserializer = Deserializer::builder()
.tokens(Tokens(vec![
Token::Struct {
name: "Allocator",
len: 2,
},
Token::Field("length"),
Token::U64(1),
Token::Field("free"),
Token::Seq { len: Some(0) },
Token::SeqEnd,
Token::StructEnd,
]))
.build();
assert_err_eq!(
DeserializeAllocator::new(&Archetypes::<Registry>::new())
.deserialize(&mut deserializer),
Error::custom("missing entity index 0")
);
}
}