use std::{any::type_name, convert::Infallible, fmt, marker::PhantomData};
use anyhow::Result;
use bevy::ecs::prelude::Bundle;
use bevy::prelude::{Deref, DerefMut};
use bevy::reflect::erased_serde::__private::serde::de::DeserializeSeed;
use bevy::reflect::{serde::TypedReflectDeserializer, Reflect, Struct};
use cuicui_dsl::DslBundle;
use thiserror::Error;
use crate::parse_dsl::{MethodCtx, ParseDsl};
#[derive(Error)]
enum ReflectDslError<T> {
#[error(
"Method on `ReflectDsl` was called with not exactly one argument. \
Try having double parenthesis around the method argument"
)]
NotExactlyOneArgument,
#[error(
"Tried to set the field '{0}' of ReflectDsl<{ty}>, but {ty} \
doesn't have such a field",
ty=type_name::<T>()
)]
BadField(String),
#[error(
"The field {path} of '{ty}' is not registered. \
Please register the type '{missing}' to be able to use ReflectDsl<{ty}>.",
ty=type_name::<T>(),
)]
NotRegistered { path: String, missing: String },
#[error("Failed to deserialize ReflectDsl<{}>: {0}", type_name::<T>())]
BadDeser(anyhow::Error),
#[error("This error never happens")]
_Ignonre(PhantomData<fn(T)>, Infallible),
}
impl<T> fmt::Debug for ReflectDslError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ReflectDslError::{BadDeser, BadField, NotRegistered, _Ignonre};
match self {
BadField(field) => f.debug_tuple("BadField").field(field).finish(),
NotRegistered { path, missing } => f
.debug_struct("NotRegistered")
.field("path", path)
.field("missing", missing)
.finish(),
BadDeser(error) => f.debug_tuple("BadDeser").field(error).finish(),
Self::NotExactlyOneArgument => write!(f, "NotExactlyOneArgument"),
_Ignonre(..) => unreachable!(),
}
}
}
pub trait Format {
#[allow(clippy::missing_errors_doc)] fn deserialize(input: &[u8], de: TypedReflectDeserializer) -> Result<Box<dyn Reflect>>;
}
pub struct RonFormat;
impl Format for RonFormat {
fn deserialize(input: &[u8], de: TypedReflectDeserializer) -> Result<Box<dyn Reflect>> {
Ok(de.deserialize(&mut ron::de::Deserializer::from_bytes(input)?)?)
}
}
#[derive(Debug, Clone, Deref, DerefMut)]
pub struct ReflectDsl<T: Struct, D: DslBundle = (), F: Format = RonFormat> {
inner: Option<T>,
#[deref]
delegate_dsl: D,
_format: PhantomData<F>,
}
impl<T: Default + Struct, D: DslBundle, F: Format> Default for ReflectDsl<T, D, F> {
fn default() -> Self {
Self {
inner: Some(T::default()),
delegate_dsl: D::default(),
_format: PhantomData,
}
}
}
impl<T, D, F> DslBundle for ReflectDsl<T, D, F>
where
T: Bundle + Default + Struct,
D: DslBundle,
F: Format,
{
fn insert(&mut self, cmds: &mut cuicui_dsl::EntityCommands) {
cmds.insert(self.inner.take().unwrap());
self.delegate_dsl.insert(cmds);
}
}
impl<T, D, F> ReflectDsl<T, D, F>
where
T: Bundle + Default + Struct,
D: DslBundle,
F: Format,
{
#[allow(deprecated)]
fn typed_method(&mut self, ctx: &MethodCtx) -> Result<(), ReflectDslError<T>> {
use ReflectDslError::{BadDeser, BadField};
let inner = self.inner.as_mut().unwrap();
if ctx.arguments.len() != 1 {
return Err(ReflectDslError::NotExactlyOneArgument);
}
let argument = ctx.arguments.get(0).unwrap();
let Some(field_to_update) = inner.field_mut(ctx.name) else {
return Err(BadField(ctx.name.to_string()));
};
let id = field_to_update.type_id();
let not_registered = || ReflectDslError::NotRegistered {
path: ctx.name.to_string(),
missing: field_to_update.type_name().to_string(),
};
let registration = ctx.registry.get(id).ok_or_else(not_registered)?;
let de = TypedReflectDeserializer::new(registration, ctx.registry);
let field_value = F::deserialize(&argument, de).map_err(BadDeser)?;
field_to_update.set(field_value).unwrap();
Ok(())
}
}
impl<T, D, F> ParseDsl for ReflectDsl<T, D, F>
where
T: Bundle + Default + Struct,
D: DslBundle,
F: Format,
{
fn method(&mut self, ctx: MethodCtx) -> Result<()> {
Ok(self.typed_method(&ctx)?)
}
}