use std::cell::RefCell;
use std::rc::Rc;
pub trait DeviceInfo {
fn total_memory_bytes(&self) -> Option<u64>;
}
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
}
}
}
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))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn registered_device_info_takes_precedence() {
clear_platform_device_info();
struct Fake;
impl DeviceInfo for Fake {
fn total_memory_bytes(&self) -> Option<u64> {
Some(8 * 1024 * 1024 * 1024)
}
}
set_platform_device_info(Rc::new(Fake));
assert_eq!(device_info().total_memory_bytes(), Some(8 << 30));
clear_platform_device_info();
}
}