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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
//! A lightweight Model-View-Update (MVU) runtime for Rust with `no_std` support.
//!
//! Implements the MVU pattern for building predictable, testable applications with
//! unidirectional data flow and controlled side effects.
//!
//! # Overview
//!
//! The Model-View-Update (MVU) pattern, also known as the Elm Architecture, structures
//! applications as a pure functional loop with three main components:
//!
//! - **Model**: Immutable state representing your entire application
//! - **Update**: Pure function that transforms `(Event, Model) → (Model, Effect)`
//! - **View**: Pure function that derives renderable Props from the Model
//!
//! This architecture makes state transitions predictable, debuggable, and testable by
//! eliminating implicit state mutation and enforcing unidirectional data flow.
//!
//! # Core Concepts
//!
//! ## Model
//!
//! The Model is an immutable data structure representing your application's complete state.
//! All behavior is a pure function of this state - nothing happens outside of it.
//!
//! ```rust
//! #[derive(Clone)]
//! struct Model {
//! counter: i32,
//! user_name: String,
//! is_loading: bool,
//! }
//! ```
//!
//! ## Event
//!
//! Events are discrete, immutable messages that trigger state transitions. They represent inputs
//! from users, systems, or asynchronous effects. Events must implement the `Clone` trait.
//!
//! ```rust
//! #[derive(Clone)]
//! enum Event {
//! UserClickedButton,
//! DataLoaded(String),
//! TimerTicked,
//! }
//! ```
//!
//! ## Effect
//!
//! Effects declaratively describe side-effecting work (async I/O, timers, etc.) that produces
//! events. They maintain purity in your update logic while enabling real-world interactions.
//!
//! Depending on your spawner implementation, effects may be processed in parallel.
//!
//! ```rust
//! # use oxide_mvu::Effect;
//! # #[derive(Clone)] enum Event { DataLoaded(String) }
//! // Describe an async operation that will emit an event
//! let effect = Effect::from_async(async move |emitter| {
//! let data = fetch_data().await;
//! emitter.emit(Event::DataLoaded(data)).await;
//! });
//! # async fn fetch_data() -> String { String::new() }
//! ```
//!
//! ## Props
//!
//! Props are a pure, derived projection of the Model optimized for rendering or external
//! presentation. They describe WHAT to render without prescribing HOW. Props commonly
//! contain data and callbacks created via [`Emitter`].
//!
//! Props are not limited to UI - they can represent any external projection (API responses,
//! hardware states, serialized output).
//!
//! # Architecture
//!
//! The MVU runtime orchestrates a unidirectional event loop:
//!
//! ```text
//! ┌──────────────────────────────────────────────────────┐
//! │ │
//! │ User Input / External Signal ◀──────────┐ │
//! │ (ie. Props callback or effect) │ │
//! │ │ │ │
//! │ ▼ │ │
//! │ ┌────────┐ │ │
//! │ │ Event │ │ │
//! │ └────┬───┘ │ │
//! │ │ // sequenced by │ │
//! │ ▼ // the runtime │ │
//! │ ┌───────────────┐ │ │
//! │ │ update(event, │ ┌───────┴─────┐ │
//! │ │ model) │ │ emit(event) │ │
//! │ └───────┬───────┘ └─────────────┘ │
//! │ │ ▲ │
//! │ ▼ │ │
//! │ ┌─────────────────────┐ │ │
//! │ │ (Model, Effect) │ │ │
//! │ └──────┬──────┬───────┘ │ │
//! │ │ │ │ │
//! │ │ └──► Effect task spawn ───┘ │
//! │ │ ▲ │
//! │ ▼ │ │
//! │ ┌─────────┐ │ │
//! │ │ Model │ │ │
//! │ └────┬────┘ │ │
//! │ │ │ │
//! │ ▼ │ │
//! │ ┌──────────────┐ │ │
//! │ │ view(model, │ ┌────────┴───────┐ │
//! │ │ emitter) │ │ props callback │ │
//! │ └──────┬───────┘ │ uses emitter │ │
//! │ │ └────────────────┘ │
//! │ ▼ ▲ │
//! │ ┌───────┐ │ │
//! │ │ Props │ // emitter captured │ │
//! │ └───┬───┘ // in Props callbacks │ │
//! │ │ │ │
//! │ ▼ │ │
//! │ ┌───────────────┐ ┌────────────┐ │
//! │ │ render(props) │ ─────────────► │ user input │ │
//! │ └───────────────┘ └────────────┘ │
//! │ │
//! └──────────────────────────────────────────────────────┘
//! ```
//!
//! # When to Use
//!
//! **MVU is ideal for:**
//! - Applications requiring predictable, debuggable state management
//! - Event-driven systems (GUIs, embedded controllers, game loops)
//! - Applications where state can be serialized/replayed (time-travel debugging)
//! - Teams prioritizing testability and clear separation of concerns
//! - `no_std` environments that can afford minimal heap allocations and meet prior criteria
//!
//! **Consider alternatives if:**
//! - You need direct object mutation for performance-critical inner loops
//! - Your application is primarily synchronous with minimal state
//!
//! # Platform Support
//!
//! ## Standard Environments
//!
//! By default, `oxide-mvu` works with the standard library.
//!
//! ```toml
//! [dependencies]
//! oxide-mvu = "0.4.2"
//! ```
//!
//! ## `no_std` Environments
//!
//! For embedded systems or environments without the standard library, enable the
//! `no_std` feature. This requires an allocator (`alloc` crate) but replaces all
//! standard library dependencies with `no_std` crates:
//!
//! ```toml
//! [dependencies]
//! oxide-mvu = { version = "0.4.2", features = ["no_std"] }
//! ```
//!
//! The runtime uses lock-free concurrency and bounded channels to minimize the cost of event
//! synchronization. This makes the framework concurrency-model agnostic. Effects may execute in
//! parallel or concurrently on the same thread as the runtime depending on hardware availability
//! and your spawner implementation.
//!
//! # Quick Start
//!
//! ```rust
//! use oxide_mvu::{Emitter, Effect, MvuLogic, MvuRuntime, Renderer};
//!
//! #[derive(Clone)]
//! enum Event {
//! AccumulateClicked,
//! }
//!
//! #[derive(Clone)]
//! struct Model {
//! count: i32,
//! }
//!
//! struct Props {
//! count: i32,
//! on_accumulate_click: Box<dyn Fn()>,
//! }
//!
//! struct MyLogic;
//!
//! impl MvuLogic<Event, Model, Props> for MyLogic {
//! fn init(&self, model: Model) -> (Model, Effect<Event>) {
//! (model, Effect::none())
//! }
//!
//! fn update(&self, event: Event, model: &Model) -> (Model, Effect<Event>) {
//! match event {
//! Event::AccumulateClicked => {
//! let new_model = Model {
//! count: model.count + 1,
//! ..model.clone()
//! };
//! (new_model, Effect::none())
//! }
//! }
//! }
//!
//! fn view(&self, model: &Model, emitter: &Emitter<Event>) -> Props {
//! let emitter = emitter.clone();
//! Props {
//! count: model.count,
//! on_accumulate_click: Box::new(move || {
//! emitter.try_emit(Event::AccumulateClicked);
//! }),
//! }
//! }
//! }
//!
//! struct MyRenderer;
//!
//! impl Renderer<Props> for MyRenderer {
//! fn render(&mut self, _props: Props) {}
//! }
//!
//! async fn main_async() {
//! // Create a spawner for your async runtime.
//! // This is how `Effect`s are executed.
//! let spawner = |fut| {
//! // Spawn the future on your chosen runtime.
//! // Examples:
//! // tokio::spawn(fut);
//! // async_std::task::spawn(fut);
//! let _ = fut;
//! };
//!
//! let runtime = MvuRuntime::builder(
//! Model { count: 0 },
//! MyLogic,
//! MyRenderer,
//! spawner,
//! ).build();
//!
//! // `run()` returns a Future representing the event loop.
//! // It must be awaited inside an async context.
//! runtime.run().await;
//! }
//! ```
//!
//! In a real application, `main_async` would be executed by your async runtime
//! (e.g. via `#[tokio::main]`, `async_std::main`, or an embedded executor).
//!
//! # Advanced Topics
//!
//! ## Effect Composition
//!
//! Multiple effects can be combined using [`Effect::batch`]:
//!
//! ```rust
//! # use oxide_mvu::Effect;
//! # #[derive(Clone)] enum Event { A, B, C }
//! let effect = Effect::batch(vec![
//! Effect::just(Event::A),
//! Effect::just(Event::B),
//! Effect::just(Event::C),
//! ]);
//! ```
//!
//! ## Event Buffer Capacity
//!
//! The runtime uses a bounded channel to queue events. The default capacity
//! ([`DEFAULT_EVENT_CAPACITY`] = 32) is sized for embedded systems with limited heap.
//! Customize this via the builder:
//!
//! ```rust,no_run
//! # use oxide_mvu::{MvuRuntime, MvuLogic, Renderer, Effect, Emitter};
//! # #[derive(Clone)] struct Model;
//! # #[derive(Clone)] enum Event {}
//! # struct Props;
//! # struct Logic;
//! # impl MvuLogic<Event, Model, Props> for Logic {
//! # fn init(&self, m: Model) -> (Model, Effect<Event>) { (m, Effect::none()) }
//! # fn update(&self, _: Event, m: &Model) -> (Model, Effect<Event>) { (m.clone(), Effect::none()) }
//! # fn view(&self, _: &Model, _: &Emitter<Event>) -> Props { Props }
//! # }
//! # struct MyRenderer;
//! # impl Renderer<Props> for MyRenderer { fn render(&mut self, _: Props) {} }
//! # let spawner = |_| {};
//! // Memory-constrained embedded systems
//! let runtime = MvuRuntime::builder(Model, Logic, MyRenderer, spawner)
//! .capacity(8)
//! .build();
//!
//! // High-throughput applications with event bursts
//! let runtime = MvuRuntime::builder(Model, Logic, MyRenderer, spawner)
//! .capacity(1024)
//! .build();
//! ```
//!
//! When the buffer is full:
//! - [`Emitter::try_emit`] returns `false` and drops the event
//! - [`Emitter::emit`] awaits until space is available (backpressure)
//!
//! ## Testing
//!
//! Enable the `testing` feature to access test utilities:
//!
//! ```toml
//! [dev-dependencies]
//! oxide-mvu = { version = "0.4.2", features = ["testing"] }
//! ```
//!
//! Test your MVU logic deterministically:
//!
//! ```rust
//! # #[cfg(feature = "testing")]
//! # {
//! use oxide_mvu::{Effect, MvuLogic, Renderer, TestMvuRuntime, create_test_spawner};
//! # #[derive(Clone)] enum Event { Increment }
//! # #[derive(Clone)] struct Model { count: i32 }
//! # struct Props;
//! # struct Logic;
//! # impl MvuLogic<Event, Model, Props> for Logic {
//! # fn init(&self, m: Model) -> (Model, Effect<Event>) { (m, Effect::none()) }
//! # fn update(&self, _: Event, m: &Model) -> (Model, Effect<Event>) {
//! # (Model { count: m.count + 1 }, Effect::none())
//! # }
//! # fn view(&self, _: &Model, _: &oxide_mvu::Emitter<Event>) -> Props { Props }
//! # }
//! # struct MyRenderer;
//! # impl Renderer<Props> for MyRenderer { fn render(&mut self, _: Props) {} }
//!
//! let runtime = TestMvuRuntime::builder(
//! Model { count: 0 },
//! Logic,
//! MyRenderer,
//! create_test_spawner()
//! ).build();
//!
//! let mut driver = runtime.run();
//! // Manually process events in tests
//! driver.process_events();
//! # }
//! ```
//!
//! See `TestMvuRuntime` (available with the `testing` feature) for comprehensive testing utilities.
//!
//! ## Async Runtime Integration
//!
//! The [`Spawner`] trait abstracts over different async runtimes. Common patterns:
//!
//! ```rust,ignore
//! // tokio
//! let spawner = |fut| { tokio::spawn(fut); };
//!
//! // async-std
//! let spawner = |fut| { async_std::task::spawn(fut); };
//!
//! // smol
//! let spawner = |fut| { smol::spawn(fut).detach(); };
//! ```
//!
//! # See Also
//!
//! - [`MvuLogic`] - The core trait defining application behavior
//! - [`Effect`] - Declarative side effect system
//! - [`Emitter`] - Event dispatch from Props callbacks
//! - [`Renderer`] - Integration point for rendering systems
//! - [`MvuRuntime`] - The runtime orchestrating the event loop
extern crate alloc;
/// Trait alias for event type constraints.
///
/// All events must implement these bounds to work with the MVU runtime.
/// Blanket implementation for any type that satisfies the bounds.
// Module declarations
// Public re-exports
pub use Effect;
pub use Emitter;
pub use MvuLogic;
pub use Renderer;
pub use ;
// Test utilities (only available with 'testing' feature or during tests)
pub use TestRenderer;
pub use ;