use crate::Checker;
pub trait Input: Sized + std::fmt::Debug + 'static {
type Raw: serde::de::DeserializeOwned + serde::Serialize;
fn tag() -> &'static str;
fn from_raw(raw: Self::Raw, checker: &mut Checker) -> anyhow::Result<Self>;
fn serialize(&self) -> anyhow::Result<serde_json::Value>;
fn example() -> Self::Raw;
}
#[derive(Clone, Copy)]
pub struct Registered<'a>(pub(crate) &'a dyn internal::DynInput);
impl Registered<'_> {
pub fn tag(&self) -> &'static str {
self.0.tag()
}
pub(crate) fn try_deserialize(
&self,
serialized: &serde_json::Value,
checker: &mut Checker,
) -> anyhow::Result<internal::Any> {
self.0.try_deserialize(serialized, checker)
}
pub fn example(&self) -> anyhow::Result<serde_json::Value> {
self.0.example()
}
}
impl std::fmt::Debug for Registered<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("input::Registered")
.field("tag", &self.tag())
.finish()
}
}
pub(crate) mod internal {
use super::*;
#[derive(Debug)]
pub(crate) struct Any {
any: Box<dyn RuntimeAny>,
}
impl Any {
pub(crate) fn new<T>(input: T) -> Self
where
T: Input,
{
Self {
any: Box::new(input),
}
}
#[must_use = "this function has no side effects"]
pub(crate) fn tag(&self) -> &'static str {
self.any.tag()
}
#[must_use = "this function has no side effects"]
pub(crate) fn downcast_ref<T>(&self) -> Option<&T>
where
T: std::any::Any,
{
self.any.as_any().downcast_ref::<T>()
}
#[must_use = "this function has no side effects"]
pub(crate) fn serialize(&self) -> anyhow::Result<serde_json::Value> {
self.any.serialize()
}
}
trait RuntimeAny: std::fmt::Debug {
fn tag(&self) -> &'static str;
fn as_any(&self) -> &dyn std::any::Any;
fn serialize(&self) -> anyhow::Result<serde_json::Value>;
}
impl<T> RuntimeAny for T
where
T: Input,
{
fn tag(&self) -> &'static str {
<Self as Input>::tag()
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn serialize(&self) -> anyhow::Result<serde_json::Value> {
<Self as Input>::serialize(self)
}
}
#[derive(Debug)]
pub(crate) struct Wrapper<T>(std::marker::PhantomData<T>);
impl<T> Wrapper<T> {
pub(crate) const INSTANCE: Self = Self::new();
pub(crate) const fn new() -> Self {
Self(std::marker::PhantomData)
}
}
impl<T> Clone for Wrapper<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Wrapper<T> {}
pub(crate) trait DynInput {
fn tag(&self) -> &'static str;
fn try_deserialize(
&self,
serialized: &serde_json::Value,
checker: &mut Checker,
) -> anyhow::Result<Any>;
fn example(&self) -> anyhow::Result<serde_json::Value>;
fn as_any(&self) -> &dyn std::any::Any;
fn type_name(&self) -> &'static str;
}
impl<T> DynInput for Wrapper<T>
where
T: Input,
{
fn tag(&self) -> &'static str {
T::tag()
}
fn try_deserialize(
&self,
serialized: &serde_json::Value,
checker: &mut Checker,
) -> anyhow::Result<Any> {
let raw = <T::Raw as serde::Deserialize<'_>>::deserialize(serialized)?;
Ok(Any::new(T::from_raw(raw, checker)?))
}
fn example(&self) -> anyhow::Result<serde_json::Value> {
Ok(serde_json::to_value(T::example())?)
}
fn as_any(&self) -> &dyn std::any::Any {
self
}
fn type_name(&self) -> &'static str {
std::any::type_name::<T>()
}
}
}