use crate::{context::Context, error::StateError, event::EventTrait};
use serde::Serialize;
use std::fmt::Debug;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use tokio::sync::RwLock;
pub type ActionFn<C, E> = Arc<
dyn Fn(Arc<RwLock<C>>, &E) -> Pin<Box<dyn Future<Output = Result<(), StateError>> + Send>>
+ Send
+ Sync,
>;
#[derive(Clone, Serialize)]
pub struct Action<C = Context, E = crate::Event> {
#[serde(skip)]
pub action_type: ActionType<C, E>,
}
impl<C, E> Debug for Action<C, E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Action")
.field("action_type", &self.action_type)
.finish()
}
}
impl<C, E> Action<C, E>
where
C: Send + Sync + 'static + Default + Clone + Debug,
E: EventTrait + Send + Sync + 'static,
{
pub fn from_fn<F, Fut>(f: F) -> Self
where
F: Fn(Arc<RwLock<C>>, &E) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<(), StateError>> + Send + 'static, {
let action_fn: ActionFn<C, E> = Arc::new(move |ctx_arc, evt| Box::pin(f(ctx_arc, evt)));
Self {
action_type: ActionType::Function(action_fn),
}
}
pub async fn execute(&self, context_arc: Arc<RwLock<C>>, event: &E) -> Result<(), StateError> {
match &self.action_type {
ActionType::Function(f) => f(context_arc, event).await,
}
}
}
#[derive(Clone, Serialize)]
pub enum ActionType<C, E> {
#[serde(skip)] Function(ActionFn<C, E>),
}
impl<C, E> Debug for ActionType<C, E> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ActionType::Function(_) => f.write_str("Function(<async_fn>)"),
}
}
}
pub trait IntoAction<C, E> {
fn into_action(self) -> Action<C, E>;
}
impl<C, E, F, Fut> IntoAction<C, E> for F
where
F: Fn(Arc<RwLock<C>>, &E) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<(), StateError>> + Send + 'static, C: Send + Sync + 'static + Default + Clone + Debug,
E: EventTrait + Send + Sync + 'static,
{
fn into_action(self) -> Action<C, E> {
Action::from_fn(self)
}
}