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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
use mpsc;
use crateCoreResult;
// Reducer and state-change contracts.
//
// Why: The engine needs a small, deterministic interface for applying updates
// that remains easy to reason about from both Rust and generated FFI surfaces.
//
// How: `Reducer` keeps mutation synchronous (for serialized updates) while
// allowing async work by pushing results back as side-effects.
/// Initialization context passed to [`Reducer::init`].
///
/// `InitContext` exists to give reducers a single place to receive all
/// runtime-provided resources they need to bootstrap background work:
///
/// - [`InitContext::sideeffect_tx`] lets reducers enqueue side-effects for
/// out-of-band processing by the engine.
/// - On Flutter targets using Flutter Rust Bridge (FRB), the `frb-spawn` feature
/// also provides a thread pool reference suitable for blocking work.
/// flutter_rust_bridge:ignore
/// Indicates whether applying an action/effect produced a new state snapshot.
/// A reducer defines how actions mutate state and how side-effects are applied.
///
/// Implementations are expected to be deterministic with respect to their inputs:
/// given the same `state` + `action`/`effect`, they should produce the same
/// resulting state and [`StateChange`].
///
/// Reducers are intentionally split into three phases:
///
/// - [`Reducer::init`]: async initialization where the reducer can spawn tasks
/// and retain cloned handles to `sideeffect_tx`.
/// - [`Reducer::reduce`]: synchronous state transitions driven by user actions.
/// - [`Reducer::effect`]: synchronous state transitions driven by background work.
///
/// Keeping `reduce`/`effect` synchronous makes update ordering easy to reason
/// about (the engine serializes all mutations behind a single mutex), while
/// still enabling async I/O by performing it in spawned tasks and sending the
/// result back as a side-effect.
///
/// ## Avoid blocking work
/// `reduce` and `effect` run under the engine's internal mutex. They must not
/// perform blocking I/O or long-running CPU work, because that would stall all
/// dispatch and side-effect processing. Perform such work in spawned tasks and
/// return results back to the engine by enqueuing a side-effect via
/// `InitContext::sideeffect_tx`.
///
/// # Threading
/// Reducers are used by [`ReducerEngine`](crate::ReducerEngine). Actions are
/// dispatched serially; you do not need to make your reducer internally
/// thread-safe beyond the trait bounds.
/// Marker trait implemented by state types that opt into sliced updates.
///
/// State types typically implement this trait via `#[state(sliced = true)]` from
/// `oxide_generator_rs`.