pub fn available_memory_bytes() -> Option<u64> {
#[cfg(any(target_os = "linux", target_os = "android"))]
{
let meminfo = std::fs::read_to_string("/proc/meminfo").ok()?;
parse_mem_available_kib(&meminfo).map(|kib| kib.saturating_mul(1024))
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
{
None
}
}
#[cfg(any(target_os = "linux", target_os = "android", test))]
fn parse_mem_available_kib(meminfo: &str) -> Option<u64> {
meminfo
.lines()
.find_map(|line| line.strip_prefix("MemAvailable:"))
.and_then(|rest| rest.split_whitespace().next())
.and_then(|kib| kib.parse::<u64>().ok())
}
fn fits_within(required_bytes: u64, headroom_bytes: u64, available: u64) -> bool {
required_bytes.saturating_add(headroom_bytes) <= available
}
pub fn fits_in_available_memory(required_bytes: u64, headroom_bytes: u64) -> Option<bool> {
let available = available_memory_bytes()?;
Some(fits_within(required_bytes, headroom_bytes, available))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_mem_available_line() {
let sample = "MemTotal: 16000000 kB\n\
MemFree: 2000000 kB\n\
MemAvailable: 8388608 kB\n\
Buffers: 100000 kB\n";
assert_eq!(parse_mem_available_kib(sample), Some(8_388_608));
}
#[test]
fn missing_mem_available_is_none() {
assert_eq!(parse_mem_available_kib("MemTotal: 16000000 kB\n"), None);
assert_eq!(parse_mem_available_kib(""), None);
}
#[test]
fn fits_is_exact_at_the_boundary() {
assert!(fits_within(0, 0, 0), "zero always fits, even in nothing");
assert!(fits_within(100, 0, 100), "exactly available must fit");
assert!(!fits_within(101, 0, 100), "one byte over must not");
}
#[test]
fn headroom_is_deducted_from_the_budget() {
assert!(fits_within(60, 40, 100), "required + headroom == available");
assert!(
!fits_within(61, 40, 100),
"one byte over once headroom is paid"
);
assert!(
!fits_within(0, 101, 100),
"headroom alone can exceed available"
);
}
#[test]
fn oversized_request_saturates_rather_than_wrapping() {
assert!(
!fits_within(u64::MAX, 1, 100),
"saturation must not wrap a colossal request into a fit"
);
assert!(!fits_within(u64::MAX - 1, 10, 1000));
assert!(!fits_within(1, u64::MAX, 1000), "headroom overflows too");
}
#[test]
fn public_fits_matches_platform_support() {
match available_memory_bytes() {
Some(_) => {
assert_eq!(fits_in_available_memory(0, 0), Some(true));
}
None => {
assert_eq!(fits_in_available_memory(0, 0), None);
}
}
}
}