kevy_embedded/config_tier.rs
1//! The tiering budget spec — split out of
2//! [`crate::config`] for the 500-LOC house rule. Mirrors the server's
3//! `[tiering] budget` forms; resolution happens at open and re-runs on
4//! every reaper tick for the probe-backed forms.
5
6/// One transparent-tiering RAM budget, as configured. Resolution to
7/// bytes probes the OS memory bound through `kevy-sys` (the sanctioned
8/// boundary).
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum TierBudgetSpec {
11 /// 0.70 × the detected memory bound (cgroup v2 `memory.max` /
12 /// `/proc/meminfo MemAvailable` on Linux; `hw.memsize` on macOS).
13 Auto,
14 /// That percent of the detected bound (validated 1..=100 at open).
15 Percent(u8),
16 /// Absolute bytes.
17 Bytes(u64),
18}
19
20#[cfg(not(target_arch = "wasm32"))]
21impl TierBudgetSpec {
22 /// The `auto` form's fraction of the detected bound (RFC §7: 0.70).
23 const AUTO_PCT: u64 = 70;
24
25 /// Resolve to bytes. `None` = the probe found no bound (the open
26 /// path turns that into a named error, never a silent off).
27 pub(crate) fn resolve(self) -> Option<u64> {
28 match self {
29 Self::Bytes(b) => Some(b),
30 Self::Auto => probe().map(|d| d / 100 * Self::AUTO_PCT),
31 Self::Percent(p) => probe().map(|d| d / 100 * u64::from(p)),
32 }
33 }
34}
35
36/// The OS memory-bound probe. On wasm32 there is no OS to ask (and
37/// kevy-sys never links there): auto/percent budgets resolve to `None`,
38/// which the open path reports as a named error.
39#[cfg(not(target_arch = "wasm32"))]
40fn probe() -> Option<u64> {
41 kevy_sys::detected_memory_bound()
42}