use std::borrow::Cow;
use std::marker::PhantomData;
use std::sync::Arc;
use async_trait::async_trait;
use entelix_core::{ExecutionContext, Result};
use serde::Serialize;
use serde::de::DeserializeOwned;
use crate::runnable::Runnable;
#[async_trait]
pub trait AnyRunnable: Send + Sync + 'static {
fn name(&self) -> Cow<'_, str> {
Cow::Borrowed("any-runnable")
}
async fn invoke_any(
&self,
input: serde_json::Value,
ctx: &ExecutionContext,
) -> Result<serde_json::Value>;
}
pub type AnyRunnableHandle = Arc<dyn AnyRunnable>;
pub fn erase<R, I, O>(runnable: R) -> AnyRunnableHandle
where
R: Runnable<I, O> + 'static,
I: DeserializeOwned + Send + 'static,
O: Serialize + Send + 'static,
{
Arc::new(ErasedRunnable {
inner: runnable,
_phantom: PhantomData,
})
}
struct ErasedRunnable<R, I, O> {
inner: R,
_phantom: PhantomData<fn(I) -> O>,
}
#[async_trait]
impl<R, I, O> AnyRunnable for ErasedRunnable<R, I, O>
where
R: Runnable<I, O> + 'static,
I: DeserializeOwned + Send + 'static,
O: Serialize + Send + 'static,
{
fn name(&self) -> Cow<'_, str> {
Runnable::name(&self.inner)
}
async fn invoke_any(
&self,
input: serde_json::Value,
ctx: &ExecutionContext,
) -> Result<serde_json::Value> {
let typed_in: I = serde_json::from_value(input)?;
let typed_out = self.inner.invoke(typed_in, ctx).await?;
Ok(serde_json::to_value(typed_out)?)
}
}