infomgr 0.2.2

Show system information.
Documentation
use serde::{Deserialize, Serialize};
use std::fmt;
use std::fs;
use std::io::{BufRead, BufReader, Error, ErrorKind, Result};
use std::ops::Sub;

#[derive(Deserialize, Serialize, Debug, Copy, Clone, Default)]
pub struct CpuTime {
    pub usr: i64,
    pub nice: i64,
    pub system: i64,
    pub idle: i64,
    pub iowait: i64,
    pub irq: i64,
    pub softirq: i64,
}

impl fmt::Display for CpuTime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s: Vec<String> = Vec::new();
        s.push(format!("{} usr,", self.usr));
        s.push(format!("{} nice,", self.nice));
        s.push(format!("{} system,", self.system));
        s.push(format!("{} idle,", self.idle));
        s.push(format!("{} iowait,", self.iowait));
        s.push(format!("{} irq,", self.irq));
        s.push(format!("{} softirq,", self.softirq));
        write!(f, "CPU: {}", s.join(" ").trim_end_matches(','))
    }
}

impl CpuTime {
    pub fn load() -> Result<Self> {
        let f = fs::OpenOptions::new()
            .read(true)
            .open("/proc/stat")
            .map_err(|e| Error::new(ErrorKind::Other, format!("{}", e)))?;

        let mut reader = BufReader::new(f);
        loop {
            let mut line = String::new();
            reader.read_line(&mut line)?;
            let mut entries = line.split_whitespace();
            if let Some("cpu") = entries.next() {
                let mut value = || -> i64 { entries.next().unwrap().parse().unwrap() };

                return Ok(CpuTime {
                    usr: value(),
                    nice: value(),
                    system: value(),
                    idle: value(),
                    iowait: value(),
                    irq: value(),
                    softirq: value(),
                });
            }
        }
    }

    pub fn new() -> Result<Self> {
        CpuTime::load()
    }
}

impl Sub for CpuTime {
    type Output = CpuTimeDiff;

    fn sub(self, other: Self) -> Self::Output {
        let diff = |a: i64, b: i64| -> f32 { (a - b).abs() as f32 };

        CpuTimeDiff {
            usr: diff(self.usr, other.usr),
            system: diff(self.system, other.system),
            nice: diff(self.nice, other.nice),
            idle: diff(self.idle, other.idle),
            iowait: diff(self.iowait, other.iowait),
            irq: diff(self.irq, other.irq),
            softirq: diff(self.softirq, other.softirq),
        }
    }
}

pub struct CpuTimeDiff {
    pub usr: f32,
    pub nice: f32,
    pub system: f32,
    pub idle: f32,
    pub iowait: f32,
    pub irq: f32,
    pub softirq: f32,
}

impl CpuTimeDiff {
    pub fn total(&self) -> f32 {
        self.usr + self.system + self.nice + self.idle + self.iowait + self.irq + self.softirq
    }

    pub fn cpu_report(&mut self) -> CpuReport {
        let total = self.total();
        CpuReport {
            usr: Some(self.usr / total),
            sys: Some(self.system / total),
            nic: Some(self.nice / total),
            idle: Some(self.idle / total),
            io: Some(self.iowait / total),
            irq: Some(self.irq / total),
            sirq: Some(self.softirq / total),
        }
    }
}

#[derive(Deserialize, Serialize, Debug, Copy, Clone, Default)]
pub struct CpuReport {
    pub usr: Option<f32>,
    pub sys: Option<f32>,
    pub nic: Option<f32>,
    pub idle: Option<f32>,
    pub io: Option<f32>,
    pub irq: Option<f32>,
    pub sirq: Option<f32>,
}

impl fmt::Display for CpuReport {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut s: Vec<String> = Vec::new();
        let round_up = |f: f32| -> f32 { (f * 1000_f32).round() / 10_f32 };

        if let Some(a) = self.usr {
            s.push(format!("{} us,", round_up(a)));
        }

        if let Some(a) = self.sys {
            s.push(format!("{} sy,", round_up(a)));
        }

        if let Some(a) = self.nic {
            s.push(format!("{} ni,", round_up(a)));
        }

        if let Some(a) = self.idle {
            s.push(format!("{} id,", round_up(a)));
        }

        if let Some(a) = self.io {
            s.push(format!("{} io,", round_up(a)));
        }

        if let Some(a) = self.irq {
            s.push(format!("{} irq,", round_up(a)));
        }

        if let Some(a) = self.sirq {
            s.push(format!("{} sirq,", round_up(a)));
        }

        write!(f, "CPU(%): {}", s.join(" ").trim_end_matches(','))
    }
}