Skip to main content

local_state/
local_state.rs

1//! Per-handler local state with `Local<T>`.
2//!
3//! `Local<T>` stores state inside the handler itself, not in
4//! [`World`]. Each handler instance gets its own independent copy, initialized
5//! with `T::default()`.
6//!
7//! Use cases:
8//! - Per-handler counters (events processed, errors seen)
9//! - Per-handler buffers (batch accumulation before flush)
10//! - Per-handler cursors (tracking read position in a log)
11//!
12//! `Local<T>` does **not** need to be registered in World. It lives entirely
13//! within the handler's internal state.
14//!
15//! Run with:
16//! ```bash
17//! cargo run -p nexus-rt --example local_state
18//! ```
19
20use nexus_rt::{Handler, IntoHandler, Local, ResMut, WorldBuilder};
21
22// -- Example 1: Simple counter -----------------------------------------------
23
24/// Each invocation increments the local counter.
25/// The counter persists across `run()` calls on the same handler instance.
26fn counting_handler(mut count: Local<u64>, event: &'static str) {
27    *count += 1;
28    println!("[counter] call #{}: event = {}", *count, event);
29}
30
31// -- Example 2: Independent instances ----------------------------------------
32
33/// Two instances of the same function get independent local state.
34fn accumulator(mut sum: Local<i64>, mut total: ResMut<i64>, value: i64) {
35    *sum += value;
36    *total += value;
37    println!("[accumulator] local_sum={}, world_total={}", *sum, *total);
38}
39
40// -- Example 3: Batch buffer -------------------------------------------------
41
42/// Accumulates events locally, flushes to World every N events.
43fn batch_writer(mut buf: Local<Vec<u32>>, mut output: ResMut<Vec<u32>>, value: u32) {
44    buf.push(value);
45    if buf.len() >= 3 {
46        println!("[batch] flushing {} events to output", buf.len());
47        output.extend(buf.drain(..));
48    }
49}
50
51fn main() {
52    println!("=== Example 1: Simple counter ===\n");
53    {
54        let mut world = WorldBuilder::new().build();
55        let mut sys = counting_handler.into_handler(world.registry_mut());
56
57        sys.run(&mut world, "alpha");
58        sys.run(&mut world, "beta");
59        sys.run(&mut world, "gamma");
60    }
61
62    println!("\n=== Example 2: Independent instances ===\n");
63    {
64        let mut builder = WorldBuilder::new();
65        builder.register::<i64>(0);
66        let mut world = builder.build();
67
68        // Two handlers from the same function — each has its own Local<i64>.
69        let mut sys_a = accumulator.into_handler(world.registry_mut());
70        let mut sys_b = accumulator.into_handler(world.registry_mut());
71
72        println!("sys_a gets 10:");
73        sys_a.run(&mut world, 10i64);
74
75        println!("sys_b gets 20:");
76        sys_b.run(&mut world, 20i64);
77
78        println!("sys_a gets 5:");
79        sys_a.run(&mut world, 5i64);
80
81        // sys_a local: 15, sys_b local: 20, world total: 35
82        println!("\nWorld total: {}", world.resource::<i64>());
83        assert_eq!(*world.resource::<i64>(), 35);
84    }
85
86    println!("\n=== Example 3: Batch buffer ===\n");
87    {
88        let mut builder = WorldBuilder::new();
89        builder.register::<Vec<u32>>(Vec::new());
90        let mut world = builder.build();
91
92        let mut sys = batch_writer.into_handler(world.registry_mut());
93
94        // First two events accumulate locally.
95        sys.run(&mut world, 1u32);
96        println!("  output len: {}", world.resource::<Vec<u32>>().len());
97
98        sys.run(&mut world, 2u32);
99        println!("  output len: {}", world.resource::<Vec<u32>>().len());
100
101        // Third event triggers flush.
102        sys.run(&mut world, 3u32);
103        println!("  output len: {}", world.resource::<Vec<u32>>().len());
104
105        // Fourth event starts a new batch.
106        sys.run(&mut world, 4u32);
107        println!("  output len: {}", world.resource::<Vec<u32>>().len());
108
109        let output = world.resource::<Vec<u32>>();
110        println!("\nFinal output: {:?}", &*output);
111        assert_eq!(&*output, &[1, 2, 3]);
112    }
113
114    println!("\nDone.");
115}