envision/app/update/
mod.rs1use super::command::Command;
4
5#[derive(Debug)]
10pub struct UpdateResult<S, M> {
11 pub state: Option<S>,
13
14 pub command: Command<M>,
16}
17
18impl<S, M> UpdateResult<S, M> {
19 pub fn none() -> Self {
21 Self {
22 state: None,
23 command: Command::none(),
24 }
25 }
26
27 pub fn state(state: S) -> Self {
29 Self {
30 state: Some(state),
31 command: Command::none(),
32 }
33 }
34
35 pub fn command(command: Command<M>) -> Self {
37 Self {
38 state: None,
39 command,
40 }
41 }
42
43 pub fn with(state: S, command: Command<M>) -> Self {
45 Self {
46 state: Some(state),
47 command,
48 }
49 }
50
51 pub fn and_command(mut self, command: Command<M>) -> Self {
53 self.command = self.command.and(command);
54 self
55 }
56
57 pub fn map_state<T, F>(self, f: F) -> UpdateResult<T, M>
59 where
60 F: FnOnce(S) -> T,
61 {
62 UpdateResult {
63 state: self.state.map(f),
64 command: self.command,
65 }
66 }
67
68 pub fn map_message<N, F>(self, f: F) -> UpdateResult<S, N>
70 where
71 F: Fn(M) -> N + Clone + Send + 'static,
72 M: Send + 'static,
73 N: Send + 'static,
74 {
75 UpdateResult {
76 state: self.state,
77 command: self.command.map(f),
78 }
79 }
80}
81
82impl<S, M> Default for UpdateResult<S, M> {
83 fn default() -> Self {
84 Self::none()
85 }
86}
87
88pub trait Update {
93 type State;
95
96 type Message;
98
99 fn update(&self, state: &mut Self::State, msg: Self::Message) -> Command<Self::Message>;
101}
102
103pub struct FnUpdate<S, M, F>
107where
108 F: Fn(&mut S, M) -> Command<M>,
109{
110 f: F,
111 _phantom: std::marker::PhantomData<(S, M)>,
112}
113
114impl<S, M, F> FnUpdate<S, M, F>
115where
116 F: Fn(&mut S, M) -> Command<M>,
117{
118 pub fn new(f: F) -> Self {
120 Self {
121 f,
122 _phantom: std::marker::PhantomData,
123 }
124 }
125}
126
127impl<S, M, F> Update for FnUpdate<S, M, F>
128where
129 F: Fn(&mut S, M) -> Command<M>,
130{
131 type State = S;
132 type Message = M;
133
134 fn update(&self, state: &mut S, msg: M) -> Command<M> {
135 (self.f)(state, msg)
136 }
137}
138
139pub trait StateExt: Sized {
141 fn updated(self, cmd: Command<impl Clone>) -> UpdateResult<Self, impl Clone> {
143 UpdateResult {
144 state: Some(self),
145 command: cmd,
146 }
147 }
148
149 fn unchanged(self) -> UpdateResult<Self, ()> {
151 UpdateResult {
152 state: Some(self),
153 command: Command::none(),
154 }
155 }
156}
157
158impl<T> StateExt for T {}
159
160#[cfg(test)]
161mod tests;