pub mod battery;
pub mod btrfs;
pub mod diskstats;
pub mod drm;
pub mod hwmon;
pub mod mdstat;
pub mod meminfo;
pub mod mounts;
pub mod net;
pub mod procstat;
pub mod rapl;
use std::fs;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
pub struct SysRoots {
pub sys: PathBuf,
pub proc: PathBuf,
}
impl Default for SysRoots {
fn default() -> Self {
Self {
sys: PathBuf::from("/sys"),
proc: PathBuf::from("/proc"),
}
}
}
pub(crate) fn read_trimmed(path: &Path) -> Option<String> {
fs::read_to_string(path).ok().map(|s| s.trim().to_owned())
}
pub(crate) fn read_u64(path: &Path) -> Option<u64> {
read_trimmed(path)?.parse().ok()
}
pub(crate) fn read_i64(path: &Path) -> Option<i64> {
read_trimmed(path)?.parse().ok()
}
pub(crate) fn sorted_entries(dir: &Path) -> Vec<String> {
let mut names: Vec<String> = match fs::read_dir(dir) {
Ok(entries) => entries
.filter_map(|e| e.ok())
.filter_map(|e| e.file_name().into_string().ok())
.collect(),
Err(_) => Vec::new(),
};
names.sort_by(|a, b| natural_cmp(a, b));
names
}
pub(crate) fn natural_cmp(a: &str, b: &str) -> std::cmp::Ordering {
fn split(s: &str) -> (&str, Option<u64>) {
let digits_start = s
.char_indices()
.rev()
.take_while(|(_, c)| c.is_ascii_digit())
.last()
.map(|(i, _)| i)
.unwrap_or(s.len());
let (prefix, digits) = s.split_at(digits_start);
(prefix, digits.parse().ok())
}
let (pa, na) = split(a);
let (pb, nb) = split(b);
pa.cmp(pb).then(na.cmp(&nb)).then_with(|| a.cmp(b))
}
#[cfg(test)]
pub(crate) mod testutil {
use std::fs;
use std::path::Path;
pub fn write(root: &Path, rel: &str, content: &str) {
let path = root.join(rel);
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(path, content).unwrap();
}
pub fn symlink(root: &Path, rel: &str, target: &Path) {
let path = root.join(rel);
fs::create_dir_all(path.parent().unwrap()).unwrap();
std::os::unix::fs::symlink(target, path).unwrap();
}
}
#[cfg(test)]
mod tests {
use super::natural_cmp;
#[test]
fn natural_order_sorts_numbers_numerically() {
let mut names = vec!["hwmon10", "hwmon2", "hwmon1", "fan"];
names.sort_by(|a, b| natural_cmp(a, b));
assert_eq!(names, vec!["fan", "hwmon1", "hwmon2", "hwmon10"]);
}
}