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
//! App-level diagnostics bridge: surface Noesis's process-global allocator
//! counters as a Bevy resource and route its error handler into Bevy's log.
//!
//! Unlike the per-element bridges (visibility, layout, brushes, …) this targets
//! nothing in the visual tree; it watches the engine itself. The plugin owns:
//!
//! * [`NoesisDiagnostics`], a resource refreshed every frame from
//! `noesis_runtime::diagnostics::{allocated_memory, allocated_memory_accum,
//! allocations_count}`. Absolute values aren't meaningful across builds;
//! reason about deltas and monotonicity (`accum` is monotonic
//! non-decreasing; the others rise and fall with object lifetimes).
//! * an optional process-global error handler ([`route_errors`]) that forwards
//! Noesis `NS_ERROR` reports into Bevy `tracing` (`warn!` / `error!`). It is
//! installed for the process lifetime (see `install_error_routing`).
//!
//! [`route_errors`]: NoesisDiagnosticsPlugin::route_errors
//!
//! Both halves need [`crate::NoesisPlugin`] to have called `noesis_runtime::init`
//! first, which it has, since this plugin is added from inside `NoesisPlugin`
//! after `init()`.
use *;
use diagnostics;
/// Snapshot of Noesis's allocator counters, refreshed once per frame.
///
/// Starts at all-zero (`Default`); a working refresh fills it with the live
/// figures after the engine has allocated anything (which it has by the time the
/// first scene builds). All values are bytes/counts straight from Noesis.
/// App-level plugin exposing [`NoesisDiagnostics`] and (optionally) routing the
/// Noesis error handler into Bevy's log.
///
/// Added by [`crate::NoesisPlugin`] with [`route_errors`](Self::route_errors)
/// enabled. Construct it directly to opt out of error routing:
///
/// ```ignore
/// app.add_plugins(NoesisDiagnosticsPlugin { route_errors: false });
/// ```
/// Install a process-global Noesis error handler that forwards into Bevy's log,
/// for the lifetime of the process.
///
/// `NoesisPlugin` adds this only after `noesis_runtime::init()`, so the handler
/// slot is live. We deliberately **leak** the RAII guard: it restores the
/// predecessor handler on drop, but Bevy gives no drop-order guarantee between a
/// main-world resource and the render-world `NoesisRenderState` that owns
/// `shutdown()`. If the guard dropped after shutdown, the restore call would
/// reach into a torn-down `NsCore` kernel and crash. A process-global log hook
/// wants process lifetime anyway (the same reason `log::set_logger` never
/// uninstalls), so leaking is the correct trade, not a workaround.
/// Pull the current allocator counters into [`NoesisDiagnostics`]. `set_if_neq`
/// keeps change-detection quiet on the (common) frames where nothing moved.