fj_core/layers/
layer.rs

1use std::ops::Deref;
2
3/// A generic layer, which controls access to layer state
4///
5/// `Layer` is a generic wrapper around some state and controls access to it. It
6/// [`Deref`]s to the state it wraps, for easy read access, but prevents any
7/// direct write access.
8///
9/// Instead, each write access to state is reified as a command, which are
10/// processed by [`Layer::process`]. Processing a command can result in any
11/// number of events, which can then be used as commands for other layers.
12///
13/// This design takes inspiration from, and uses the nomenclature of, this
14/// article:
15/// <https://thinkbeforecoding.com/post/2021/12/17/functional-event-sourcing-decider>
16pub struct Layer<S> {
17    state: S,
18}
19
20impl<S> Layer<S> {
21    /// Create an instance of `Layer`
22    pub fn new(state: S) -> Self {
23        Self { state }
24    }
25
26    /// Process a command
27    ///
28    /// The command is processed synchronously. When this method returns, the
29    /// state has been updated.
30    pub fn process<C>(
31        &mut self,
32        command: C,
33        events: &mut Vec<C::Event>,
34    ) -> C::Result
35    where
36        C: Command<S>,
37    {
38        let result = command.decide(&self.state, events);
39
40        for event in events {
41            event.evolve(&mut self.state);
42        }
43
44        result
45    }
46
47    /// Drop this instance, returning the wrapped state
48    pub fn into_state(self) -> S {
49        self.state
50    }
51}
52
53impl<S> Deref for Layer<S> {
54    type Target = S;
55
56    fn deref(&self) -> &Self::Target {
57        &self.state
58    }
59}
60
61impl<S> Default for Layer<S>
62where
63    S: Default,
64{
65    fn default() -> Self {
66        Self::new(S::default())
67    }
68}
69
70/// A command that encodes a request to update a layer's state
71pub trait Command<S> {
72    /// The direct result of processing a command that is returned to the caller
73    ///
74    /// Changes to the state that result from a command are encoded as events
75    /// (see [`Command::Event`]). In addition to that, a command may return
76    /// information to the caller, and `Result` defines the type of that
77    /// information.
78    type Result;
79
80    /// An event that encodes a change to the state
81    ///
82    /// Events are produced by [`Command::decide`] and processed by
83    /// [`Event::evolve`].
84    type Event: Event<S>;
85
86    /// Decide which events to produce, given the command and provided state
87    ///
88    /// If the command must result in changes to the state, any number of events
89    /// that describe these state changes can be produced.
90    fn decide(self, state: &S, events: &mut Vec<Self::Event>) -> Self::Result;
91}
92
93/// An event that encodes a change to a layer's state
94pub trait Event<S> {
95    /// Evolve the provided state
96    ///
97    /// This is the only method that [`Layer`] gives mutable access to the
98    /// state, making sure that all changes to the state are captured as events.
99    ///
100    /// Implementations of this method are supposed to be relatively dumb. Any
101    /// decisions that go into updating the state should be made in
102    /// [`Command::decide`], and encoded into the event.
103    fn evolve(&self, state: &mut S);
104}