use tower::Service;
use crate::{Action, ActionContext, Actions, Frame, FrameFuture, Handler};
use super::{Open, Stateful, Stateless};
#[derive(Clone)]
pub struct Direct<Status, State> {
actions: Actions<State>,
status: Status,
}
impl<Status, State> Direct<Status, State>
where
State: Clone + Send + Sync + 'static,
{
pub fn on_frame<ActionHandler, Args>(mut self, action: ActionHandler) -> Self
where
ActionHandler: Handler<Args, State> + Clone + Send + Sync + 'static,
Args: Clone + Send + Sync + 'static,
{
self.actions.push(Box::new(Action::new(action)));
self
}
pub fn action_context(&self) -> ActionContext<State> {
ActionContext::Unit
}
pub fn handle_frame_with_state(&self, frame: Frame, state: State) -> FrameFuture {
let mut responses = vec![];
for action in self.actions.clone().into_iter() {
responses.push(
action
.into_actionable(state.clone())
.handle_frame(frame.clone()),
);
}
FrameFuture::from_frame_futures(responses)
}
}
impl<State> Direct<Open, State> {
pub fn init() -> Self {
Direct {
status: Open,
actions: Actions::new(),
}
}
pub fn with_state(&self, state: State) -> Direct<Stateful<State>, State> {
Direct {
actions: self.actions.clone(),
status: Stateful(state),
}
}
}
impl Direct<Open, ()> {
pub fn handle_frame(self, frame: Frame) -> FrameFuture {
self.handle_frame_with_state(frame, ())
}
pub fn without_state(self) -> Direct<Stateless, ()> {
Direct {
actions: self.actions,
status: Stateless,
}
}
}
impl Direct<Stateless, ()> {
pub fn handle_frame(self, frame: Frame) -> FrameFuture {
self.handle_frame_with_state(frame, ())
}
}
impl<State> Direct<Stateful<State>, State>
where
State: Clone + Send + 'static,
{
pub fn state(&self) -> State {
self.status.0.clone()
}
pub fn handle_frame(self, frame: Frame) -> FrameFuture {
let mut responses = vec![];
for action in self.actions.clone().into_iter() {
responses.push(action.into_actionable(self.state()).call(frame.clone()));
}
FrameFuture::from_frame_futures(responses)
}
}
#[tokio::test]
async fn calling_with_a_frame_statelessly() -> Result<(), tower::BoxError> {
assert_eq!(
Direct::init()
.without_state()
.handle_frame(Frame::default())
.await?,
Frame::default()
);
assert_eq!(
Direct::init().handle_frame(Frame::default()).await?,
Frame::default()
);
Ok(())
}
#[tokio::test]
async fn calling_with_a_frame_statefully() -> Result<(), tower::BoxError> {
#[derive(Clone)]
struct ArbitraryState;
let result = Direct::init()
.with_state(ArbitraryState)
.handle_frame(Frame::default())
.await;
assert_eq!(result?, Frame::default());
Ok(())
}