Skip to main content

World

Struct World 

Source
pub struct World { /* private fields */ }
Expand description

Frozen singleton resource storage.

Created by WorldBuilder::build(). Resources are indexed by dense ResourceId for O(1) dispatch-time access (~3 cycles per fetch).

§Safe API

§Unsafe API (framework internals)

The low-level get / get_mut methods are unsafe — used by SystemParam::fetch for ~3-cycle dispatch. The caller must ensure no mutable aliasing.

Implementations§

Source§

impl World

Source

pub fn builder() -> WorldBuilder

Convenience constructor — returns a new WorldBuilder.

Source

pub fn registry(&self) -> &Registry

Returns a shared reference to the type registry.

Use this for read-only queries (e.g. id, contains). For construction-time calls like into_system, use registry_mut instead.

Source

pub fn registry_mut(&mut self) -> &mut Registry

Returns a mutable reference to the type registry.

Needed at construction time for into_system, into_callback, and into_stage which call Registry::check_access.

Examples found in repository?
examples/optional_resources.rs (line 84)
70fn main() {
71    println!("=== Scenario 1: All optional resources present ===\n");
72    {
73        let mut builder = WorldBuilder::new();
74        builder
75            .register(Config { threshold: 5.0 })
76            .register(DebugLog {
77                entries: Vec::new(),
78            })
79            .register(Metrics {
80                events_processed: 0,
81            });
82        let mut world = builder.build();
83
84        let mut process = process_event.into_handler(world.registry_mut());
85        let mut track = track_metrics.into_handler(world.registry_mut());
86
87        for value in [3.0, 7.5, 1.2] {
88            process.run(&mut world, value);
89            track.run(&mut world, value);
90            println!();
91        }
92
93        let log = world.resource::<DebugLog>();
94        println!("Debug log entries: {:?}", log.entries);
95
96        let metrics = world.resource::<Metrics>();
97        println!("Events processed: {}", metrics.events_processed);
98    }
99
100    println!("\n=== Scenario 2: No optional resources ===\n");
101    {
102        let mut builder = WorldBuilder::new();
103        builder.register(Config { threshold: 5.0 });
104        // DebugLog and Metrics intentionally not registered.
105        let mut world = builder.build();
106
107        let mut process = process_event.into_handler(world.registry_mut());
108        let mut track = track_metrics.into_handler(world.registry_mut());
109
110        for value in [3.0, 7.5] {
111            process.run(&mut world, value);
112            track.run(&mut world, value);
113            println!();
114        }
115
116        println!("Handlers ran cleanly without optional resources.");
117    }
118
119    println!("\nDone.");
120}
More examples
Hide additional examples
examples/perf_construction.rs (line 142)
130fn main() {
131    // Register enough types to exercise the check_access bitset.
132    let mut wb = WorldBuilder::new();
133    wb.register::<u64>(0);
134    wb.register::<u32>(0);
135    wb.register::<bool>(false);
136    wb.register::<f64>(0.0);
137    wb.register::<i64>(0);
138    wb.register::<i32>(0);
139    wb.register::<u8>(0);
140    wb.register::<u16>(0);
141    let mut world = wb.build();
142    let r = world.registry_mut();
143
144    print_header("into_handler Construction (cycles)");
145
146    bench_batched("into_handler  1-param (Res<u64>)", || {
147        let _ = black_box(sys_1p.into_handler(r));
148        0
149    });
150
151    bench_batched("into_handler  2-param (Res + ResMut)", || {
152        let _ = black_box(sys_2p.into_handler(r));
153        0
154    });
155
156    bench_batched("into_handler  4-param", || {
157        let _ = black_box(sys_4p.into_handler(r));
158        0
159    });
160
161    bench_batched("into_handler  8-param", || {
162        let _ = black_box(sys_8p.into_handler(r));
163        0
164    });
165
166    bench_batched("into_handler  2-param (Local + ResMut)", || {
167        let _ = black_box(sys_local.into_handler(r));
168        0
169    });
170
171    bench_batched("into_handler  2-param (Option<Res> + ResMut)", || {
172        let _ = black_box(sys_option.into_handler(r));
173        0
174    });
175
176    println!();
177    print_header("into_callback Construction (cycles)");
178
179    bench_batched("into_callback 2-param (Res + ResMut)", || {
180        let _ = black_box(cb_2p.into_callback(0u64, r));
181        0
182    });
183
184    bench_batched("into_callback 4-param", || {
185        let _ = black_box(cb_4p.into_callback(0u64, r));
186        0
187    });
188
189    println!();
190    print_header("into_stage Construction (cycles)");
191
192    bench_batched(".stage() 2-param (Res + ResMut)", || {
193        let _ = black_box(PipelineStart::<u32>::new().stage(stage_2p, r));
194        0
195    });
196
197    bench_batched(".stage() 4-param", || {
198        let _ = black_box(PipelineStart::<u32>::new().stage(stage_4p, r));
199        0
200    });
201
202    println!();
203}
examples/local_state.rs (line 55)
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}
examples/pipeline.rs (line 86)
80fn main() {
81    // --- Bare value pipeline: arity-0 closure stages ---
82
83    println!("=== Bare Value Pipeline ===\n");
84
85    let mut world = WorldBuilder::new().build();
86    let r = world.registry_mut();
87
88    let mut bare_pipeline = PipelineStart::<u32>::new()
89        .stage(|x: u32| x * 2, r)
90        .stage(|x: u32| x + 1, r);
91
92    println!("  5 → {}", bare_pipeline.run(&mut world, 5));
93    println!("  10 → {}", bare_pipeline.run(&mut world, 10));
94
95    // --- Option pipeline: filter + inspect (cold path), map (hot path) ---
96
97    println!("\n=== Option Pipeline ===\n");
98
99    let mut wb = WorldBuilder::new();
100    wb.register(PriceCache::new());
101    let mut world = wb.build();
102    let r = world.registry_mut();
103
104    let mut option_pipeline = PipelineStart::<MarketTick>::new()
105        .stage(
106            |tick: MarketTick| -> Option<MarketTick> {
107                if tick.price > 0.0 { Some(tick) } else { None }
108            },
109            r,
110        )
111        .filter(|_w, tick| tick.symbol == "BTC")
112        .inspect(|_w, tick| {
113            println!("  [inspect] {} @ {:.2}", tick.symbol, tick.price);
114        })
115        .map(store_price, r);
116
117    let ticks = [
118        MarketTick {
119            symbol: "BTC",
120            price: 50_000.0,
121        },
122        MarketTick {
123            symbol: "ETH",
124            price: 3_000.0,
125        }, // filtered: not BTC
126        MarketTick {
127            symbol: "BTC",
128            price: -1.0,
129        }, // filtered: negative
130        MarketTick {
131            symbol: "BTC",
132            price: 51_000.0,
133        },
134    ];
135
136    for tick in ticks {
137        option_pipeline.run(&mut world, tick);
138    }
139
140    let cache = world.resource::<PriceCache>();
141    println!(
142        "\n  PriceCache: latest={:.2}, updates={}",
143        cache.latest, cache.updates
144    );
145    assert_eq!(cache.updates, 2);
146    assert_eq!(cache.latest, 51_000.0);
147
148    // --- Result pipeline: validate → check → catch → store ---
149
150    println!("\n=== Result Pipeline with catch ===\n");
151
152    let mut wb = WorldBuilder::new();
153    wb.register(PriceCache::new());
154    wb.register::<u64>(0); // error counter
155    let mut world = wb.build();
156    let r = world.registry_mut();
157
158    let mut result_pipeline = PipelineStart::<MarketTick>::new()
159        .stage(validate, r)
160        .and_then(check_known, r)
161        .catch(count_error, r)
162        .map(store_price, r);
163
164    let ticks = [
165        MarketTick {
166            symbol: "BTC",
167            price: 52_000.0,
168        },
169        MarketTick {
170            symbol: "XYZ",
171            price: 100.0,
172        }, // unknown symbol → catch
173        MarketTick {
174            symbol: "ETH",
175            price: -5.0,
176        }, // invalid price → catch
177        MarketTick {
178            symbol: "ETH",
179            price: 3_500.0,
180        },
181    ];
182
183    for tick in ticks {
184        result_pipeline.run(&mut world, tick);
185    }
186
187    let errors = *world.resource::<u64>();
188    println!("\n  Errors: {errors}");
189    assert_eq!(errors, 2);
190
191    // --- Build into Handler ---
192
193    println!("\n=== Pipeline as Handler ===\n");
194
195    let mut wb = WorldBuilder::new();
196    wb.register::<u64>(0);
197    let mut world = wb.build();
198    let r = world.registry_mut();
199
200    let mut pipeline = PipelineStart::<u32>::new().stage(accumulate, r).build();
201
202    pipeline.run(&mut world, 10);
203    pipeline.run(&mut world, 20);
204    pipeline.run(&mut world, 30);
205
206    let total = *world.resource::<u64>();
207    println!("  Total: {total}");
208    assert_eq!(total, 60);
209
210    println!("\nDone.");
211}
examples/mock_runtime.rs (line 218)
203fn main() {
204    // -- Build ----------------------------------------------------------------
205
206    let mut wb = WorldBuilder::new();
207    wb.install_plugin(TradingPlugin {
208        initial_prices: vec![("BTC", 50_000.0), ("ETH", 3_000.0)],
209        risk_cap: 100,
210    });
211    let mut md = wb.install_driver(MarketDataInstaller);
212    let mut world = wb.build();
213
214    // Standalone handler — demonstrates change detection.
215    fn on_signal(signals: Res<SignalBuffer>, _event: ()) {
216        black_box(signals.signals.len());
217    }
218    let mut signal_handler = on_signal.into_handler(world.registry_mut());
219
220    // -- Correctness check ----------------------------------------------------
221
222    let ticks = [
223        MarketTick {
224            symbol: "BTC",
225            price: 50_100.0,
226        }, // delta=100 > 50 → signal
227        MarketTick {
228            symbol: "ETH",
229            price: 3_010.0,
230        }, // delta=10 < 50 → no signal
231        MarketTick {
232            symbol: "BTC",
233            price: 49_900.0,
234        }, // delta=200 > 50 → signal
235    ];
236
237    md.poll(&mut world, &ticks);
238
239    // 2 signals accepted, risk cap=100 so both go through.
240    assert_eq!(world.resource::<OrderCount>().0, 2);
241
242    // Change detection: SignalBuffer was modified → handler should run.
243    assert!(signal_handler.inputs_changed(&world));
244    signal_handler.run(&mut world, ());
245
246    // Advance sequence, no new writes → handler should skip.
247    world.next_sequence();
248    assert!(!signal_handler.inputs_changed(&world));
249
250    println!("Correctness checks passed.\n");
251
252    // -- Latency measurement --------------------------------------------------
253
254    const WARMUP: usize = 1_000;
255    const ITERATIONS: usize = 1_000;
256
257    // Ticks that exercise the full pipeline path (signal detection + cache write).
258    let bench_ticks = [
259        MarketTick {
260            symbol: "BTC",
261            price: 50_100.0,
262        },
263        MarketTick {
264            symbol: "ETH",
265            price: 3_100.0,
266        },
267        MarketTick {
268            symbol: "BTC",
269            price: 50_200.0,
270        },
271        MarketTick {
272            symbol: "ETH",
273            price: 3_200.0,
274        },
275    ];
276
277    println!(
278        "=== nexus-rt Dispatch Latency (cycles, {} iterations) ===\n",
279        ITERATIONS
280    );
281    println!(
282        "{:<44} {:>8} {:>8} {:>8}",
283        "Operation", "p50", "p99", "p999"
284    );
285    println!("{}", "-".repeat(72));
286
287    // Single tick through dyn pipeline
288    {
289        let tick = bench_ticks[0];
290        for _ in 0..WARMUP {
291            world.next_sequence();
292            md.pipeline.run(&mut world, black_box(tick));
293        }
294        let mut samples = Vec::with_capacity(ITERATIONS);
295        for _ in 0..ITERATIONS {
296            world.next_sequence();
297            let start = rdtsc_start();
298            md.pipeline.run(&mut world, black_box(tick));
299            let end = rdtsc_end();
300            samples.push(end.wrapping_sub(start));
301        }
302        report("single tick (dyn pipeline, 3 stages)", &mut samples);
303    }
304
305    // Standalone handler (1 param, Res<T>)
306    {
307        for _ in 0..WARMUP {
308            black_box(());
309            signal_handler.run(&mut world, ());
310        }
311        let mut samples = Vec::with_capacity(ITERATIONS);
312        for _ in 0..ITERATIONS {
313            let start = rdtsc_start();
314            black_box(());
315            signal_handler.run(&mut world, ());
316            let end = rdtsc_end();
317            samples.push(end.wrapping_sub(start));
318        }
319        report("handler dispatch (1 param, Res<T>)", &mut samples);
320    }
321
322    // 4-tick batch through driver poll
323    {
324        for _ in 0..WARMUP {
325            md.poll(&mut world, &bench_ticks);
326        }
327        let mut samples = Vec::with_capacity(ITERATIONS);
328        for _ in 0..ITERATIONS {
329            let start = rdtsc_start();
330            md.poll(&mut world, black_box(&bench_ticks));
331            let end = rdtsc_end();
332            samples.push(end.wrapping_sub(start));
333        }
334        let mut per_tick: Vec<u64> = samples
335            .iter()
336            .map(|&s| s / bench_ticks.len() as u64)
337            .collect();
338        report("4-tick poll (total)", &mut samples);
339        report("4-tick poll (per tick)", &mut per_tick);
340    }
341
342    // Change detection
343    {
344        world.next_sequence(); // ensure stale
345        for _ in 0..WARMUP {
346            black_box(signal_handler.inputs_changed(&world));
347        }
348        let mut samples = Vec::with_capacity(ITERATIONS);
349        for _ in 0..ITERATIONS {
350            let start = rdtsc_start();
351            black_box(signal_handler.inputs_changed(&world));
352            let end = rdtsc_end();
353            samples.push(end.wrapping_sub(start));
354        }
355        report("inputs_changed (1 param, stale)", &mut samples);
356    }
357
358    println!();
359}
examples/perf_pipeline.rs (line 241)
236fn main() {
237    let mut wb = WorldBuilder::new();
238    wb.register::<u64>(42);
239    wb.register::<u32>(7);
240    let mut world = wb.build();
241    let r = world.registry_mut();
242
243    // --- Bare 3-stage pipeline (no Option, no World access) ---
244
245    let mut bare = PipelineStart::<u64>::new()
246        .stage(|x: u64| x.wrapping_mul(3), r)
247        .stage(|x: u64| x.wrapping_add(7), r)
248        .stage(|x: u64| x >> 1, r);
249
250    // --- Option 3-stage pipeline ---
251
252    let mut option = PipelineStart::<u64>::new()
253        .stage(
254            |x: u64| -> Option<u64> { if x > 0 { Some(x) } else { None } },
255            r,
256        )
257        .map(|x: u64| x.wrapping_mul(3), r)
258        .filter(|_w, x| *x < 1_000_000);
259
260    // --- World-accessing pipeline (pre-resolved via Res<T>) ---
261
262    let mut world_resolved = PipelineStart::<u64>::new()
263        .stage(add_resource, r)
264        .stage(mul_resource, r);
265
266    // --- World-accessing 3-stage pipeline ---
267
268    let mut stage_3 = PipelineStart::<u64>::new()
269        .stage(add_resource, r)
270        .stage(mul_resource, r)
271        .stage(sub_resource, r);
272
273    // --- Built (boxed) pipeline ---
274
275    let mut boxed = PipelineStart::<u64>::new()
276        .stage(|x: u64| x.wrapping_mul(3), r)
277        .stage(|x: u64| x.wrapping_add(7), r)
278        .stage(|_x: u64| {}, r)
279        .build();
280
281    // --- Batch pipelines (same chains as their linear counterparts) ---
282
283    fn sink(mut acc: ResMut<u64>, x: u64) {
284        *acc = acc.wrapping_add(x);
285    }
286
287    // Bare: 3 compute stages + sink (same chain for both batch and linear)
288    let mut batch_bare = PipelineStart::<u64>::new()
289        .stage(|x: u64| x.wrapping_mul(3), r)
290        .stage(|x: u64| x.wrapping_add(7), r)
291        .stage(sink, r)
292        .build_batch(1024);
293
294    let mut linear_bare = PipelineStart::<u64>::new()
295        .stage(|x: u64| x.wrapping_mul(3), r)
296        .stage(|x: u64| x.wrapping_add(7), r)
297        .stage(sink, r);
298
299    // Res<T>: 3 world-access stages + sink (same chain for both)
300    let mut batch_res = PipelineStart::<u64>::new()
301        .stage(add_resource, r)
302        .stage(mul_resource, r)
303        .stage(sub_resource, r)
304        .stage(sink, r)
305        .build_batch(1024);
306
307    let mut linear_res = PipelineStart::<u64>::new()
308        .stage(add_resource, r)
309        .stage(mul_resource, r)
310        .stage(sub_resource, r)
311        .stage(sink, r);
312
313    // --- Result→catch→map→unwrap_or ---
314
315    let mut catch_pipeline = PipelineStart::<u64>::new()
316        .stage(
317            |x: u64| -> Result<u64, &'static str> { if x > 0 { Ok(x) } else { Err("zero") } },
318            r,
319        )
320        .catch(|_err: &'static str| {}, r)
321        .map(|x: u64| x.wrapping_mul(2), r)
322        .unwrap_or(0);
323
324    // --- Handler dispatch setup ---
325
326    let mut sys_res = handler_res_read.into_handler(world.registry_mut());
327    let mut sys_res_mut = handler_res_mut_write.into_handler(world.registry_mut());
328    let mut sys_two = handler_two_res.into_handler(world.registry_mut());
329    let mut sys_dyn: Box<dyn Handler<u64>> =
330        Box::new(handler_res_read.into_handler(world.registry_mut()));
331
332    // --- Pipeline benchmarks ---
333
334    print_header("Pipeline Dispatch Latency (cycles)");
335
336    let mut input = 1u64;
337
338    bench_batched("baseline (hand-written fn)", || {
339        input = input.wrapping_add(1);
340        baseline_handwritten(&mut world, black_box(input))
341    });
342
343    bench_batched("bare 3-stage pipe", || {
344        input = input.wrapping_add(1);
345        bare_3stage_run(&mut bare, &mut world, black_box(input))
346    });
347
348    bench_batched("option 3-stage (Some path)", || {
349        input = input.wrapping_add(1);
350        option_3stage_run(&mut option, &mut world, black_box(input + 1)).unwrap_or(0)
351    });
352
353    bench_batched("option 3-stage (None path)", || {
354        option_3stage_run(&mut option, &mut world, black_box(0)).unwrap_or(0)
355    });
356
357    bench_batched("world-access 2-stage (Res<T>)", || {
358        input = input.wrapping_add(1);
359        world_access_run(&mut world_resolved, &mut world, black_box(input))
360    });
361
362    bench_batched("boxed Pipeline (dyn dispatch)", || {
363        input = input.wrapping_add(1);
364        boxed_pipeline_run(&mut boxed, &mut world, black_box(input));
365        0
366    });
367
368    bench_batched("result→catch→map→unwrap_or", || {
369        input = input.wrapping_add(1);
370        catch_pipeline.run(&mut world, black_box(input))
371    });
372
373    // --- Handler dispatch benchmarks ---
374
375    println!();
376    print_header("Handler Dispatch Latency (cycles)");
377
378    bench_batched("Handler + Res<u64> (read)", || {
379        input = input.wrapping_add(1);
380        probe_handler_res_read(&mut sys_res, &mut world, black_box(input));
381        0
382    });
383
384    bench_batched("Handler + ResMut<u64> (write+stamp)", || {
385        input = input.wrapping_add(1);
386        probe_handler_res_mut(&mut sys_res_mut, &mut world, black_box(input));
387        0
388    });
389
390    bench_batched("Handler + 2x Res (tuple fetch)", || {
391        input = input.wrapping_add(1);
392        probe_handler_two_res(&mut sys_two, &mut world, black_box(input));
393        0
394    });
395
396    bench_batched("Box<dyn Handler> + Res<u64>", || {
397        input = input.wrapping_add(1);
398        probe_dyn_handler(&mut *sys_dyn, &mut world, black_box(input));
399        0
400    });
401
402    // --- Stage pipeline with Res<T> (3-stage) ---
403
404    println!();
405    print_header("Stage Pipeline with Res<T> (cycles)");
406
407    bench_batched("3-stage pipeline (Res<T>)", || {
408        input = input.wrapping_add(1);
409        stage_3.run(&mut world, black_box(input))
410    });
411
412    // --- Batch vs Linear throughput (total cycles for 100 items) ---
413
414    println!();
415    print_header("Batch vs Linear Throughput (total cycles, 100 items)");
416
417    let items_100: Vec<u64> = (0..100).collect();
418
419    // Batch bare: fill + run
420    {
421        for _ in 0..WARMUP {
422            batch_bare.input_mut().extend_from_slice(&items_100);
423            batch_bare.run(&mut world);
424        }
425        let mut samples = Vec::with_capacity(ITERATIONS);
426        for _ in 0..ITERATIONS {
427            batch_bare.input_mut().extend_from_slice(&items_100);
428            let start = rdtsc_start();
429            batch_bare.run(&mut world);
430            let end = rdtsc_end();
431            samples.push(end.wrapping_sub(start));
432        }
433        samples.sort_unstable();
434        println!(
435            "{:<44} {:>8} {:>8} {:>8}",
436            "batch bare (100 items)",
437            percentile(&samples, 50.0),
438            percentile(&samples, 99.0),
439            percentile(&samples, 99.9),
440        );
441    }
442
443    // Linear bare: 100 individual calls (same chain)
444    {
445        for _ in 0..WARMUP {
446            for i in 0..100u64 {
447                linear_bare.run(&mut world, black_box(i));
448            }
449        }
450        let mut samples = Vec::with_capacity(ITERATIONS);
451        for _ in 0..ITERATIONS {
452            let start = rdtsc_start();
453            for i in 0..100u64 {
454                linear_bare.run(&mut world, black_box(i));
455            }
456            let end = rdtsc_end();
457            samples.push(end.wrapping_sub(start));
458        }
459        samples.sort_unstable();
460        println!(
461            "{:<44} {:>8} {:>8} {:>8}",
462            "linear bare (100 calls)",
463            percentile(&samples, 50.0),
464            percentile(&samples, 99.0),
465            percentile(&samples, 99.9),
466        );
467    }
468
469    // Batch Res<T>: fill + run
470    {
471        for _ in 0..WARMUP {
472            batch_res.input_mut().extend_from_slice(&items_100);
473            batch_res.run(&mut world);
474        }
475        let mut samples = Vec::with_capacity(ITERATIONS);
476        for _ in 0..ITERATIONS {
477            batch_res.input_mut().extend_from_slice(&items_100);
478            let start = rdtsc_start();
479            batch_res.run(&mut world);
480            let end = rdtsc_end();
481            samples.push(end.wrapping_sub(start));
482        }
483        samples.sort_unstable();
484        println!(
485            "{:<44} {:>8} {:>8} {:>8}",
486            "batch Res<T> (100 items)",
487            percentile(&samples, 50.0),
488            percentile(&samples, 99.0),
489            percentile(&samples, 99.9),
490        );
491    }
492
493    // Linear Res<T>: 100 individual calls (same chain)
494    {
495        for _ in 0..WARMUP {
496            for i in 0..100u64 {
497                linear_res.run(&mut world, black_box(i));
498            }
499        }
500        let mut samples = Vec::with_capacity(ITERATIONS);
501        for _ in 0..ITERATIONS {
502            let start = rdtsc_start();
503            for i in 0..100u64 {
504                linear_res.run(&mut world, black_box(i));
505            }
506            let end = rdtsc_end();
507            samples.push(end.wrapping_sub(start));
508        }
509        samples.sort_unstable();
510        println!(
511            "{:<44} {:>8} {:>8} {:>8}",
512            "linear Res<T> (100 calls)",
513            percentile(&samples, 50.0),
514            percentile(&samples, 99.0),
515            percentile(&samples, 99.9),
516        );
517    }
518
519    // --- inputs_changed cost ---
520
521    println!();
522    print_header("inputs_changed Latency (cycles)");
523
524    // Build a world with enough resources for 8-param handlers.
525    let mut ic_wb = WorldBuilder::new();
526    ic_wb.register::<u64>(0);
527    ic_wb.register::<u32>(0);
528    ic_wb.register::<bool>(false);
529    ic_wb.register::<f64>(0.0);
530    ic_wb.register::<i64>(0);
531    ic_wb.register::<i32>(0);
532    ic_wb.register::<u8>(0);
533    ic_wb.register::<u16>(0);
534    let mut ic_world = ic_wb.build();
535    let ic_r = ic_world.registry_mut();
536
537    let ic1 = ic_1p.into_handler(ic_r);
538    let ic2 = ic_2p.into_handler(ic_r);
539    let ic4 = ic_4p.into_handler(ic_r);
540    let ic8 = ic_8p.into_handler(ic_r);
541
542    // Tick 0: all changed (changed_at == current_sequence).
543    bench_batched("inputs_changed 1-param (changed)", || {
544        if ic1.inputs_changed(&ic_world) { 1 } else { 0 }
545    });
546
547    bench_batched("inputs_changed 2-param (changed)", || {
548        if ic2.inputs_changed(&ic_world) { 1 } else { 0 }
549    });
550
551    bench_batched("inputs_changed 4-param (changed)", || {
552        if ic4.inputs_changed(&ic_world) { 1 } else { 0 }
553    });
554
555    bench_batched("inputs_changed 8-param (changed)", || {
556        if ic8.inputs_changed(&ic_world) { 1 } else { 0 }
557    });
558
559    // Advance tick so inputs are stale.
560    ic_world.next_sequence();
561
562    bench_batched("inputs_changed 1-param (stale)", || {
563        if ic1.inputs_changed(&ic_world) { 1 } else { 0 }
564    });
565
566    bench_batched("inputs_changed 2-param (stale)", || {
567        if ic2.inputs_changed(&ic_world) { 1 } else { 0 }
568    });
569
570    bench_batched("inputs_changed 4-param (stale)", || {
571        if ic4.inputs_changed(&ic_world) { 1 } else { 0 }
572    });
573
574    bench_batched("inputs_changed 8-param (stale)", || {
575        if ic8.inputs_changed(&ic_world) { 1 } else { 0 }
576    });
577
578    println!();
579}
Source

pub fn id<T: 'static>(&self) -> ResourceId

Resolve the ResourceId for a type. Cold path — uses HashMap lookup.

§Panics

Panics if the resource type was not registered.

Source

pub fn try_id<T: 'static>(&self) -> Option<ResourceId>

Try to resolve the ResourceId for a type. Returns None if the type was not registered.

Source

pub fn len(&self) -> usize

Returns the number of registered resources.

Source

pub fn is_empty(&self) -> bool

Returns true if no resources are stored.

Source

pub fn contains<T: 'static>(&self) -> bool

Returns true if a resource of type T is stored.

Source

pub fn resource<T: 'static>(&self) -> &T

Safe shared access to a resource. Cold path — resolves via HashMap.

Takes &self — multiple shared references can coexist. The borrow checker prevents mixing with resource_mut (which takes &mut self).

§Panics

Panics if the resource type was not registered.

Examples found in repository?
examples/optional_resources.rs (line 93)
70fn main() {
71    println!("=== Scenario 1: All optional resources present ===\n");
72    {
73        let mut builder = WorldBuilder::new();
74        builder
75            .register(Config { threshold: 5.0 })
76            .register(DebugLog {
77                entries: Vec::new(),
78            })
79            .register(Metrics {
80                events_processed: 0,
81            });
82        let mut world = builder.build();
83
84        let mut process = process_event.into_handler(world.registry_mut());
85        let mut track = track_metrics.into_handler(world.registry_mut());
86
87        for value in [3.0, 7.5, 1.2] {
88            process.run(&mut world, value);
89            track.run(&mut world, value);
90            println!();
91        }
92
93        let log = world.resource::<DebugLog>();
94        println!("Debug log entries: {:?}", log.entries);
95
96        let metrics = world.resource::<Metrics>();
97        println!("Events processed: {}", metrics.events_processed);
98    }
99
100    println!("\n=== Scenario 2: No optional resources ===\n");
101    {
102        let mut builder = WorldBuilder::new();
103        builder.register(Config { threshold: 5.0 });
104        // DebugLog and Metrics intentionally not registered.
105        let mut world = builder.build();
106
107        let mut process = process_event.into_handler(world.registry_mut());
108        let mut track = track_metrics.into_handler(world.registry_mut());
109
110        for value in [3.0, 7.5] {
111            process.run(&mut world, value);
112            track.run(&mut world, value);
113            println!();
114        }
115
116        println!("Handlers ran cleanly without optional resources.");
117    }
118
119    println!("\nDone.");
120}
More examples
Hide additional examples
examples/local_state.rs (line 82)
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}
examples/pipeline.rs (line 140)
80fn main() {
81    // --- Bare value pipeline: arity-0 closure stages ---
82
83    println!("=== Bare Value Pipeline ===\n");
84
85    let mut world = WorldBuilder::new().build();
86    let r = world.registry_mut();
87
88    let mut bare_pipeline = PipelineStart::<u32>::new()
89        .stage(|x: u32| x * 2, r)
90        .stage(|x: u32| x + 1, r);
91
92    println!("  5 → {}", bare_pipeline.run(&mut world, 5));
93    println!("  10 → {}", bare_pipeline.run(&mut world, 10));
94
95    // --- Option pipeline: filter + inspect (cold path), map (hot path) ---
96
97    println!("\n=== Option Pipeline ===\n");
98
99    let mut wb = WorldBuilder::new();
100    wb.register(PriceCache::new());
101    let mut world = wb.build();
102    let r = world.registry_mut();
103
104    let mut option_pipeline = PipelineStart::<MarketTick>::new()
105        .stage(
106            |tick: MarketTick| -> Option<MarketTick> {
107                if tick.price > 0.0 { Some(tick) } else { None }
108            },
109            r,
110        )
111        .filter(|_w, tick| tick.symbol == "BTC")
112        .inspect(|_w, tick| {
113            println!("  [inspect] {} @ {:.2}", tick.symbol, tick.price);
114        })
115        .map(store_price, r);
116
117    let ticks = [
118        MarketTick {
119            symbol: "BTC",
120            price: 50_000.0,
121        },
122        MarketTick {
123            symbol: "ETH",
124            price: 3_000.0,
125        }, // filtered: not BTC
126        MarketTick {
127            symbol: "BTC",
128            price: -1.0,
129        }, // filtered: negative
130        MarketTick {
131            symbol: "BTC",
132            price: 51_000.0,
133        },
134    ];
135
136    for tick in ticks {
137        option_pipeline.run(&mut world, tick);
138    }
139
140    let cache = world.resource::<PriceCache>();
141    println!(
142        "\n  PriceCache: latest={:.2}, updates={}",
143        cache.latest, cache.updates
144    );
145    assert_eq!(cache.updates, 2);
146    assert_eq!(cache.latest, 51_000.0);
147
148    // --- Result pipeline: validate → check → catch → store ---
149
150    println!("\n=== Result Pipeline with catch ===\n");
151
152    let mut wb = WorldBuilder::new();
153    wb.register(PriceCache::new());
154    wb.register::<u64>(0); // error counter
155    let mut world = wb.build();
156    let r = world.registry_mut();
157
158    let mut result_pipeline = PipelineStart::<MarketTick>::new()
159        .stage(validate, r)
160        .and_then(check_known, r)
161        .catch(count_error, r)
162        .map(store_price, r);
163
164    let ticks = [
165        MarketTick {
166            symbol: "BTC",
167            price: 52_000.0,
168        },
169        MarketTick {
170            symbol: "XYZ",
171            price: 100.0,
172        }, // unknown symbol → catch
173        MarketTick {
174            symbol: "ETH",
175            price: -5.0,
176        }, // invalid price → catch
177        MarketTick {
178            symbol: "ETH",
179            price: 3_500.0,
180        },
181    ];
182
183    for tick in ticks {
184        result_pipeline.run(&mut world, tick);
185    }
186
187    let errors = *world.resource::<u64>();
188    println!("\n  Errors: {errors}");
189    assert_eq!(errors, 2);
190
191    // --- Build into Handler ---
192
193    println!("\n=== Pipeline as Handler ===\n");
194
195    let mut wb = WorldBuilder::new();
196    wb.register::<u64>(0);
197    let mut world = wb.build();
198    let r = world.registry_mut();
199
200    let mut pipeline = PipelineStart::<u32>::new().stage(accumulate, r).build();
201
202    pipeline.run(&mut world, 10);
203    pipeline.run(&mut world, 20);
204    pipeline.run(&mut world, 30);
205
206    let total = *world.resource::<u64>();
207    println!("  Total: {total}");
208    assert_eq!(total, 60);
209
210    println!("\nDone.");
211}
examples/mock_runtime.rs (line 240)
203fn main() {
204    // -- Build ----------------------------------------------------------------
205
206    let mut wb = WorldBuilder::new();
207    wb.install_plugin(TradingPlugin {
208        initial_prices: vec![("BTC", 50_000.0), ("ETH", 3_000.0)],
209        risk_cap: 100,
210    });
211    let mut md = wb.install_driver(MarketDataInstaller);
212    let mut world = wb.build();
213
214    // Standalone handler — demonstrates change detection.
215    fn on_signal(signals: Res<SignalBuffer>, _event: ()) {
216        black_box(signals.signals.len());
217    }
218    let mut signal_handler = on_signal.into_handler(world.registry_mut());
219
220    // -- Correctness check ----------------------------------------------------
221
222    let ticks = [
223        MarketTick {
224            symbol: "BTC",
225            price: 50_100.0,
226        }, // delta=100 > 50 → signal
227        MarketTick {
228            symbol: "ETH",
229            price: 3_010.0,
230        }, // delta=10 < 50 → no signal
231        MarketTick {
232            symbol: "BTC",
233            price: 49_900.0,
234        }, // delta=200 > 50 → signal
235    ];
236
237    md.poll(&mut world, &ticks);
238
239    // 2 signals accepted, risk cap=100 so both go through.
240    assert_eq!(world.resource::<OrderCount>().0, 2);
241
242    // Change detection: SignalBuffer was modified → handler should run.
243    assert!(signal_handler.inputs_changed(&world));
244    signal_handler.run(&mut world, ());
245
246    // Advance sequence, no new writes → handler should skip.
247    world.next_sequence();
248    assert!(!signal_handler.inputs_changed(&world));
249
250    println!("Correctness checks passed.\n");
251
252    // -- Latency measurement --------------------------------------------------
253
254    const WARMUP: usize = 1_000;
255    const ITERATIONS: usize = 1_000;
256
257    // Ticks that exercise the full pipeline path (signal detection + cache write).
258    let bench_ticks = [
259        MarketTick {
260            symbol: "BTC",
261            price: 50_100.0,
262        },
263        MarketTick {
264            symbol: "ETH",
265            price: 3_100.0,
266        },
267        MarketTick {
268            symbol: "BTC",
269            price: 50_200.0,
270        },
271        MarketTick {
272            symbol: "ETH",
273            price: 3_200.0,
274        },
275    ];
276
277    println!(
278        "=== nexus-rt Dispatch Latency (cycles, {} iterations) ===\n",
279        ITERATIONS
280    );
281    println!(
282        "{:<44} {:>8} {:>8} {:>8}",
283        "Operation", "p50", "p99", "p999"
284    );
285    println!("{}", "-".repeat(72));
286
287    // Single tick through dyn pipeline
288    {
289        let tick = bench_ticks[0];
290        for _ in 0..WARMUP {
291            world.next_sequence();
292            md.pipeline.run(&mut world, black_box(tick));
293        }
294        let mut samples = Vec::with_capacity(ITERATIONS);
295        for _ in 0..ITERATIONS {
296            world.next_sequence();
297            let start = rdtsc_start();
298            md.pipeline.run(&mut world, black_box(tick));
299            let end = rdtsc_end();
300            samples.push(end.wrapping_sub(start));
301        }
302        report("single tick (dyn pipeline, 3 stages)", &mut samples);
303    }
304
305    // Standalone handler (1 param, Res<T>)
306    {
307        for _ in 0..WARMUP {
308            black_box(());
309            signal_handler.run(&mut world, ());
310        }
311        let mut samples = Vec::with_capacity(ITERATIONS);
312        for _ in 0..ITERATIONS {
313            let start = rdtsc_start();
314            black_box(());
315            signal_handler.run(&mut world, ());
316            let end = rdtsc_end();
317            samples.push(end.wrapping_sub(start));
318        }
319        report("handler dispatch (1 param, Res<T>)", &mut samples);
320    }
321
322    // 4-tick batch through driver poll
323    {
324        for _ in 0..WARMUP {
325            md.poll(&mut world, &bench_ticks);
326        }
327        let mut samples = Vec::with_capacity(ITERATIONS);
328        for _ in 0..ITERATIONS {
329            let start = rdtsc_start();
330            md.poll(&mut world, black_box(&bench_ticks));
331            let end = rdtsc_end();
332            samples.push(end.wrapping_sub(start));
333        }
334        let mut per_tick: Vec<u64> = samples
335            .iter()
336            .map(|&s| s / bench_ticks.len() as u64)
337            .collect();
338        report("4-tick poll (total)", &mut samples);
339        report("4-tick poll (per tick)", &mut per_tick);
340    }
341
342    // Change detection
343    {
344        world.next_sequence(); // ensure stale
345        for _ in 0..WARMUP {
346            black_box(signal_handler.inputs_changed(&world));
347        }
348        let mut samples = Vec::with_capacity(ITERATIONS);
349        for _ in 0..ITERATIONS {
350            let start = rdtsc_start();
351            black_box(signal_handler.inputs_changed(&world));
352            let end = rdtsc_end();
353            samples.push(end.wrapping_sub(start));
354        }
355        report("inputs_changed (1 param, stale)", &mut samples);
356    }
357
358    println!();
359}
Source

pub fn resource_mut<T: 'static>(&mut self) -> &mut T

Safe exclusive access to a resource. Cold path — resolves via HashMap.

§Panics

Panics if the resource type was not registered.

Source

pub fn current_sequence(&self) -> Sequence

Returns the current event sequence number.

Source

pub fn next_sequence(&mut self) -> Sequence

Advance to the next event sequence number and return it.

Drivers call this before dispatching each event. The returned sequence number identifies the event being processed. Resources mutated during dispatch will record this sequence in changed_at.

Examples found in repository?
examples/mock_runtime.rs (line 194)
190    fn poll(&mut self, world: &mut World, ticks: &[MarketTick]) {
191        if ticks.is_empty() {
192            return;
193        }
194        world.next_sequence();
195        for tick in ticks {
196            self.pipeline.run(world, *tick);
197        }
198    }
199}
200
201// ── main ────────────────────────────────────────────────────────────────
202
203fn main() {
204    // -- Build ----------------------------------------------------------------
205
206    let mut wb = WorldBuilder::new();
207    wb.install_plugin(TradingPlugin {
208        initial_prices: vec![("BTC", 50_000.0), ("ETH", 3_000.0)],
209        risk_cap: 100,
210    });
211    let mut md = wb.install_driver(MarketDataInstaller);
212    let mut world = wb.build();
213
214    // Standalone handler — demonstrates change detection.
215    fn on_signal(signals: Res<SignalBuffer>, _event: ()) {
216        black_box(signals.signals.len());
217    }
218    let mut signal_handler = on_signal.into_handler(world.registry_mut());
219
220    // -- Correctness check ----------------------------------------------------
221
222    let ticks = [
223        MarketTick {
224            symbol: "BTC",
225            price: 50_100.0,
226        }, // delta=100 > 50 → signal
227        MarketTick {
228            symbol: "ETH",
229            price: 3_010.0,
230        }, // delta=10 < 50 → no signal
231        MarketTick {
232            symbol: "BTC",
233            price: 49_900.0,
234        }, // delta=200 > 50 → signal
235    ];
236
237    md.poll(&mut world, &ticks);
238
239    // 2 signals accepted, risk cap=100 so both go through.
240    assert_eq!(world.resource::<OrderCount>().0, 2);
241
242    // Change detection: SignalBuffer was modified → handler should run.
243    assert!(signal_handler.inputs_changed(&world));
244    signal_handler.run(&mut world, ());
245
246    // Advance sequence, no new writes → handler should skip.
247    world.next_sequence();
248    assert!(!signal_handler.inputs_changed(&world));
249
250    println!("Correctness checks passed.\n");
251
252    // -- Latency measurement --------------------------------------------------
253
254    const WARMUP: usize = 1_000;
255    const ITERATIONS: usize = 1_000;
256
257    // Ticks that exercise the full pipeline path (signal detection + cache write).
258    let bench_ticks = [
259        MarketTick {
260            symbol: "BTC",
261            price: 50_100.0,
262        },
263        MarketTick {
264            symbol: "ETH",
265            price: 3_100.0,
266        },
267        MarketTick {
268            symbol: "BTC",
269            price: 50_200.0,
270        },
271        MarketTick {
272            symbol: "ETH",
273            price: 3_200.0,
274        },
275    ];
276
277    println!(
278        "=== nexus-rt Dispatch Latency (cycles, {} iterations) ===\n",
279        ITERATIONS
280    );
281    println!(
282        "{:<44} {:>8} {:>8} {:>8}",
283        "Operation", "p50", "p99", "p999"
284    );
285    println!("{}", "-".repeat(72));
286
287    // Single tick through dyn pipeline
288    {
289        let tick = bench_ticks[0];
290        for _ in 0..WARMUP {
291            world.next_sequence();
292            md.pipeline.run(&mut world, black_box(tick));
293        }
294        let mut samples = Vec::with_capacity(ITERATIONS);
295        for _ in 0..ITERATIONS {
296            world.next_sequence();
297            let start = rdtsc_start();
298            md.pipeline.run(&mut world, black_box(tick));
299            let end = rdtsc_end();
300            samples.push(end.wrapping_sub(start));
301        }
302        report("single tick (dyn pipeline, 3 stages)", &mut samples);
303    }
304
305    // Standalone handler (1 param, Res<T>)
306    {
307        for _ in 0..WARMUP {
308            black_box(());
309            signal_handler.run(&mut world, ());
310        }
311        let mut samples = Vec::with_capacity(ITERATIONS);
312        for _ in 0..ITERATIONS {
313            let start = rdtsc_start();
314            black_box(());
315            signal_handler.run(&mut world, ());
316            let end = rdtsc_end();
317            samples.push(end.wrapping_sub(start));
318        }
319        report("handler dispatch (1 param, Res<T>)", &mut samples);
320    }
321
322    // 4-tick batch through driver poll
323    {
324        for _ in 0..WARMUP {
325            md.poll(&mut world, &bench_ticks);
326        }
327        let mut samples = Vec::with_capacity(ITERATIONS);
328        for _ in 0..ITERATIONS {
329            let start = rdtsc_start();
330            md.poll(&mut world, black_box(&bench_ticks));
331            let end = rdtsc_end();
332            samples.push(end.wrapping_sub(start));
333        }
334        let mut per_tick: Vec<u64> = samples
335            .iter()
336            .map(|&s| s / bench_ticks.len() as u64)
337            .collect();
338        report("4-tick poll (total)", &mut samples);
339        report("4-tick poll (per tick)", &mut per_tick);
340    }
341
342    // Change detection
343    {
344        world.next_sequence(); // ensure stale
345        for _ in 0..WARMUP {
346            black_box(signal_handler.inputs_changed(&world));
347        }
348        let mut samples = Vec::with_capacity(ITERATIONS);
349        for _ in 0..ITERATIONS {
350            let start = rdtsc_start();
351            black_box(signal_handler.inputs_changed(&world));
352            let end = rdtsc_end();
353            samples.push(end.wrapping_sub(start));
354        }
355        report("inputs_changed (1 param, stale)", &mut samples);
356    }
357
358    println!();
359}
More examples
Hide additional examples
examples/perf_pipeline.rs (line 560)
236fn main() {
237    let mut wb = WorldBuilder::new();
238    wb.register::<u64>(42);
239    wb.register::<u32>(7);
240    let mut world = wb.build();
241    let r = world.registry_mut();
242
243    // --- Bare 3-stage pipeline (no Option, no World access) ---
244
245    let mut bare = PipelineStart::<u64>::new()
246        .stage(|x: u64| x.wrapping_mul(3), r)
247        .stage(|x: u64| x.wrapping_add(7), r)
248        .stage(|x: u64| x >> 1, r);
249
250    // --- Option 3-stage pipeline ---
251
252    let mut option = PipelineStart::<u64>::new()
253        .stage(
254            |x: u64| -> Option<u64> { if x > 0 { Some(x) } else { None } },
255            r,
256        )
257        .map(|x: u64| x.wrapping_mul(3), r)
258        .filter(|_w, x| *x < 1_000_000);
259
260    // --- World-accessing pipeline (pre-resolved via Res<T>) ---
261
262    let mut world_resolved = PipelineStart::<u64>::new()
263        .stage(add_resource, r)
264        .stage(mul_resource, r);
265
266    // --- World-accessing 3-stage pipeline ---
267
268    let mut stage_3 = PipelineStart::<u64>::new()
269        .stage(add_resource, r)
270        .stage(mul_resource, r)
271        .stage(sub_resource, r);
272
273    // --- Built (boxed) pipeline ---
274
275    let mut boxed = PipelineStart::<u64>::new()
276        .stage(|x: u64| x.wrapping_mul(3), r)
277        .stage(|x: u64| x.wrapping_add(7), r)
278        .stage(|_x: u64| {}, r)
279        .build();
280
281    // --- Batch pipelines (same chains as their linear counterparts) ---
282
283    fn sink(mut acc: ResMut<u64>, x: u64) {
284        *acc = acc.wrapping_add(x);
285    }
286
287    // Bare: 3 compute stages + sink (same chain for both batch and linear)
288    let mut batch_bare = PipelineStart::<u64>::new()
289        .stage(|x: u64| x.wrapping_mul(3), r)
290        .stage(|x: u64| x.wrapping_add(7), r)
291        .stage(sink, r)
292        .build_batch(1024);
293
294    let mut linear_bare = PipelineStart::<u64>::new()
295        .stage(|x: u64| x.wrapping_mul(3), r)
296        .stage(|x: u64| x.wrapping_add(7), r)
297        .stage(sink, r);
298
299    // Res<T>: 3 world-access stages + sink (same chain for both)
300    let mut batch_res = PipelineStart::<u64>::new()
301        .stage(add_resource, r)
302        .stage(mul_resource, r)
303        .stage(sub_resource, r)
304        .stage(sink, r)
305        .build_batch(1024);
306
307    let mut linear_res = PipelineStart::<u64>::new()
308        .stage(add_resource, r)
309        .stage(mul_resource, r)
310        .stage(sub_resource, r)
311        .stage(sink, r);
312
313    // --- Result→catch→map→unwrap_or ---
314
315    let mut catch_pipeline = PipelineStart::<u64>::new()
316        .stage(
317            |x: u64| -> Result<u64, &'static str> { if x > 0 { Ok(x) } else { Err("zero") } },
318            r,
319        )
320        .catch(|_err: &'static str| {}, r)
321        .map(|x: u64| x.wrapping_mul(2), r)
322        .unwrap_or(0);
323
324    // --- Handler dispatch setup ---
325
326    let mut sys_res = handler_res_read.into_handler(world.registry_mut());
327    let mut sys_res_mut = handler_res_mut_write.into_handler(world.registry_mut());
328    let mut sys_two = handler_two_res.into_handler(world.registry_mut());
329    let mut sys_dyn: Box<dyn Handler<u64>> =
330        Box::new(handler_res_read.into_handler(world.registry_mut()));
331
332    // --- Pipeline benchmarks ---
333
334    print_header("Pipeline Dispatch Latency (cycles)");
335
336    let mut input = 1u64;
337
338    bench_batched("baseline (hand-written fn)", || {
339        input = input.wrapping_add(1);
340        baseline_handwritten(&mut world, black_box(input))
341    });
342
343    bench_batched("bare 3-stage pipe", || {
344        input = input.wrapping_add(1);
345        bare_3stage_run(&mut bare, &mut world, black_box(input))
346    });
347
348    bench_batched("option 3-stage (Some path)", || {
349        input = input.wrapping_add(1);
350        option_3stage_run(&mut option, &mut world, black_box(input + 1)).unwrap_or(0)
351    });
352
353    bench_batched("option 3-stage (None path)", || {
354        option_3stage_run(&mut option, &mut world, black_box(0)).unwrap_or(0)
355    });
356
357    bench_batched("world-access 2-stage (Res<T>)", || {
358        input = input.wrapping_add(1);
359        world_access_run(&mut world_resolved, &mut world, black_box(input))
360    });
361
362    bench_batched("boxed Pipeline (dyn dispatch)", || {
363        input = input.wrapping_add(1);
364        boxed_pipeline_run(&mut boxed, &mut world, black_box(input));
365        0
366    });
367
368    bench_batched("result→catch→map→unwrap_or", || {
369        input = input.wrapping_add(1);
370        catch_pipeline.run(&mut world, black_box(input))
371    });
372
373    // --- Handler dispatch benchmarks ---
374
375    println!();
376    print_header("Handler Dispatch Latency (cycles)");
377
378    bench_batched("Handler + Res<u64> (read)", || {
379        input = input.wrapping_add(1);
380        probe_handler_res_read(&mut sys_res, &mut world, black_box(input));
381        0
382    });
383
384    bench_batched("Handler + ResMut<u64> (write+stamp)", || {
385        input = input.wrapping_add(1);
386        probe_handler_res_mut(&mut sys_res_mut, &mut world, black_box(input));
387        0
388    });
389
390    bench_batched("Handler + 2x Res (tuple fetch)", || {
391        input = input.wrapping_add(1);
392        probe_handler_two_res(&mut sys_two, &mut world, black_box(input));
393        0
394    });
395
396    bench_batched("Box<dyn Handler> + Res<u64>", || {
397        input = input.wrapping_add(1);
398        probe_dyn_handler(&mut *sys_dyn, &mut world, black_box(input));
399        0
400    });
401
402    // --- Stage pipeline with Res<T> (3-stage) ---
403
404    println!();
405    print_header("Stage Pipeline with Res<T> (cycles)");
406
407    bench_batched("3-stage pipeline (Res<T>)", || {
408        input = input.wrapping_add(1);
409        stage_3.run(&mut world, black_box(input))
410    });
411
412    // --- Batch vs Linear throughput (total cycles for 100 items) ---
413
414    println!();
415    print_header("Batch vs Linear Throughput (total cycles, 100 items)");
416
417    let items_100: Vec<u64> = (0..100).collect();
418
419    // Batch bare: fill + run
420    {
421        for _ in 0..WARMUP {
422            batch_bare.input_mut().extend_from_slice(&items_100);
423            batch_bare.run(&mut world);
424        }
425        let mut samples = Vec::with_capacity(ITERATIONS);
426        for _ in 0..ITERATIONS {
427            batch_bare.input_mut().extend_from_slice(&items_100);
428            let start = rdtsc_start();
429            batch_bare.run(&mut world);
430            let end = rdtsc_end();
431            samples.push(end.wrapping_sub(start));
432        }
433        samples.sort_unstable();
434        println!(
435            "{:<44} {:>8} {:>8} {:>8}",
436            "batch bare (100 items)",
437            percentile(&samples, 50.0),
438            percentile(&samples, 99.0),
439            percentile(&samples, 99.9),
440        );
441    }
442
443    // Linear bare: 100 individual calls (same chain)
444    {
445        for _ in 0..WARMUP {
446            for i in 0..100u64 {
447                linear_bare.run(&mut world, black_box(i));
448            }
449        }
450        let mut samples = Vec::with_capacity(ITERATIONS);
451        for _ in 0..ITERATIONS {
452            let start = rdtsc_start();
453            for i in 0..100u64 {
454                linear_bare.run(&mut world, black_box(i));
455            }
456            let end = rdtsc_end();
457            samples.push(end.wrapping_sub(start));
458        }
459        samples.sort_unstable();
460        println!(
461            "{:<44} {:>8} {:>8} {:>8}",
462            "linear bare (100 calls)",
463            percentile(&samples, 50.0),
464            percentile(&samples, 99.0),
465            percentile(&samples, 99.9),
466        );
467    }
468
469    // Batch Res<T>: fill + run
470    {
471        for _ in 0..WARMUP {
472            batch_res.input_mut().extend_from_slice(&items_100);
473            batch_res.run(&mut world);
474        }
475        let mut samples = Vec::with_capacity(ITERATIONS);
476        for _ in 0..ITERATIONS {
477            batch_res.input_mut().extend_from_slice(&items_100);
478            let start = rdtsc_start();
479            batch_res.run(&mut world);
480            let end = rdtsc_end();
481            samples.push(end.wrapping_sub(start));
482        }
483        samples.sort_unstable();
484        println!(
485            "{:<44} {:>8} {:>8} {:>8}",
486            "batch Res<T> (100 items)",
487            percentile(&samples, 50.0),
488            percentile(&samples, 99.0),
489            percentile(&samples, 99.9),
490        );
491    }
492
493    // Linear Res<T>: 100 individual calls (same chain)
494    {
495        for _ in 0..WARMUP {
496            for i in 0..100u64 {
497                linear_res.run(&mut world, black_box(i));
498            }
499        }
500        let mut samples = Vec::with_capacity(ITERATIONS);
501        for _ in 0..ITERATIONS {
502            let start = rdtsc_start();
503            for i in 0..100u64 {
504                linear_res.run(&mut world, black_box(i));
505            }
506            let end = rdtsc_end();
507            samples.push(end.wrapping_sub(start));
508        }
509        samples.sort_unstable();
510        println!(
511            "{:<44} {:>8} {:>8} {:>8}",
512            "linear Res<T> (100 calls)",
513            percentile(&samples, 50.0),
514            percentile(&samples, 99.0),
515            percentile(&samples, 99.9),
516        );
517    }
518
519    // --- inputs_changed cost ---
520
521    println!();
522    print_header("inputs_changed Latency (cycles)");
523
524    // Build a world with enough resources for 8-param handlers.
525    let mut ic_wb = WorldBuilder::new();
526    ic_wb.register::<u64>(0);
527    ic_wb.register::<u32>(0);
528    ic_wb.register::<bool>(false);
529    ic_wb.register::<f64>(0.0);
530    ic_wb.register::<i64>(0);
531    ic_wb.register::<i32>(0);
532    ic_wb.register::<u8>(0);
533    ic_wb.register::<u16>(0);
534    let mut ic_world = ic_wb.build();
535    let ic_r = ic_world.registry_mut();
536
537    let ic1 = ic_1p.into_handler(ic_r);
538    let ic2 = ic_2p.into_handler(ic_r);
539    let ic4 = ic_4p.into_handler(ic_r);
540    let ic8 = ic_8p.into_handler(ic_r);
541
542    // Tick 0: all changed (changed_at == current_sequence).
543    bench_batched("inputs_changed 1-param (changed)", || {
544        if ic1.inputs_changed(&ic_world) { 1 } else { 0 }
545    });
546
547    bench_batched("inputs_changed 2-param (changed)", || {
548        if ic2.inputs_changed(&ic_world) { 1 } else { 0 }
549    });
550
551    bench_batched("inputs_changed 4-param (changed)", || {
552        if ic4.inputs_changed(&ic_world) { 1 } else { 0 }
553    });
554
555    bench_batched("inputs_changed 8-param (changed)", || {
556        if ic8.inputs_changed(&ic_world) { 1 } else { 0 }
557    });
558
559    // Advance tick so inputs are stale.
560    ic_world.next_sequence();
561
562    bench_batched("inputs_changed 1-param (stale)", || {
563        if ic1.inputs_changed(&ic_world) { 1 } else { 0 }
564    });
565
566    bench_batched("inputs_changed 2-param (stale)", || {
567        if ic2.inputs_changed(&ic_world) { 1 } else { 0 }
568    });
569
570    bench_batched("inputs_changed 4-param (stale)", || {
571        if ic4.inputs_changed(&ic_world) { 1 } else { 0 }
572    });
573
574    bench_batched("inputs_changed 8-param (stale)", || {
575        if ic8.inputs_changed(&ic_world) { 1 } else { 0 }
576    });
577
578    println!();
579}
Source

pub unsafe fn get<T: 'static>(&self, id: ResourceId) -> &T

Fetch a shared reference to a resource by pre-validated index.

§Safety
  • id must have been returned by WorldBuilder::register for the same builder that produced this container.
  • T must be the same type that was registered at this id.
  • The caller must ensure no mutable reference to this resource exists.
Source

pub unsafe fn get_mut<T: 'static>(&self, id: ResourceId) -> &mut T

Fetch a mutable reference to a resource by pre-validated index.

Takes &self — the container structure is frozen, but individual resources have interior mutability via raw pointers. Sound because callers (single-threaded sequential dispatch) uphold no-aliasing.

§Safety
  • id must have been returned by WorldBuilder::register for the same builder that produced this container.
  • T must be the same type that was registered at this id.
  • The caller must ensure no other reference (shared or mutable) to this resource exists.
Source

pub unsafe fn get_ptr(&self, id: ResourceId) -> *mut u8

Fetch a raw pointer to a resource by pre-validated index.

Intended for macro-generated dispatch code that needs direct pointer access.

§Safety

Trait Implementations§

Auto Trait Implementations§

§

impl Freeze for World

§

impl !RefUnwindSafe for World

§

impl !Sync for World

§

impl Unpin for World

§

impl UnsafeUnpin for World

§

impl UnwindSafe for World

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.