use bevy::ecs::component::Component;
use bevy::ecs::entity::Entity;
use bevy::ecs::hierarchy::Children;
use bevy::ecs::relationship::RelationshipTarget;
use bevy::ecs::world::EntityWorldMut;
use bevy_serde_lens_core::{DeUtils, ScopeUtils, SerUtils};
use serde::de::{SeqAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::fmt::{Debug, Display};
use std::{any::type_name, marker::PhantomData};
use crate::root::RootObject;
use crate::{BevyObject, BindProject, Maybe, ZstInit};
pub trait ChildrenLike: Component + Sized {
fn iter_children(&self) -> impl Iterator<Item = Entity>;
fn add_child(parent: EntityWorldMut, child: Entity) -> Result<(), impl Display>;
}
impl<T> ChildrenLike for T
where
T: RelationshipTarget,
{
fn iter_children(&self) -> impl Iterator<Item = Entity> {
T::iter(self)
}
fn add_child(mut parent: EntityWorldMut, child: Entity) -> Result<(), impl Display> {
parent.add_related::<T::Relationship>(&[child]);
Ok::<(), &'static str>(())
}
}
pub struct Child<T, C = Children>(PhantomData<(T, C)>);
impl<T, C> ZstInit for Child<T, C> {
fn init() -> Self {
Self(PhantomData)
}
}
impl<T, C> Debug for Child<T, C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Child").finish()
}
}
impl<T: BevyObject, C> BindProject for Child<T, C> {
type To = Self;
type Filter = ();
}
impl<T: BevyObject, C: ChildrenLike> Serialize for Child<T, C> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let entity = SerUtils::current_entity::<S>()?;
SerUtils::with_world::<S, _>(|world| {
let Ok(entity) = world.get_entity(entity) else {
return Err(serde::ser::Error::custom(format!(
"Entity missing {entity:?}."
)));
};
let Some(children) = entity.get::<C>() else {
return Err(serde::ser::Error::custom(format!(
"No children found for {}.",
type_name::<T>()
)));
};
for entity in children.iter_children() {
let Ok(entity) = world.get_entity(entity) else {
continue;
};
if T::filter(&entity) {
return ScopeUtils::current_entity_scope(entity.id(), || {
T::init().serialize(serializer)
});
}
}
Err(serde::ser::Error::custom(format!(
"No valid children found for {}.",
type_name::<T>()
)))
})?
}
}
impl<'de, T: BevyObject, C: ChildrenLike> Deserialize<'de> for Child<T, C> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let child = RootObject::<T>::deserialize(deserializer)?.get();
DeUtils::with_entity_mut::<D, _>(|entity| {
C::add_child(entity, child).map_err(serde::de::Error::custom)
})??;
Ok(Child(PhantomData))
}
}
impl<T, C> Default for Maybe<Child<T, C>> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<T, C> BindProject for Maybe<Child<T, C>> {
type To = Self;
type Filter = ();
}
impl<T: BevyObject, C: ChildrenLike> Serialize for Maybe<Child<T, C>> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let entity = SerUtils::current_entity::<S>()?;
SerUtils::with_world::<S, _>(|world| {
let Ok(entity) = world.get_entity(entity) else {
return Err(serde::ser::Error::custom(format!(
"Entity missing {entity:?}."
)));
};
let Some(children) = entity.get::<C>() else {
return None::<T::Object>.serialize(serializer);
};
for entity in children.iter_children() {
let Ok(entity) = world.get_entity(entity) else {
continue;
};
if T::filter(&entity) {
return ScopeUtils::current_entity_scope(entity.id(), || {
Some(T::init()).serialize(serializer)
})
.map_err(serde::ser::Error::custom);
}
}
None::<T::Object>.serialize(serializer)
})?
}
}
impl<'de, T: BevyObject, C: ChildrenLike> Deserialize<'de> for Maybe<Child<T, C>> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
<Option<Child<T, C>>>::deserialize(deserializer)?;
Ok(Self(PhantomData))
}
}
pub struct ChildVec<T, C = Children>(PhantomData<(T, C)>);
impl<T, C> Debug for ChildVec<T, C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ChildVec").finish()
}
}
impl<T, C> ZstInit for ChildVec<T, C> {
fn init() -> Self {
Self(PhantomData)
}
}
impl<T, C> Default for ChildVec<T, C> {
fn default() -> Self {
Self(PhantomData)
}
}
impl<T: BevyObject, C: ChildrenLike> Serialize for ChildVec<T, C> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeSeq;
let entity = SerUtils::current_entity::<S>()?;
SerUtils::with_world::<S, _>(|world| {
let Ok(entity) = world.get_entity(entity) else {
return Err(serde::ser::Error::custom(format!(
"Entity missing {entity:?}."
)));
};
let Some(children) = entity.get::<C>() else {
return serializer.serialize_seq(Some(0))?.end();
};
let count = children
.iter_children()
.filter_map(|e| world.get_entity(e).ok())
.filter(T::filter)
.count();
let mut seq = serializer.serialize_seq(Some(count))?;
for entity in children
.iter_children()
.filter_map(|e| world.get_entity(e).ok())
.filter(T::filter)
{
ScopeUtils::current_entity_scope(entity.id(), || {
seq.serialize_element(&T::init())
})?;
}
seq.end()
})?
}
}
impl<'de, T: BevyObject, C: ChildrenLike> Deserialize<'de> for ChildVec<T, C> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_seq(ChildVec::<T, C>(PhantomData))
}
}
impl<'de, T: BevyObject, C: ChildrenLike> Visitor<'de> for ChildVec<T, C> {
type Value = ChildVec<T, C>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a sequence of entities")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
while seq.next_element::<Child<T, C>>()?.is_some() {}
Ok(ChildVec(PhantomData))
}
}
impl<T: BevyObject, C: ChildrenLike> BindProject for ChildVec<T, C> {
type To = Self;
type Filter = ();
}