use std::{cell::RefCell, rc::Rc, time::Duration};
pub trait DeviceInfo {
fn total_memory_bytes(&self) -> Option<u64>;
fn resident_memory_bytes(&self) -> Option<u64> {
None
}
fn available_memory_bytes(&self) -> Option<u64> {
None
}
fn process_cpu_time(&self) -> Option<Duration> {
None
}
fn release_free_memory(&self) -> bool {
false
}
}
pub type DeviceInfoRef = Rc<dyn DeviceInfo>;
struct DefaultDeviceInfo;
impl DeviceInfo for DefaultDeviceInfo {
fn total_memory_bytes(&self) -> Option<u64> {
#[cfg(any(target_os = "linux", target_os = "android"))]
{
let text = std::fs::read_to_string("/proc/meminfo").ok()?;
for line in text.lines() {
if let Some(rest) = line.strip_prefix("MemTotal:") {
let kb: u64 = rest.split_whitespace().next()?.parse().ok()?;
return Some(kb * 1024);
}
}
None
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
{
None
}
}
fn resident_memory_bytes(&self) -> Option<u64> {
#[cfg(any(target_os = "linux", target_os = "android"))]
{
let text = std::fs::read_to_string("/proc/self/statm").ok()?;
resident_bytes_from_statm(&text, page_size_bytes())
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
{
None
}
}
}
#[cfg(any(target_os = "linux", target_os = "android", test))]
fn resident_bytes_from_statm(text: &str, page_size: u64) -> Option<u64> {
text.split_whitespace()
.nth(1)?
.parse::<u64>()
.ok()?
.checked_mul(page_size)
}
#[cfg(any(target_os = "linux", target_os = "android", test))]
const fn page_size_bytes() -> u64 {
4096
}
thread_local! {
static PLATFORM_DEVICE_INFO: RefCell<Option<DeviceInfoRef>> = const { RefCell::new(None) };
}
pub fn set_platform_device_info(info: DeviceInfoRef) {
PLATFORM_DEVICE_INFO.with(|cell| *cell.borrow_mut() = Some(info));
}
pub fn clear_platform_device_info() {
PLATFORM_DEVICE_INFO.with(|cell| *cell.borrow_mut() = None);
}
pub fn device_info() -> DeviceInfoRef {
PLATFORM_DEVICE_INFO
.with(|cell| cell.borrow().clone())
.unwrap_or_else(|| Rc::new(DefaultDeviceInfo))
}
pub fn release_free_memory() -> bool {
device_info().release_free_memory()
}
#[cfg(test)]
#[path = "tests/device_info_tests.rs"]
mod tests;