#[test]
#[rustfmt::skip]
fn recipe_ser() {
use shipyard::{Component, EntitiesViewMut, ViewMut, WorldBorrow};
#[derive(Component, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
struct Name(String);
#[derive(Component, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum FavoriteLanguage {
Rust,
}
#[derive(WorldBorrow, serde::Serialize)]
struct LanguagesViewMut<'v> {
#[serde(skip)]
entities: EntitiesViewMut<'v>,
#[serde(borrow)]
vm_name: ViewMut<'v, Name>,
#[serde(borrow)]
vm_favorite_language: ViewMut<'v, FavoriteLanguage>,
}
}
#[test]
#[rustfmt::skip]
fn recipe_de_start() {
use serde::Deserializer;
use shipyard::{Component, EntitiesViewMut, IntoIter, ViewMut, WorldBorrow};
#[derive(Component, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
struct Name(String);
#[derive(Component, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum FavoriteLanguage {
Rust,
}
#[derive(WorldBorrow, serde::Serialize)]
struct LanguagesViewMut<'v> {
#[serde(skip)]
entities: EntitiesViewMut<'v>,
#[serde(borrow)]
vm_name: ViewMut<'v, Name>,
#[serde(borrow)]
vm_favorite_language: ViewMut<'v, FavoriteLanguage>,
}
impl<'tmp, 'view, 'de: 'view> serde::Deserialize<'de> for LanguagesViewMut<'view> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
panic!("LanguagesViewMut cannot be directly deserialized. Use deserialize_in_place instead.")
}
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
struct LanguagesViewMutVisitor<'tmp, 'view> {
place: &'tmp mut LanguagesViewMut<'view>,
}
impl<'tmp, 'view, 'de: 'view> serde::de::Visitor<'de> for LanguagesViewMutVisitor<'tmp, 'view> {
type Value = ();
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a struct with vm_name and vm_favorite_language fields")
}
fn visit_map<A>(mut self, mut map: A) -> Result<(), A::Error>
where
A: serde::de::MapAccess<'de>,
{
todo!()
}
}
deserializer.deserialize_struct(
"LanguagesViewMut",
&["vm_name", "vm_favorite_language"],
LanguagesViewMutVisitor { place },
)
}
}
}
#[test]
#[rustfmt::skip]
fn recipe_de() {
use serde::Deserializer;
use shipyard::{Component, EntitiesViewMut, IntoIter, ViewMut, WorldBorrow};
#[derive(Component, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
struct Name(String);
#[derive(Component, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum FavoriteLanguage {
Rust,
}
#[derive(WorldBorrow, serde::Serialize)]
struct LanguagesViewMut<'v> {
#[serde(skip)]
entities: EntitiesViewMut<'v>,
#[serde(borrow)]
vm_name: ViewMut<'v, Name>,
#[serde(borrow)]
vm_favorite_language: ViewMut<'v, FavoriteLanguage>,
}
struct LanguagesViewMutVisitor<'tmp, 'view> {
place: &'tmp mut LanguagesViewMut<'view>,
}
impl<'tmp, 'view, 'de: 'view> serde::de::Visitor<'de> for LanguagesViewMutVisitor<'tmp, 'view> {
type Value = ();
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a struct with vm_name and vm_favorite_language fields")
}
fn visit_map<A>(mut self, mut map: A) -> Result<(), A::Error>
where
A: serde::de::MapAccess<'de>,
{
struct NameDeserializer<'tmp, 'view> {
place: &'tmp mut LanguagesViewMut<'view>,
}
impl<'tmp, 'view, 'de: 'view> serde::de::DeserializeSeed<'de> for NameDeserializer<'tmp, 'view> {
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
serde::Deserialize::deserialize_in_place(deserializer, &mut self.place.vm_name)
}
}
struct FavoriteLanguageDeserializer<'tmp, 'view> {
place: &'tmp mut LanguagesViewMut<'view>,
}
impl<'tmp, 'view, 'de: 'view> serde::de::DeserializeSeed<'de>
for FavoriteLanguageDeserializer<'tmp, 'view>
{
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
serde::Deserialize::deserialize_in_place(
deserializer,
&mut self.place.vm_favorite_language,
)
}
}
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"vm_name" => {
map.next_value_seed(NameDeserializer { place: self.place })?;
}
"vm_favorite_language" => {
map.next_value_seed(FavoriteLanguageDeserializer { place: self.place })?;
}
_ => {
map.next_value::<serde::de::IgnoredAny>()?;
}
}
}
for eid in self
.place
.vm_name
.iter()
.ids()
.chain(self.place.vm_favorite_language.iter().ids())
{
self.place.entities.spawn(eid);
}
Ok(())
}
}
}
#[test]
fn recipe_test() {
use serde::Deserializer;
use shipyard::{Component, EntitiesViewMut, IntoIter, ViewMut, World, WorldBorrow};
let mut world = World::new();
let eid1 = world.add_entity(Name("Alice".to_string()));
let eid2 = world.add_entity((Name("Bob".to_string()), FavoriteLanguage::Rust));
let serialized = world.run(|vm_favorite_language: LanguagesViewMut| {
serde_json::to_string(&vm_favorite_language).unwrap()
});
drop(world);
let mut new_world = World::new();
let mut deserializer = serde_json::Deserializer::from_str(&serialized);
new_world.deserialize::<_, LanguagesViewMut>(&mut deserializer);
new_world.run(|mut vm_favorite_language: LanguagesViewMut| {
assert!(vm_favorite_language.entities.is_alive(eid1));
assert!(vm_favorite_language.entities.is_alive(eid2));
assert_eq!(vm_favorite_language.vm_name[eid1].0, "Alice");
assert_eq!(vm_favorite_language.vm_name[eid2].0, "Bob");
assert_eq!(
vm_favorite_language.vm_favorite_language[eid2],
FavoriteLanguage::Rust
);
});
#[derive(Component, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
struct Name(String);
#[derive(Component, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum FavoriteLanguage {
Rust,
}
#[derive(WorldBorrow, serde::Serialize)]
struct LanguagesViewMut<'v> {
#[serde(skip)]
entities: EntitiesViewMut<'v>,
#[serde(borrow)]
vm_name: ViewMut<'v, Name>,
#[serde(borrow)]
vm_favorite_language: ViewMut<'v, FavoriteLanguage>,
}
impl<'tmp, 'view, 'de: 'view> serde::Deserialize<'de> for LanguagesViewMut<'view> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
panic!("LanguagesViewMut cannot be directly deserialized. Use deserialize_in_place instead.")
}
fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
struct LanguagesViewMutVisitor<'tmp, 'view> {
place: &'tmp mut LanguagesViewMut<'view>,
}
impl<'tmp, 'view, 'de: 'view> serde::de::Visitor<'de> for LanguagesViewMutVisitor<'tmp, 'view> {
type Value = ();
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a struct with vm_name and vm_favorite_language fields")
}
fn visit_map<A>(mut self, mut map: A) -> Result<(), A::Error>
where
A: serde::de::MapAccess<'de>,
{
struct NameDeserializer<'tmp, 'view> {
place: &'tmp mut LanguagesViewMut<'view>,
}
impl<'tmp, 'view, 'de: 'view> serde::de::DeserializeSeed<'de> for NameDeserializer<'tmp, 'view> {
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
serde::Deserialize::deserialize_in_place(
deserializer,
&mut self.place.vm_name,
)
}
}
struct FavoriteLanguageDeserializer<'tmp, 'view> {
place: &'tmp mut LanguagesViewMut<'view>,
}
impl<'tmp, 'view, 'de: 'view> serde::de::DeserializeSeed<'de>
for FavoriteLanguageDeserializer<'tmp, 'view>
{
type Value = ();
fn deserialize<D>(self, deserializer: D) -> Result<(), D::Error>
where
D: Deserializer<'de>,
{
serde::Deserialize::deserialize_in_place(
deserializer,
&mut self.place.vm_favorite_language,
)
}
}
while let Some(key) = map.next_key::<String>()? {
match key.as_str() {
"vm_name" => {
map.next_value_seed(NameDeserializer { place: self.place })?;
}
"vm_favorite_language" => {
map.next_value_seed(FavoriteLanguageDeserializer {
place: self.place,
})?;
}
_ => {
map.next_value::<serde::de::IgnoredAny>()?;
}
}
}
for eid in self
.place
.vm_name
.iter()
.ids()
.chain(self.place.vm_favorite_language.iter().ids())
{
self.place.entities.spawn(eid);
}
Ok(())
}
}
deserializer.deserialize_struct(
"LanguagesViewMut",
&["vm_name", "vm_favorite_language"],
LanguagesViewMutVisitor { place },
)
}
}
}