intrepid_core/system/
stateful.rs

1use tower::Service;
2
3use crate::{ActionContext, Frame, FrameFuture, Handler};
4
5use super::System;
6
7/// The `Stateful` type state represents a system that has been configured with the application
8/// state that its actions require. This type state is a new type wrapper around a generic state
9/// that we don't know until the application is made, and it's the only system status which isn't
10/// a zero-sized tag marker.
11#[derive(Clone, Copy, Default)]
12pub struct Stateful<State>(pub State);
13
14/// A system which knows a state that lines up with the actions it contains. It's possible to
15/// create a stateful system from an open system, and it's possible to transition to it from
16/// a stateless system, if that system is given a handler that requires state. However, it's not
17/// possible to transition from a stateful system to a stateless system.
18pub type StatefulSystem<State> = System<Stateful<State>, State>;
19
20impl<State> StatefulSystem<State>
21where
22    State: Clone + Send + Sync + 'static,
23{
24    /// Call the system with a frame.
25    pub async fn handle_frame(self, frame: crate::Frame) -> crate::Result<Frame> {
26        match self {
27            Self::Batch(system) => system.handle_frame(frame).await,
28            Self::DispatchBatch(system) => system.handle_frame(frame).await,
29            Self::Routed(system) => system.handle_frame(frame).await,
30            Self::FirstMatch(system) => system.handle_frame(frame).await,
31        }
32    }
33}
34
35impl<State> Handler<Frame, State> for StatefulSystem<State>
36where
37    State: Clone + Send + Sync + 'static,
38{
39    type Future = FrameFuture;
40
41    fn invoke(&self, frame: impl Into<Frame>, state: State) -> Self::Future {
42        let frame = frame.into();
43        let instance = self.clone();
44
45        match instance {
46            Self::Batch(system) => system.handle_frame_with_state(frame, state),
47            Self::DispatchBatch(system) => system.handle_frame_with_state(frame, state),
48            Self::Routed(system) => system.handle_frame_with_state(frame, state),
49            Self::FirstMatch(system) => system.handle_frame_with_state(frame, state),
50        }
51    }
52
53    fn context(&self) -> ActionContext<State> {
54        match self {
55            Self::Batch(system) => system.action_context(),
56            Self::DispatchBatch(system) => system.action_context(),
57            Self::Routed(system) => system.action_context(),
58            Self::FirstMatch(system) => system.action_context(),
59        }
60    }
61}
62
63impl<State, IntoFrame> Service<IntoFrame> for StatefulSystem<State>
64where
65    State: Clone + Send + Sync + 'static,
66    IntoFrame: Into<Frame> + Clone + Send + 'static,
67{
68    type Response = Frame;
69    type Error = crate::Error;
70    type Future = FrameFuture;
71
72    fn poll_ready(
73        &mut self,
74        _: &mut std::task::Context<'_>,
75    ) -> std::task::Poll<Result<(), Self::Error>> {
76        std::task::Poll::Ready(Ok(()))
77    }
78
79    fn call(&mut self, frame: IntoFrame) -> Self::Future {
80        let state = match self {
81            Self::Batch(system) => system.state(),
82            Self::DispatchBatch(system) => system.state(),
83            Self::Routed(system) => system.state(),
84            Self::FirstMatch(system) => system.state(),
85        };
86
87        let frame: Frame = frame.into();
88        let instance = self.clone();
89
90        instance.invoke(frame, state)
91    }
92}