use crate::error::HandlerError;
use crate::value::Value;
use std::any::Any;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
pub type HandlerReturn = Result<StepOutput, HandlerError>;
pub enum StepOutput {
State(Rc<dyn Any>),
Compared(Option<Value>),
}
impl StepOutput {
pub fn compared(&self) -> Option<&Value> {
match self {
StepOutput::Compared(v) => v.as_ref(),
StepOutput::State(_) => None,
}
}
}
pub enum StepReturn {
Ready(HandlerReturn),
Pending(Pin<Box<dyn Future<Output = HandlerReturn>>>),
}
fn value_state(state: &Rc<dyn Any>) -> Value {
state
.downcast_ref::<Value>()
.cloned()
.unwrap_or(Value::Null)
}
type HandlerFn = dyn Fn(Rc<dyn Any>, Vec<Value>) -> StepReturn;
#[derive(Clone)]
pub struct Handler {
f: Rc<HandlerFn>,
}
impl Handler {
pub fn noop() -> Handler {
Handler {
f: Rc::new(|_state, _args| StepReturn::Ready(Ok(StepOutput::Compared(None)))),
}
}
pub fn new(f: impl Fn(Rc<dyn Any>, Vec<Value>) -> HandlerReturn + 'static) -> Handler {
Handler {
f: Rc::new(move |state, args| StepReturn::Ready(f(state, args))),
}
}
pub fn sync0(f: impl Fn(Value) -> Result<Option<Value>, HandlerError> + 'static) -> Handler {
Handler::new(move |state, args| {
if !args.is_empty() {
return Err(HandlerError::new("no handler with 0 parameter(s)"));
}
Ok(StepOutput::Compared(f(value_state(&state))?))
})
}
pub fn sync1(
f: impl Fn(Value, Value) -> Result<Option<Value>, HandlerError> + 'static,
) -> Handler {
Handler::new(move |state, args| {
if args.len() != 1 {
return Err(HandlerError::new("no handler with 1 parameter(s)"));
}
Ok(StepOutput::Compared(f(value_state(&state), args[0].clone())?))
})
}
pub fn sync2(
f: impl Fn(Value, Value, Value) -> Result<Option<Value>, HandlerError> + 'static,
) -> Handler {
Handler::new(move |state, args| {
if args.len() != 2 {
return Err(HandlerError::new("no handler with 2 parameter(s)"));
}
Ok(StepOutput::Compared(f(value_state(&state), args[0].clone(), args[1].clone())?))
})
}
pub fn state1(f: impl Fn(Value, Value) -> Result<Value, HandlerError> + 'static) -> Handler {
Handler::new(move |state, args| {
if args.len() != 1 {
return Err(HandlerError::new("no handler with 1 parameter(s)"));
}
Ok(StepOutput::State(Rc::new(f(value_state(&state), args[0].clone())?)))
})
}
pub fn async0(
f: impl Fn(Value) -> Pin<Box<dyn Future<Output = HandlerReturn>>> + 'static,
) -> Handler {
Handler {
f: Rc::new(move |state, args| {
if !args.is_empty() {
return StepReturn::Ready(Err(HandlerError::new(
"no handler with 0 parameter(s)",
)));
}
StepReturn::Pending(f(value_state(&state)))
}),
}
}
pub fn sync_var(
f: impl Fn(Value, Vec<Value>) -> Result<Option<Value>, HandlerError> + 'static,
) -> Handler {
Handler::new(move |state, args| Ok(StepOutput::Compared(f(value_state(&state), args)?)))
}
pub fn async_var(
f: impl Fn(Value, Vec<Value>) -> Pin<Box<dyn Future<Output = HandlerReturn>>> + 'static,
) -> Handler {
Handler {
f: Rc::new(move |state, args| StepReturn::Pending(f(value_state(&state), args))),
}
}
pub(crate) fn call(&self, state: Rc<dyn Any>, args: Vec<Value>) -> StepReturn {
(self.f)(state, args)
}
}