#[cfg(target_os = "macos")]
use std::process::Command;
#[must_use]
pub fn available_memory_bytes() -> Option<u64> {
#[cfg(target_os = "linux")]
{
read_linux_mem_available()
}
#[cfg(target_os = "macos")]
{
read_macos_available()
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
{
None
}
}
#[cfg(target_os = "linux")]
fn read_linux_mem_available() -> Option<u64> {
let s = std::fs::read_to_string("/proc/meminfo").ok()?;
for line in s.lines() {
if let Some(rest) = line.strip_prefix("MemAvailable:") {
let kb: u64 = rest.split_whitespace().next()?.parse().ok()?;
return kb.checked_mul(1024);
}
}
None
}
#[cfg(target_os = "macos")]
fn read_macos_available() -> Option<u64> {
let page_size = sysctl_u64("hw.pagesize")?;
let free = sysctl_u64("vm.page_free_count")?;
let inactive = sysctl_u64("vm.page_inactive_count").unwrap_or(0);
Some(free.saturating_add(inactive).saturating_mul(page_size))
}
#[cfg(target_os = "macos")]
fn sysctl_u64(name: &str) -> Option<u64> {
let out = Command::new("sysctl").args(["-n", name]).output().ok()?;
if !out.status.success() {
return None;
}
std::str::from_utf8(&out.stdout).ok()?.trim().parse().ok()
}