openmina_core/
substate.rs

1use redux::Dispatcher;
2
3pub type SubstateResult<T> = Result<T, String>;
4
5/// A trait for obtaining immutable and mutable references to a substate of type `T`.
6///
7/// # Example
8///
9/// ```ignore
10/// impl SubstateAccess<P2pState> for State {
11///    fn substate(&self) -> SubstateResult<&P2pState> {
12///        self.p2p
13///            .ready()
14///            .ok_or_else(|| "P2P state unavailable. P2P layer is not ready".to_owned())
15///    }
16///
17///    fn substate_mut(&mut self) -> SubstateResult<&mut P2pState> {
18///        self.p2p
19///            .ready_mut()
20///            .ok_or_else(|| "P2P state unavailable. P2P layer is not ready".to_owned())
21///    }
22///  }
23/// ```
24pub trait SubstateAccess<T> {
25    /// Attempts to obtain an immutable reference to the substate.
26    ///
27    /// In case of failure, an error `String` describing the reason is returned.
28    fn substate(&self) -> SubstateResult<&T>;
29
30    /// Attempts to obtain a mutable reference to the substate.
31    ///
32    /// In case of failure, an error `String` describing the reason is returned.
33    fn substate_mut(&mut self) -> SubstateResult<&mut T>;
34}
35
36/// Substate context which provides mutable access to a substate of type `S`, and can
37/// be consumed to obtain a [redux::Dispatcher] and a parent state of type `T`.
38pub struct Substate<'a, A, T, S> {
39    state: &'a mut T,
40    dispatcher: &'a mut Dispatcher<A, T>,
41    _marker: std::marker::PhantomData<S>,
42}
43
44impl<'a, A, T, S> Substate<'a, A, T, S>
45where
46    T: SubstateAccess<S>,
47{
48    /// Creates a new instance from a parent state and dispatcher.
49    pub fn new(state: &'a mut T, dispatcher: &'a mut Dispatcher<A, T>) -> Self {
50        Self {
51            state,
52            dispatcher,
53            _marker: Default::default(),
54        }
55    }
56
57    /// Creates a new instance from an already existing [Substate] for the same parent state.
58    pub fn from_compatible_substate<OS>(other: Substate<'a, A, T, OS>) -> Substate<'a, A, T, S> {
59        let Substate {
60            state, dispatcher, ..
61        } = other;
62
63        Self::new(state, dispatcher)
64    }
65
66    /// Obtain an immutable reference to the state.
67    ///
68    ///
69    /// WARNING: Should only be used in tests and for debugging
70    pub fn unsafe_get_state(&self) -> &T {
71        self.state
72    }
73
74    /// Attempts to obtain an immutable reference to the substate.
75    ///
76    /// In case of failure, an error `String` describing the reason is returned.
77    pub fn get_substate(&self) -> SubstateResult<&S> {
78        self.state.substate()
79    }
80
81    /// Attempts to obtain a mutable reference to the substate.
82    ///
83    /// In case of failure, an error `String` describing the reason is returned.
84    pub fn get_substate_mut(&mut self) -> SubstateResult<&mut S> {
85        self.state.substate_mut()
86    }
87
88    /// Consumes itself to produce a reference to a dispatcher and parent state.
89    pub fn into_dispatcher_and_state(self) -> (&'a mut Dispatcher<A, T>, &'a T) {
90        (self.dispatcher, self.state)
91    }
92
93    /// Consumes itself to produce a reference to a dispatcher.
94    pub fn into_dispatcher(self) -> &'a mut Dispatcher<A, T> {
95        self.dispatcher
96    }
97}
98
99/// Helper macro for the trivial substate access pattern.
100///
101/// # Example:
102///
103/// ```ignore
104/// impl_substate_access!(State, TransitionFrontierSyncState, transition_frontier.sync);
105/// ```
106#[macro_export]
107macro_rules! impl_substate_access {
108    ($state:ty, $substate_type:ty, $($substate_path:tt)*) => {
109        impl $crate::SubstateAccess<$substate_type> for $state {
110            fn substate(&self) -> $crate::SubstateResult<&$substate_type> {
111                Ok(&self.$($substate_path)*)
112            }
113
114            fn substate_mut(&mut self) -> $crate::SubstateResult<&mut $substate_type> {
115                Ok(&mut self.$($substate_path)*)
116            }
117        }
118    };
119}