intrepid_core/system/
stateful.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
use tower::Service;

use crate::{ActionContext, Frame, FrameFuture, Handler};

use super::System;

/// The `Stateful` type state represents a system that has been configured with the application
/// state that its actions require. This type state is a new type wrapper around a generic state
/// that we don't know until the application is made, and it's the only system status which isn't
/// a zero-sized tag marker.
#[derive(Clone, Copy, Default)]
pub struct Stateful<State>(pub State);

/// A system which knows a state that lines up with the actions it contains. It's possible to
/// create a stateful system from an open system, and it's possible to transition to it from
/// a stateless system, if that system is given a handler that requires state. However, it's not
/// possible to transition from a stateful system to a stateless system.
pub type StatefulSystem<State> = System<Stateful<State>, State>;

impl<State> StatefulSystem<State>
where
    State: Clone + Send + Sync + 'static,
{
    /// Call the system with a frame.
    pub async fn handle_frame(self, frame: crate::Frame) -> crate::Result<Frame> {
        match self {
            Self::Direct(system) => system.handle_frame(frame).await,
            Self::Dispatch(system) => system.handle_frame(frame).await,
            Self::Routed(system) => system.handle_frame(frame).await,
        }
    }
}

impl<State> Handler<Frame, State> for StatefulSystem<State>
where
    State: Clone + Send + Sync + 'static,
{
    type Future = FrameFuture;

    fn invoke(&self, frame: impl Into<Frame>, state: State) -> Self::Future {
        let frame = frame.into();
        let instance = self.clone();

        match instance {
            Self::Direct(system) => system.handle_frame_with_state(frame, state),
            Self::Dispatch(system) => system.handle_frame_with_state(frame, state),
            Self::Routed(system) => system.handle_frame_with_state(frame, state),
        }
    }

    fn context(&self) -> ActionContext<State> {
        match self {
            Self::Direct(system) => system.action_context(),
            Self::Dispatch(system) => system.action_context(),
            Self::Routed(system) => system.action_context(),
        }
    }
}

impl<State, IntoFrame> Service<IntoFrame> for StatefulSystem<State>
where
    State: Clone + Send + Sync + 'static,
    IntoFrame: Into<Frame> + Clone + Send + 'static,
{
    type Response = Frame;
    type Error = crate::Error;
    type Future = FrameFuture;

    fn poll_ready(
        &mut self,
        _: &mut std::task::Context<'_>,
    ) -> std::task::Poll<Result<(), Self::Error>> {
        std::task::Poll::Ready(Ok(()))
    }

    fn call(&mut self, frame: IntoFrame) -> Self::Future {
        let state = match self {
            Self::Direct(system) => system.state(),
            Self::Dispatch(system) => system.state(),
            Self::Routed(system) => system.state(),
        };

        let frame: Frame = frame.into();
        let instance = self.clone();

        instance.invoke(frame, state)
    }
}