#[cfg(test)]
use super::mocks::MEMINFO;
use super::SysPath;
use crate::{Error, Result};
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
const MEM_TOTAL: &str = "MemTotal:";
const MEM_FREE: &str = "MemFree:";
const MEM_AVAILABLE: &str = "MemAvailable:";
const SWAP_TOTAL: &str = "SwapTotal:";
const SWAP_FREE: &str = "SwapFree:";
const MEM_BUFFERS: &str = "Buffers:";
const MEM_CACHED: &str = "Cached:";
const MEM_ACTIVE: &str = "Active:";
const MEM_INACTIVE: &str = "Inactive:";
const MEM_SHARED: &str = "Shmem:";
#[derive(Debug, Default, Eq, PartialEq, Copy, Clone)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct Memory {
pub total: u64,
pub free: u64,
pub available: u64,
pub buffers: u64,
pub cached: u64,
pub active: u64,
pub inactive: u64,
pub shared: u64,
}
impl Memory {
pub fn from_proc() -> Result<Memory> {
let mut mem = Memory::default();
for line in SysPath::ProcMemInfo.read()?.lines() {
let mut elems = line.split_ascii_whitespace();
if let Some(p) = elems.next() {
let param = match p {
MEM_TOTAL => &mut mem.total,
MEM_FREE => &mut mem.free,
MEM_AVAILABLE => &mut mem.available,
MEM_BUFFERS => &mut mem.buffers,
MEM_CACHED => &mut mem.cached,
MEM_ACTIVE => &mut mem.active,
MEM_INACTIVE => &mut mem.inactive,
MEM_SHARED => &mut mem.shared,
_ => continue,
};
if let Some(v) = elems.next() {
*param = v
.parse::<u64>()
.map(|v| v * 1024) .map_err(|e| Error::InvalidInputError(v.to_string(), e.to_string()))?;
}
}
}
Ok(mem)
}
}
fn _mem_extract(out: &str, line: &str) -> Result<usize> {
Ok(out
.lines()
.filter(|l| l.starts_with(line))
.collect::<String>()
.split_ascii_whitespace()
.skip(1)
.take(1)
.collect::<String>()
.parse::<usize>()
.map_err(|e| Error::CommandParseError(e.to_string()))?
* 1024 as usize)
}
pub(crate) fn mem_extract(line: &str) -> Result<usize> {
_mem_extract(&SysPath::ProcMemInfo.read()?, &line)
}
pub fn memory_total() -> Result<usize> {
mem_extract(MEM_TOTAL)
}
pub fn memory_free() -> Result<usize> {
mem_extract(MEM_FREE)
}
pub fn swap_total() -> Result<usize> {
mem_extract(SWAP_TOTAL)
}
pub fn swap_free() -> Result<usize> {
mem_extract(SWAP_FREE)
}
pub fn memory() -> Result<Memory> {
Memory::from_proc()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn extracts_meminfo() {
assert_eq!(_mem_extract(MEMINFO, MEM_TOTAL), Ok(16712671232));
assert_eq!(_mem_extract(MEMINFO, MEM_AVAILABLE), Ok(14993084416));
assert_eq!(_mem_extract(MEMINFO, SWAP_TOTAL), Ok(0));
assert_eq!(_mem_extract(MEMINFO, SWAP_FREE), Ok(0));
}
}