1use crate::unit::DataSize;
12use crate::util::read_to_string_mut;
13
14use std::path::Path;
15use std::{fs, io};
16
17#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Memory {
20 raw: String
21}
22
23impl Memory {
24
25 fn path() -> &'static Path {
26 Path::new("/proc/meminfo")
27 }
28
29 #[cfg(test)]
30 fn from_string(raw: String) -> Self {
31 Self {raw}
32 }
33
34 pub fn read() -> io::Result<Self> {
36 Ok(Self {
37 raw: fs::read_to_string(Self::path())?
38 })
39 }
40
41 pub fn reload(&mut self) -> io::Result<()> {
43 read_to_string_mut(Self::path(), &mut self.raw)
44 }
45
46 pub fn values<'a>(&'a self) -> impl Iterator<Item=(&'a str, &'a str)> {
48 self.raw.split('\n')
49 .filter_map(|line| {
50 let mut iter = line.splitn(2, ':');
52 let (key, value) = (iter.next()?, iter.next()?);
53 Some((key.trim(), value.trim()))
54 })
55 }
56
57 pub fn keys<'a>(&'a self) -> impl Iterator<Item=&'a str> {
59 self.values()
60 .map(|(k, _)| k)
61 }
62
63 pub fn value<'a>(&'a self, key: &str) -> Option<&'a str> {
65 self.values()
66 .find_map(|(k, v)| k.eq_ignore_ascii_case(key).then(|| v))
67 }
68
69 pub fn size_value<'a>(&'a self, key: &str) -> Option<DataSize> {
71 self.value(key)
72 .and_then(DataSize::from_str)
73 }
74
75 pub fn total_memory(&self) -> Option<DataSize> {
77 self.size_value("MemTotal")
78 }
79
80 pub fn free_memory(&self) -> Option<DataSize> {
82 self.size_value("MemFree")
83 }
84
85 pub fn available_memory(&self) -> Option<DataSize> {
87 self.size_value("MemAvailable")
88 }
89
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use crate::unit::DataSizeUnit;
96
97 fn memory_info() -> Memory {
98 Memory::from_string("\
99MemTotal: 32853280 kB
100MemFree: 919776 kB
101MemAvailable: 28781828 kB
102Buffers: 298460 kB
103Cached: 27104800 kB
104SwapCached: 168 kB
105Active: 7764012 kB
106Inactive: 22289624 kB
107Active(anon): 2257064 kB
108Inactive(anon): 624500 kB
109Active(file): 5506948 kB
110Inactive(file): 21665124 kB
111Unevictable: 16 kB
112Mlocked: 16 kB
113SwapTotal: 2097148 kB
114SwapFree: 2094844 kB
115Dirty: 360 kB
116Writeback: 0 kB
117AnonPages: 2650504 kB
118Mapped: 760008 kB
119Shmem: 231188 kB
120KReclaimable: 1154740 kB
121Slab: 1529684 kB
122SReclaimable: 1154740 kB
123SUnreclaim: 374944 kB
124KernelStack: 21600 kB
125PageTables: 31948 kB
126NFS_Unstable: 0 kB
127Bounce: 0 kB
128WritebackTmp: 0 kB
129CommitLimit: 18523788 kB
130Committed_AS: 9191380 kB
131VmallocTotal: 34359738367 kB
132VmallocUsed: 62668 kB
133VmallocChunk: 0 kB
134Percpu: 37376 kB
135HardwareCorrupted: 0 kB
136AnonHugePages: 0 kB
137ShmemHugePages: 0 kB
138ShmemPmdMapped: 0 kB
139FileHugePages: 0 kB
140FilePmdMapped: 0 kB
141HugePages_Total: 0
142HugePages_Free: 0
143HugePages_Rsvd: 0
144HugePages_Surp: 0
145Hugepagesize: 2048 kB
146Hugetlb: 0 kB
147DirectMap4k: 922564 kB
148DirectMap2M: 10518528 kB
149DirectMap1G: 22020096 kB\
150 ".into())
151 }
152
153 #[test]
154 fn total_memory() {
155 let mem_info = memory_info();
156 let total_memory = mem_info.total_memory().unwrap();
157 assert_eq!(total_memory.to(&DataSizeUnit::Kb), 32853280.0);
158 }
159
160}