use crate::arch_requirements::{required_roles, WeightRole};
use crate::error::RealizarError;
use crate::gguf::ArchConstraints;
use std::fmt;
pub use trueno::contracts::{
self as kernel_contracts, validate_f32_buffer, validate_gemv_shapes, validate_weight_buffer,
QuantFormat, TensorLayout, WeightBufferError, STACK_LAYOUT,
};
#[derive(Debug, Clone)]
pub struct ModelLoadProof {
architecture: String,
num_layers: usize,
}
impl ModelLoadProof {
#[must_use]
pub fn architecture(&self) -> &str {
&self.architecture
}
#[must_use]
pub fn num_layers(&self) -> usize {
self.num_layers
}
}
#[derive(Debug, Clone)]
pub struct ModelLoadConfig {
pub architecture: String,
pub num_layers: usize,
pub hidden_dim: usize,
pub num_heads: usize,
pub num_kv_heads: usize,
pub intermediate_dim: usize,
pub vocab_size: usize,
pub present_roles: Vec<WeightRole>,
}
#[derive(Debug, Clone)]
pub struct ModelLoadError {
pub gate: &'static str,
pub reason: String,
}
impl fmt::Display for ModelLoadError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"GH-279 contract gate '{}' failed: {}",
self.gate, self.reason
)
}
}
impl std::error::Error for ModelLoadError {}
impl From<ModelLoadError> for RealizarError {
fn from(e: ModelLoadError) -> Self {
RealizarError::UnsupportedOperation {
operation: format!("contract_gate::{}", e.gate),
reason: e.reason,
}
}
}
pub fn validate_model_load(
config: &ModelLoadConfig,
) -> std::result::Result<ModelLoadProof, ModelLoadError> {
validate_supported_architecture(&config.architecture)?;
validate_dimensions(config)?;
let arch = validate_architecture(&config.architecture)?;
if !config.present_roles.is_empty() {
validate_completeness(&arch, &config.present_roles, &config.architecture)?;
}
Ok(ModelLoadProof {
architecture: config.architecture.clone(),
num_layers: config.num_layers,
})
}
pub fn validate_model_load_basic(
architecture: &str,
num_layers: usize,
hidden_dim: usize,
num_heads: usize,
num_kv_heads: usize,
intermediate_dim: usize,
vocab_size: usize,
) -> std::result::Result<ModelLoadProof, ModelLoadError> {
validate_model_load(&ModelLoadConfig {
architecture: architecture.to_string(),
num_layers,
hidden_dim,
num_heads,
num_kv_heads,
intermediate_dim,
vocab_size,
present_roles: Vec::new(), })
}
pub fn gate_error(e: ModelLoadError) -> RealizarError {
e.into()
}
fn require_nonzero(field_name: &str, value: usize) -> std::result::Result<(), ModelLoadError> {
if value == 0 {
return Err(ModelLoadError {
gate: "dimension_plausibility",
reason: format!("{field_name} is 0"),
});
}
Ok(())
}
fn validate_dimensions(config: &ModelLoadConfig) -> std::result::Result<(), ModelLoadError> {
require_nonzero("hidden_dim", config.hidden_dim)?;
require_nonzero("num_heads", config.num_heads)?;
if !config.hidden_dim.is_multiple_of(config.num_heads) {
return Err(ModelLoadError {
gate: "dimension_plausibility",
reason: format!(
"hidden_dim ({}) is not divisible by num_heads ({})",
config.hidden_dim, config.num_heads
),
});
}
require_nonzero("vocab_size", config.vocab_size)?;
require_nonzero("num_kv_heads", config.num_kv_heads)?;
if config.num_kv_heads > config.num_heads {
return Err(ModelLoadError {
gate: "dimension_plausibility",
reason: format!(
"num_kv_heads ({}) > num_heads ({})",
config.num_kv_heads, config.num_heads
),
});
}
require_nonzero("intermediate_dim", config.intermediate_dim)?;
require_nonzero("num_layers", config.num_layers)?;
Ok(())
}
fn validate_architecture(arch_name: &str) -> std::result::Result<ArchConstraints, ModelLoadError> {
let arch = ArchConstraints::from_architecture(arch_name);
Ok(arch)
}
#[must_use]
pub fn is_gemma_family(arch_name: &str) -> bool {
let lower = arch_name.to_ascii_lowercase();
lower.starts_with("gemma")
}
#[must_use]
pub fn is_gemma1_supported(arch_name: &str) -> bool {
let lower = arch_name.to_ascii_lowercase();
lower == "gemma" || lower == "gemmaforcausallm"
}
#[must_use]
pub fn is_gemma2_supported(arch_name: &str) -> bool {
let lower = arch_name.to_ascii_lowercase();
lower == "gemma2" || lower == "gemma2forcausallm"
}
fn validate_supported_architecture(arch_name: &str) -> std::result::Result<(), ModelLoadError> {
if is_gemma1_supported(arch_name) {
return Ok(());
}
if is_gemma2_supported(arch_name) {
return Ok(());
}
if is_gemma_family(arch_name) {
return Err(ModelLoadError {
gate: "architecture_supported",
reason: format!(
"Gemma3/Gemma3n architecture '{arch_name}' requires behaviors \
(per-layer embedding scaling, alternating local/global attention \
with QK-norm) that realizar's forward path does not implement yet. \
Running it would silently produce incorrect output, so it is \
refused. (Gemma v1 — PMAT-809 — and Gemma v2 — PMAT-810 — ARE \
supported.) Track Gemma3 support at PMAT-807."
),
});
}
Ok(())
}
fn validate_completeness(
arch: &ArchConstraints,
present: &[WeightRole],
arch_name: &str,
) -> std::result::Result<(), ModelLoadError> {
contract_pre_weight_completeness!();
let required = required_roles(arch);
let mut missing = Vec::new();
for &role in required {
if !present.contains(&role) {
missing.push(role.field_name());
}
}
if !missing.is_empty() {
return Err(ModelLoadError {
gate: "architecture_completeness",
reason: format!(
"Architecture '{}' requires {} weights but model is missing: [{}]",
arch_name,
required.len(),
missing.join(", "),
),
});
}
contract_post_weight_completeness!(&());
Ok(())
}
pub fn validate_f32_dequant_limits(
tensor_entries: &[(usize, u8)],
file_size: u64,
) -> std::result::Result<(), ModelLoadError> {
let mut estimated_f32_bytes: u64 = 0;
for &(byte_size, dtype) in tensor_entries {
let elements = estimate_elements(byte_size, dtype);
estimated_f32_bytes += elements as u64 * 4;
}
dequant_verdict(file_size, estimated_f32_bytes, system_memory_bytes())
}
fn dequant_verdict(
file_size: u64,
estimated_f32_bytes: u64,
mem_total: Option<u64>,
) -> std::result::Result<(), ModelLoadError> {
let estimated_peak = file_size.saturating_add(estimated_f32_bytes);
let Some(mem_total) = mem_total else {
return Err(ModelLoadError {
gate: "resource_limits",
reason: format!(
"cannot determine total system RAM on this platform ({}), so the F32 \
dequant OOM guard cannot be evaluated; refusing to dequant ~{} GB \
(file {} GB + dequant {} GB). An unknown memory limit is not an \
unlimited one (#2568). Use the quantized inference path.",
std::env::consts::OS,
estimated_peak / (1 << 30),
file_size / (1 << 30),
estimated_f32_bytes / (1 << 30),
),
});
};
let threshold = mem_total / 5 * 4;
if estimated_peak > threshold {
return Err(ModelLoadError {
gate: "resource_limits",
reason: format!(
"F32 dequant would use ~{} GB (file {} GB + dequant {} GB), \
exceeds 80% of system RAM ({} GB). Use quantized inference path.",
estimated_peak / (1 << 30),
file_size / (1 << 30),
estimated_f32_bytes / (1 << 30),
mem_total / (1 << 30),
),
});
}
Ok(())
}
fn estimate_elements(byte_size: usize, dtype: u8) -> usize {
match dtype {
12 => byte_size / 144 * 256, 14 => byte_size / 210 * 256, 2 => byte_size / 36 * 32, 1 => byte_size / 2, 30 => byte_size / 2, 8 => byte_size / 5 * 4, 9 => byte_size / 5 * 4, _ => byte_size / 4, }
}
const SYSCTL_PATHS: &[&str] = &["/usr/sbin/sysctl", "/sbin/sysctl"];
pub fn system_memory_bytes() -> Option<u64> {
if let Some(bytes) = proc_meminfo_total_bytes() {
return Some(bytes);
}
if let Some(bytes) = sysctl_hw_memsize_bytes() {
return Some(bytes);
}
windows_total_bytes()
}
#[cfg(windows)]
fn windows_total_bytes() -> Option<u64> {
use sysinfo::System;
let mut sys = System::new();
sys.refresh_memory();
Some(sys.total_memory()).filter(|&b| b > 0)
}
#[cfg(not(windows))]
fn windows_total_bytes() -> Option<u64> {
None
}
fn proc_meminfo_total_bytes() -> Option<u64> {
let content = std::fs::read_to_string("/proc/meminfo").ok()?;
parse_meminfo_total_bytes(&content)
}
fn parse_meminfo_total_bytes(content: &str) -> Option<u64> {
for line in content.lines() {
if let Some(rest) = line.strip_prefix("MemTotal:") {
let kb: u64 = rest.split_whitespace().next()?.parse().ok()?;
return kb.checked_mul(1024).filter(|&b| b > 0);
}
}
None
}
fn sysctl_hw_memsize_bytes() -> Option<u64> {
if !cfg!(target_os = "macos") {
return None;
}
run_sysctl_memsize(SYSCTL_PATHS)
}
fn run_sysctl_memsize(paths: &[&str]) -> Option<u64> {
for path in paths {
let Ok(output) = std::process::Command::new(path)
.args(["-n", "hw.memsize"])
.output()
else {
continue; };
if !output.status.success() {
continue; }
if let Some(bytes) = parse_sysctl_memsize(&String::from_utf8_lossy(&output.stdout)) {
return Some(bytes);
}
}
None
}
fn parse_sysctl_memsize(stdout: &str) -> Option<u64> {
stdout.trim().parse::<u64>().ok().filter(|&b| b > 0)
}
#[must_use]
pub fn transpose_f32(data: &[f32], rows: usize, cols: usize) -> Vec<f32> {
contract_pre_transpose_involution!();
assert_eq!(
data.len(),
rows * cols,
"transpose_f32: data.len()={} != rows*cols={}",
data.len(),
rows * cols
);
let mut out = vec![0.0f32; rows * cols];
trueno::blis::transpose::transpose(rows, cols, data, &mut out)
.expect("transpose_f32: dimension mismatch (should be impossible after assert)");
contract_post_transpose!(&out);
out
}
#[cfg(test)]
mod tests {
#[test]
fn memory_probe_exists_on_every_shipped_platform() {
let got = system_memory_bytes();
assert!(
got.is_some(),
"no memory probe on this platform ({}). Fail-closed is only safe \
where a probe EXISTS: without one the guard refuses every dequant \
and the load path is dead. Add a probe for this target (#2568).",
std::env::consts::OS
);
let bytes = got.unwrap_or(0);
assert!(
bytes >= 256 * 1024 * 1024 && bytes <= 8 * 1024 * 1024 * 1024 * 1024,
"implausible total memory {bytes} bytes on {} -- suspect a unit \
error (kB read as bytes, or the reverse)",
std::env::consts::OS
);
}
#[cfg(windows)]
#[test]
fn windows_probe_reports_bytes_not_kilobytes() {
let b = windows_total_bytes().expect("windows probe must report a total");
assert!(
b >= 1024 * 1024 * 1024,
"windows total_memory returned {b}; a value this small means \
KILOBYTES were read as BYTES (#2568)"
);
}
use super::*;
fn valid_config() -> ModelLoadConfig {
ModelLoadConfig {
architecture: "llama".to_string(),
num_layers: 32,
hidden_dim: 4096,
num_heads: 32,
num_kv_heads: 8,
intermediate_dim: 11008,
vocab_size: 32000,
present_roles: Vec::new(),
}
}
#[test]
fn test_valid_model_passes() {
let proof = validate_model_load(&valid_config()).expect("should pass");
assert_eq!(proof.architecture(), "llama");
assert_eq!(proof.num_layers(), 32);
}
#[test]
fn test_zero_hidden_dim_fails() {
let mut config = valid_config();
config.hidden_dim = 0;
let err = validate_model_load(&config).unwrap_err();
assert_eq!(err.gate, "dimension_plausibility");
assert!(err.reason.contains("hidden_dim"));
}
#[test]
fn test_zero_num_heads_fails() {
let mut config = valid_config();
config.num_heads = 0;
let err = validate_model_load(&config).unwrap_err();
assert!(err.reason.contains("num_heads"));
}
#[test]
fn test_hidden_not_divisible_by_heads() {
let mut config = valid_config();
config.hidden_dim = 4097;
let err = validate_model_load(&config).unwrap_err();
assert!(err.reason.contains("not divisible"));
}
#[test]
fn test_kv_heads_greater_than_heads() {
let mut config = valid_config();
config.num_kv_heads = 64;
let err = validate_model_load(&config).unwrap_err();
assert!(err.reason.contains("num_kv_heads"));
}
#[test]
fn test_zero_vocab_fails() {
let mut config = valid_config();
config.vocab_size = 0;
let err = validate_model_load(&config).unwrap_err();
assert!(err.reason.contains("vocab_size"));
}
#[test]
fn test_zero_layers_fails() {
let mut config = valid_config();
config.num_layers = 0;
let err = validate_model_load(&config).unwrap_err();
assert!(err.reason.contains("num_layers"));
}
#[test]
fn test_zero_intermediate_fails() {
let mut config = valid_config();
config.intermediate_dim = 0;
let err = validate_model_load(&config).unwrap_err();
assert!(err.reason.contains("intermediate_dim"));
}
#[test]
fn test_basic_convenience() {
let proof =
validate_model_load_basic("qwen2", 28, 1536, 12, 2, 8960, 151936).expect("should pass");
assert_eq!(proof.architecture(), "qwen2");
}
#[test]
fn test_completeness_llama_all_present() {
let mut config = valid_config();
config.present_roles = vec![
WeightRole::AttnNorm,
WeightRole::FfnNorm,
WeightRole::QProj,
WeightRole::KProj,
WeightRole::VProj,
WeightRole::OProj,
WeightRole::FfnGate,
WeightRole::FfnUp,
WeightRole::FfnDown,
];
assert!(validate_model_load(&config).is_ok());
}
#[test]
fn test_completeness_llama_missing_gate() {
let mut config = valid_config();
config.present_roles = vec![
WeightRole::AttnNorm,
WeightRole::FfnNorm,
WeightRole::QProj,
WeightRole::KProj,
WeightRole::VProj,
WeightRole::OProj,
];
let err = validate_model_load(&config).unwrap_err();
assert_eq!(err.gate, "architecture_completeness");
assert!(err.reason.contains("ffn_gate"));
}
#[test]
fn test_completeness_qwen3_needs_qk_norm() {
let mut config = valid_config();
config.architecture = "qwen3".to_string();
config.present_roles = vec![
WeightRole::AttnNorm,
WeightRole::FfnNorm,
WeightRole::QProj,
WeightRole::KProj,
WeightRole::VProj,
WeightRole::OProj,
WeightRole::FfnGate,
WeightRole::FfnUp,
WeightRole::FfnDown,
];
let err = validate_model_load(&config).unwrap_err();
assert!(err.reason.contains("attn_q_norm"));
}
#[test]
fn test_completeness_qwen3_with_qk_norm_passes() {
let mut config = valid_config();
config.architecture = "qwen3".to_string();
config.present_roles = vec![
WeightRole::AttnNorm,
WeightRole::FfnNorm,
WeightRole::QProj,
WeightRole::KProj,
WeightRole::VProj,
WeightRole::OProj,
WeightRole::FfnGate,
WeightRole::FfnUp,
WeightRole::FfnDown,
WeightRole::AttnQNorm,
WeightRole::AttnKNorm,
];
assert!(validate_model_load(&config).is_ok());
}
#[test]
fn test_no_roles_skips_completeness() {
let config = valid_config();
assert!(config.present_roles.is_empty());
assert!(validate_model_load(&config).is_ok());
}
#[test]
fn test_unknown_architecture_uses_base() {
let proof = validate_model_load_basic("unknown_future_arch", 1, 128, 4, 4, 512, 1000)
.expect("unknown arch should pass with base constraints");
assert_eq!(proof.architecture(), "unknown_future_arch");
}
#[test]
fn test_gemma3_rejected_at_load() {
let gemma_names = [
"gemma3",
"Gemma3ForCausalLM",
"gemma3n", ];
for name in gemma_names {
let mut config = valid_config();
config.architecture = name.to_string();
let err = validate_model_load(&config)
.expect_err(&format!("Gemma3 arch '{name}' must be refused, not run"));
assert_eq!(
err.gate, "architecture_supported",
"'{name}' rejected by wrong gate: {}",
err.gate
);
assert!(
err.reason.contains("Gemma3"),
"'{name}' error must name the refused architecture: {}",
err.reason
);
}
}
#[test]
fn test_gemma2_now_supported() {
for name in ["gemma2", "GEMMA2", "Gemma2ForCausalLM"] {
assert!(
is_gemma2_supported(name),
"'{name}' must be recognized as supported Gemma v2"
);
let mut config = valid_config();
config.architecture = name.to_string();
assert!(
validate_model_load(&config).is_ok(),
"Gemma v2 arch '{name}' must now load (PMAT-810)"
);
}
assert!(!is_gemma2_supported("gemma3"));
assert!(!is_gemma2_supported("gemma3n"));
assert!(!is_gemma2_supported("gemma"));
}
#[test]
fn test_gemma1_now_supported() {
for name in ["gemma", "GEMMA", "GemmaForCausalLM"] {
assert!(
is_gemma1_supported(name),
"'{name}' must be recognized as supported Gemma v1"
);
let mut config = valid_config();
config.architecture = name.to_string();
assert!(
validate_model_load(&config).is_ok(),
"Gemma v1 arch '{name}' must now load (PMAT-809)"
);
}
assert!(!is_gemma1_supported("gemma2"));
assert!(!is_gemma1_supported("gemma3"));
assert!(!is_gemma1_supported("gemma3n"));
}
#[test]
fn test_gemma2_accepted_via_basic_loader_path() {
validate_model_load_basic("gemma2", 26, 2304, 8, 4, 9216, 256_000)
.expect("gemma2 must now load at the basic loader gate (PMAT-810)");
}
#[test]
fn test_gemma1_accepted_via_basic_loader_path() {
let proof = validate_model_load_basic("gemma", 18, 2048, 8, 1, 16384, 256_128)
.expect("gemma v1 must now load at the basic loader gate");
assert_eq!(proof.architecture(), "gemma");
}
#[test]
fn test_non_gemma_architectures_unaffected() {
for arch in [
"llama",
"qwen2",
"qwen3",
"mistral",
"phi",
"phi2",
"deepseek",
"gpt2",
"unknown_future_arch",
] {
assert!(
!is_gemma_family(arch),
"'{arch}' wrongly classified as Gemma"
);
let mut config = valid_config();
config.architecture = arch.to_string();
assert!(
validate_model_load(&config).is_ok(),
"non-Gemma arch '{arch}' must still load"
);
}
}
#[test]
fn test_is_gemma_family_classification() {
assert!(is_gemma_family("gemma"));
assert!(is_gemma_family("GEMMA"));
assert!(is_gemma_family("Gemma2ForCausalLM"));
assert!(!is_gemma_family("llama"));
assert!(!is_gemma_family("gem")); assert!(!is_gemma_family(""));
}
#[test]
fn test_error_display() {
let err = ModelLoadError {
gate: "test_gate",
reason: "test reason".to_string(),
};
let msg = format!("{err}");
assert!(msg.contains("GH-279"));
assert!(msg.contains("test_gate"));
assert!(msg.contains("test reason"));
}
#[test]
fn test_error_converts_to_realizar_error() {
let err = ModelLoadError {
gate: "test",
reason: "test".to_string(),
};
let r_err: RealizarError = err.into();
match r_err {
RealizarError::UnsupportedOperation { operation, .. } => {
assert!(operation.contains("contract_gate"));
},
_ => panic!("expected UnsupportedOperation"),
}
}
#[test]
fn test_estimate_elements_f32() {
assert_eq!(estimate_elements(400, 0), 100);
}
#[test]
fn test_estimate_elements_q4k() {
assert_eq!(estimate_elements(144, 12), 256);
assert_eq!(estimate_elements(288, 12), 512);
}
#[test]
fn test_estimate_elements_q6k() {
assert_eq!(estimate_elements(210, 14), 256);
}
#[test]
fn test_estimate_elements_f16() {
assert_eq!(estimate_elements(200, 1), 100);
}
#[test]
fn test_estimate_elements_bf16() {
assert_eq!(estimate_elements(200, 30), 100);
}
#[test]
fn test_small_model_passes_resource_check() {
let tensors: Vec<(usize, u8)> = vec![(144 * 1000, 12)]; let result = validate_f32_dequant_limits(&tensors, 1_000_000);
assert!(
result.is_ok(),
"a ~5 MB peak must pass the resource gate on any host that can run \
this test, got: {:?}",
result.err()
);
}
#[test]
fn test_dequant_verdict_fails_closed_when_memory_unknown() {
let err = dequant_verdict(1 << 30, 8 << 30, None)
.expect_err("unknown system memory MUST refuse the dequant, not allow it");
assert_eq!(err.gate, "resource_limits");
assert!(
err.reason.contains("cannot determine total system RAM"),
"the refusal must name the missing measurement, got: {}",
err.reason
);
}
#[test]
fn test_dequant_verdict_fails_closed_even_for_a_tiny_model() {
assert!(
dequant_verdict(1, 0, None).is_err(),
"an unmeasurable host must refuse every dequant, however small"
);
}
#[test]
fn test_dequant_verdict_refuses_over_80_percent() {
let err = dequant_verdict(2 << 30, 12 << 30, Some(16 << 30))
.expect_err("14 GiB peak on a 16 GiB host must be refused");
assert!(
err.reason.contains("exceeds 80% of system RAM"),
"{}",
err.reason
);
}
#[test]
fn test_dequant_verdict_allows_under_80_percent() {
assert!(dequant_verdict(2 << 30, 6 << 30, Some(16 << 30)).is_ok());
}
#[test]
fn test_dequant_verdict_threshold_does_not_overflow() {
assert!(dequant_verdict(0, 0, Some(u64::MAX)).is_ok());
assert!(
dequant_verdict(1, 0, Some(0)).is_err(),
"a host reporting 0 bytes of RAM fits nothing"
);
}
#[test]
fn test_system_memory_bytes_is_measurable_on_this_platform() {
let mem = system_memory_bytes();
assert!(
mem.is_some(),
"no memory probe for target_os={}: the F32 dequant OOM guard cannot \
be armed here. Add a probe to system_memory_bytes() (#2568) — do \
NOT skip this assertion by platform.",
std::env::consts::OS,
);
assert!(mem.expect("checked is_some above") > 0);
}
#[test]
fn test_parse_meminfo_total_bytes() {
let sample = "MemTotal: 131377776 kB\nMemFree: 2000 kB\n";
assert_eq!(parse_meminfo_total_bytes(sample), Some(131_377_776 * 1024));
assert_eq!(parse_meminfo_total_bytes("MemFree: 2000 kB\n"), None);
assert_eq!(parse_meminfo_total_bytes("MemTotal: kB\n"), None);
assert_eq!(parse_meminfo_total_bytes("MemTotal: 0 kB\n"), None);
assert_eq!(parse_meminfo_total_bytes(""), None);
}
#[test]
fn test_parse_sysctl_memsize() {
assert_eq!(parse_sysctl_memsize("17179869184\n"), Some(17_179_869_184));
assert_eq!(
parse_sysctl_memsize(" 17179869184 "),
Some(17_179_869_184)
);
assert_eq!(parse_sysctl_memsize(""), None);
assert_eq!(parse_sysctl_memsize("hw.memsize: 17179869184\n"), None);
assert_eq!(parse_sysctl_memsize("0\n"), None);
}
#[test]
fn test_run_sysctl_memsize_against_a_stub() {
let dir = tempfile::tempdir().expect("tempdir");
let good = dir.path().join("sysctl_ok");
std::fs::write(&good, "#!/bin/sh\necho 17179869184\n").expect("write stub");
set_executable(&good);
let bad = dir.path().join("sysctl_fail");
std::fs::write(&bad, "#!/bin/sh\necho 999\nexit 1\n").expect("write stub");
set_executable(&bad);
let missing = dir.path().join("sysctl_absent");
let (good, bad, missing) = (
good.to_string_lossy().into_owned(),
bad.to_string_lossy().into_owned(),
missing.to_string_lossy().into_owned(),
);
assert_eq!(run_sysctl_memsize(&[&good]), Some(17_179_869_184));
assert_eq!(
run_sysctl_memsize(&[&bad]),
None,
"non-zero exit must not be trusted"
);
assert_eq!(run_sysctl_memsize(&[&missing]), None);
assert_eq!(
run_sysctl_memsize(&[&missing, &bad, &good]),
Some(17_179_869_184)
);
assert_eq!(run_sysctl_memsize(&[]), None);
}
fn set_executable(path: &std::path::Path) {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o755))
.expect("chmod stub");
}
}
}