use crate::BatchSerialization;
use crate::asset::{DE_REUSABLE_HANDLES, SER_REUSABLE_HANDLES};
use crate::typetagged::TYPETAG_SERVER;
use crate::typetagged::{ErasedObject, TypeTagServer};
use bevy::app::App;
use bevy::ecs::resource::Resource;
use bevy::ecs::world::World;
use bevy::reflect::TypePath;
use bevy_serde_lens_core::ScopeUtils;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::marker::PhantomData;
use std::sync::Mutex;
#[allow(unused)]
use crate::batch;
pub trait WorldExtension {
fn save<T: BatchSerialization, S: Serializer>(
&mut self,
serializer: S,
) -> Result<S::Ok, S::Error>;
fn load<'de, T: BatchSerialization, D: Deserializer<'de>>(
&mut self,
deserializer: D,
) -> Result<(), D::Error>;
fn serialize_lens<S: BatchSerialization>(&mut self) -> SerializeLens<S>;
fn deserialize_scope<T>(&mut self, f: impl FnOnce() -> T) -> T;
fn despawn_bound_objects<T: BatchSerialization>(&mut self);
fn register_typetag<A: ErasedObject, B: Into<A> + TypePath + DeserializeOwned>(&mut self);
fn register_typetag_by_name<A: ErasedObject, B: Into<A> + DeserializeOwned>(
&mut self,
name: &str,
);
fn register_serialize_resource_cx<R: Resource>(
&mut self,
extract: impl Fn(&R, &mut dyn FnMut()) + Send + Sync + 'static,
);
fn register_deserialize_resource_cx<R: Resource>(
&mut self,
extract: impl Fn(&mut R, &mut dyn FnMut()) + Send + Sync + 'static,
);
}
impl WorldExtension for World {
fn save<T: BatchSerialization, S: Serializer>(
&mut self,
serializer: S,
) -> Result<S::Ok, S::Error> {
self.init_resource::<RegisteredExtractions>();
let mut serializer = Some(serializer);
let mut result = None;
let mut handles = Default::default();
SER_REUSABLE_HANDLES.set(&mut handles, || {
self.resource_scope::<RegisteredExtractions, _>(|world, extractions| {
(extractions.ser)(world, &mut |world| {
result = Some(T::serialize(world, serializer.take().unwrap()))
})
});
});
result.unwrap()
}
fn load<'de, T: BatchSerialization, D: Deserializer<'de>>(
&mut self,
deserializer: D,
) -> Result<(), D::Error> {
self.init_resource::<RegisteredExtractions>();
let mut deserializer = Some(deserializer);
let mut result = None;
let mut handles = Default::default();
DE_REUSABLE_HANDLES.set(&mut handles, || {
self.resource_scope::<RegisteredExtractions, _>(|world, extractions| {
(extractions.de)(world, &mut |world| {
result = Some(ScopeUtils::deserialize_scope(world, || {
T::De::deserialize(deserializer.take().unwrap())
}))
})
});
});
result.unwrap().map(|_| ())
}
fn serialize_lens<S: BatchSerialization>(&mut self) -> SerializeLens<S> {
SerializeLens(Mutex::new(self), PhantomData)
}
fn deserialize_scope<T>(&mut self, f: impl FnOnce() -> T) -> T {
self.init_resource::<RegisteredExtractions>();
let mut f = Some(f);
let mut result = None;
let mut handles = Default::default();
DE_REUSABLE_HANDLES.set(&mut handles, || {
self.resource_scope::<RegisteredExtractions, _>(|world, extractions| {
(extractions.de)(world, &mut |world| {
result = Some(ScopeUtils::deserialize_scope(world, f.take().unwrap()))
})
});
});
result.unwrap()
}
fn despawn_bound_objects<T: BatchSerialization>(&mut self) {
T::despawn(self);
self.flush();
}
fn register_typetag<A: ErasedObject, B: Into<A> + TypePath + DeserializeOwned>(&mut self) {
let mut server = self.get_resource_or_insert_with(TypeTagServer::default);
server.register::<A, B>()
}
fn register_typetag_by_name<A: ErasedObject, B: Into<A> + DeserializeOwned>(
&mut self,
name: &str,
) {
let mut server = self.get_resource_or_insert_with(TypeTagServer::default);
server.register_by_name::<A, B>(name)
}
fn register_serialize_resource_cx<R: Resource>(
&mut self,
extract: impl Fn(&R, &mut dyn FnMut()) + Send + Sync + 'static,
) {
self.init_resource::<RegisteredExtractions>();
let mut res = self.resource_mut::<RegisteredExtractions>();
res.ser = Box::new(move |world, callback| {
if world.contains_resource::<R>() {
world.resource_scope::<R, _>(|world, res| extract(&res, &mut || callback(world)))
} else {
callback(world)
}
})
}
fn register_deserialize_resource_cx<R: Resource>(
&mut self,
extract: impl Fn(&mut R, &mut dyn FnMut()) + Send + Sync + 'static,
) {
self.init_resource::<RegisteredExtractions>();
let mut res = self.resource_mut::<RegisteredExtractions>();
res.de = Box::new(move |world, callback| {
if world.contains_resource::<R>() {
world.resource_scope::<R, _>(|world, mut res| {
extract(&mut res, &mut || callback(world))
})
} else {
callback(world)
}
})
}
}
impl WorldExtension for App {
fn save<T: BatchSerialization, S: Serializer>(
&mut self,
serializer: S,
) -> Result<S::Ok, S::Error> {
self.world_mut().save::<T, S>(serializer)
}
fn load<'de, T: BatchSerialization, D: Deserializer<'de>>(
&mut self,
deserializer: D,
) -> Result<(), D::Error> {
self.world_mut().load::<T, D>(deserializer)
}
fn serialize_lens<S: BatchSerialization>(&mut self) -> SerializeLens<S> {
self.world_mut().serialize_lens()
}
fn deserialize_scope<T>(&mut self, f: impl FnOnce() -> T) -> T {
self.world_mut().deserialize_scope(f)
}
fn despawn_bound_objects<T: BatchSerialization>(&mut self) {
self.world_mut().despawn_bound_objects::<T>()
}
fn register_typetag<A: ErasedObject, B: Into<A> + TypePath + DeserializeOwned>(&mut self) {
self.world_mut().register_typetag::<A, B>()
}
fn register_typetag_by_name<A: ErasedObject, B: Into<A> + DeserializeOwned>(
&mut self,
name: &str,
) {
self.world_mut().register_typetag_by_name::<A, B>(name)
}
fn register_serialize_resource_cx<R: Resource>(
&mut self,
extract: impl Fn(&R, &mut dyn FnMut()) + Send + Sync + 'static,
) {
self.world_mut().register_serialize_resource_cx(extract);
}
fn register_deserialize_resource_cx<R: Resource>(
&mut self,
extract: impl Fn(&mut R, &mut dyn FnMut()) + Send + Sync + 'static,
) {
self.world_mut().register_deserialize_resource_cx(extract);
}
}
pub struct SerializeLens<'t, S: BatchSerialization>(Mutex<&'t mut World>, PhantomData<S>);
impl<T: BatchSerialization> Serialize for SerializeLens<'_, T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.0.lock().unwrap().save::<T, S>(serializer)
}
}
pub struct InWorld<S: BatchSerialization>(PhantomData<S>);
impl<'de, T: BatchSerialization> Deserialize<'de> for InWorld<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
T::De::deserialize(deserializer)?;
Ok(Self(PhantomData))
}
}
#[derive(Resource)]
pub struct RegisteredExtractions {
ser: Box<dyn Fn(&mut World, &mut dyn FnMut(&mut World)) + Send + Sync>,
de: Box<dyn Fn(&mut World, &mut dyn FnMut(&mut World)) + Send + Sync>,
}
impl Default for RegisteredExtractions {
fn default() -> Self {
Self {
ser: Box::new(|world, callback| callback(world)),
de: Box::new(|world, callback| {
if world.contains_resource::<TypeTagServer>() {
world.resource_scope::<TypeTagServer, _>(|world, server| {
TYPETAG_SERVER.set(&server, || callback(world))
})
} else {
callback(world)
}
}),
}
}
}