use core::ptr;
use core::{ffi::c_void, mem};
use errno::Errno;
use libc::{
host_info64_t, host_statistics64, mach_host_self, mach_task_self, sysconf, sysctlbyname,
vm_statistics64, HOST_VM_INFO64, HOST_VM_INFO64_COUNT, KERN_SUCCESS, _SC_PAGESIZE,
};
use mach::mach_port::mach_port_deallocate;
pub fn page_size() -> Result<u64, Option<Errno>> {
errno::set_errno(Errno(0));
let return_value = unsafe { sysconf(_SC_PAGESIZE) };
if return_value < 0 {
let error_code = errno::errno().0;
if error_code != 0 {
Err(Some(Errno(error_code)))
} else {
Err(None)
}
} else {
Ok(return_value as u64)
}
}
pub fn try_get_total_physical_memory() -> Result<u64, Errno> {
let name = c"hw.memsize";
let mut memsize = 0u64;
let mut memsize_len = size_of_val(&memsize);
let return_value = unsafe {
sysctlbyname(
name.as_ptr(),
&mut memsize as *mut _ as *mut c_void,
&mut memsize_len,
ptr::null_mut(),
0,
)
};
if return_value == 0 {
Ok(memsize)
} else {
Err(errno::errno())
}
}
pub fn total() -> u64 {
try_get_total_physical_memory().expect("sysctlbyname")
}
pub fn vm_statistics() -> Result<vm_statistics64, Errno> {
let mach_port = unsafe { mach_host_self() };
let mut count = HOST_VM_INFO64_COUNT;
let mut stats: vm_statistics64 = unsafe { mem::zeroed() };
let return_value = unsafe {
host_statistics64(
mach_port,
HOST_VM_INFO64,
&mut stats as *mut _ as host_info64_t,
&mut count,
)
};
let port_result = unsafe { mach_port_deallocate(mach_task_self(), mach_port) };
if port_result != KERN_SUCCESS || return_value != KERN_SUCCESS {
Err(errno::errno())
} else {
Ok(stats)
}
}
pub fn calculate_available_memory() -> u64 {
let page_size = page_size().expect("error getting page size");
let stats = vm_statistics().expect("error getting vm_statistics64");
(stats.active_count + stats.free_count) as u64 * page_size
}