Linux MemInfo
![GitHub source size](https://img.shields.io/github/languages/code-size/marcoradocchia/linux-meminfo?color=ea6962&logo=github)
![GitHub open issues](https://img.shields.io/github/issues-raw/marcoradocchia/linux-meminfo?color=%23d8a657&logo=github)
![GitHub open pull requests](https://img.shields.io/github/issues-pr-raw/marcoradocchia/linux-meminfo?color=%2389b482&logo=github)
![GitHub sponsors](https://img.shields.io/github/sponsors/marcoradocchia?color=%23d3869b&logo=github)
![GitHub license](https://img.shields.io/github/license/marcoradocchia/linux-meminfo?color=%23e78a4e)
![Crates.io downloads](https://img.shields.io/crates/d/linux-meminfo?label=crates.io%20downloads&color=%23a9b665&logo=rust)
![Crates.io version](https://img.shields.io/crates/v/linux-meminfo?logo=rust&color=%23d8a657)
This library provides easy and low level access to `meminfo`, the _pseudofile_
placed by the Linux kernel inside the `proc` _pseudo-filesystem_ (for more
information, see the `proc`
[manpage](https://man7.org/linux/man-pages/man5/proc.5.html)).
The public API is built around the `MemInfo` type, a struct responsible for
retrieving memory-related information about the system. Calling its constructor
opens the `/proc/meminfo` pseudofile and reads its data into an internal buffer.
Having `MemInfo` to own both the open file and a buffer of its data allows
separation of concerns between _reading_ from the pseudofile, _managing_ and
_parsing_ the buffered data.
The parser implementation responsible for parsing `/proc/meminfo` entries
works exclusively on string slices, just owning a reference to the pseudofile
buffered bytes. This allows for efficient, **zero-allocation** parsing.
## Examples
The following example shows the most basic usage of the `MemInfo` API. First
we construct a new instance, which translates to `/proc/meminfo` being opened
and read into the internal buffer; then we call the `MemInfo::parse`, which
returns a **lazy** iterator over parsed entries, in this case represented by
the `MemInfoEntry` type. The iterator being lazy meaning it parses a new
entry on each call to the `next` method. In other words: _you only pay for the
entries you parse_.
```rust
use std::error;
use meminfo::MemInfo;
fn main() -> Result<(), Box> {
let mut meminfo = MemInfo::new()?;
let mut entries = meminfo.parse();
let mem_total = entries.next().unwrap();
assert_eq!("MemTotal", mem_total.label());
assert_eq!(Some("kB"), mem_total.unit());
println!("System's total usable RAM: {}kB", mem_total.size()?);
Ok(())
}
```
Users may have distinct use cases that call for regular retrieval of a
particular set of entries within the `/proc/meminfo` pseudofile. The
`MemInfo::parse_extended` efficiently addresses this requirement, extending
parsed entries with additional information pertaining to the byte range they
occupy in the file stream. This functionality allows users to selectively read
and parse specific entries as needed. Also, this way, the internal buffer can
be shrank to the capacity required to read in such entries, reducing the runtime
memory footprint of the program.
```rust
use std::io::SeekFrom;
use std::time::Duration;
use std::{error, thread};
use meminfo::{MemInfo, MemInfoError};
#[derive(Debug)]
struct MemAvailable {
size: usize,
start_pos: usize,
}
impl MemAvailable {
fn new(meminfo: &mut MemInfo) -> Result {
let mut entries = meminfo.parse_extended().skip(2);
let mem_available = entries.next().unwrap();
assert_eq!("MemAvailable", mem_available.label());
assert_eq!(Some("kB"), mem_available.unit());
let size = mem_available.size().unwrap();
let start_pos = mem_available.start_pos();
let capacity = mem_available.required_capacity();
drop(entries);
meminfo.clear();
meminfo.shrink_to(capacity);
Ok(MemAvailable { size, start_pos })
}
fn fetch(&mut self, meminfo: &mut MemInfo) -> Result<(), MemInfoError> {
let seek_pos = SeekFrom::Start(self.start_pos as u64);
meminfo.seek(seek_pos)?;
meminfo.clear();
meminfo.read()?;
let entry = meminfo.parse().next().unwrap();
self.size = entry.size().unwrap();
Ok(())
}
}
fn main() -> Result<(), Box> {
let mut meminfo = MemInfo::new()?;
let mut mem_available = MemAvailable::new(&mut meminfo)?;
loop {
println!("System's available RAM: {}kB", mem_available.size);
thread::sleep(Duration::from_secs(2));
mem_available.fetch(&mut meminfo)?;
}
}
```
## Usage
To use this library in your project, run the following command in your project
root directory:
```sh
cargo add linux-meminfo
```
## Features
By default, the `MemInfoEntry` and `MemInfoEntryExtended` constructors perform
UTF-8 validation on `/proc/meminfo` parsed data. Malformed data would cause
a panic in this case. However, enabling the `utf8-unchecked` feature removes
such validation, potentially increasing parsing performance. To achieve this,
the new constructors make use of unsafe code, thus the user should be aware
that malformed `/proc/meminfo` data would cause undefined behaviour.
To opt-in such feature, run the following command in your the project root
directory:
```sh
cargo add linux-meminfo --features=utf8-unchecked
```
## License
This library is licensed under the terms of the [GPLv3](LICENSE) license.
## Contributions
Any contribution is welcome and encouraged.