probes 0.7.1

Library to read out system stats from a machine running Unix
Documentation
extern crate libc;

pub mod cpu;
pub mod disk_stats;
pub mod disk_usage;
mod error;
pub mod load;
pub mod memory;
pub mod network;
pub mod process_memory;

use std::fs;
use std::io;
use std::io::BufRead;
use std::io::Read;
use std::path::Path;
use std::result;
use std::time::SystemTime;

pub use crate::error::ProbeError;

pub type Result<T> = result::Result<T, error::ProbeError>;

#[inline]
fn file_to_string(path: &Path) -> Result<String> {
    let mut file = fs::File::open(path).map_err(|e| ProbeError::IO(e, path_to_string(path)))?;
    let mut read = String::new();
    file.read_to_string(&mut read)
        .map_err(|e| ProbeError::IO(e, path_to_string(path)))?;
    Ok(read)
}

#[inline]
fn file_to_buf_reader(path: &Path) -> Result<io::BufReader<fs::File>> {
    fs::File::open(path)
        .map_err(|e| ProbeError::IO(e, path_to_string(path)))
        .and_then(|f| Ok(io::BufReader::new(f)))
}

#[inline]
fn path_to_string(path: &Path) -> String {
    path.to_string_lossy().to_string()
}

#[inline]
fn calculate_time_difference(first_time: u64, second_time: u64) -> Result<u64> {
    if first_time > second_time {
        Err(ProbeError::InvalidInput(format!(
            "first time {} was after second time {}",
            first_time, second_time
        )))
    } else {
        Ok(second_time - first_time)
    }
}

#[inline]
fn time_adjusted(
    field_name: &str,
    first_value: u64,
    second_value: u64,
    time_difference_ns: u64,
) -> Result<u64> {
    if first_value < second_value {
        Err(ProbeError::UnexpectedContent(format!(
            "First value {} was lower than second value {} for '{}'",
            first_value, second_value, field_name
        )))
    } else {
        Ok(
            ((first_value - second_value) as f64 / time_difference_ns as f64 * 60_000_000_000.0)
                as u64,
        )
    }
}

#[inline]
fn parse_u64(segment: &str) -> Result<u64> {
    segment
        .parse()
        .map_err(|_| ProbeError::UnexpectedContent(format!("Could not parse '{}' as u64", segment)))
}

#[inline]
fn dir_exists(path: &Path) -> bool {
    path.exists() && path.is_dir()
}

#[inline]
fn read_file_value_as_u64(path: &Path) -> Result<u64> {
    let mut reader = file_to_buf_reader(path)?;
    let mut line = String::new();
    reader
        .read_line(&mut line)
        .map_err(|e| ProbeError::IO(e, path_to_string(path)))?;
    parse_u64(&line.trim())
}

#[inline]
fn precise_time_ns() -> u64 {
    return SystemTime::now()
        .duration_since(SystemTime::UNIX_EPOCH)
        .unwrap()
        .as_nanos() as u64;
}

fn bytes_to_kilo_bytes(bytes: u64) -> u64 {
    bytes.checked_div(1024).unwrap_or(0)
}

#[cfg(test)]
mod tests {
    use crate::error::ProbeError;

    #[test]
    fn test_calculate_time_difference() {
        assert_eq!(100, super::calculate_time_difference(100, 200).unwrap());
        assert!(super::calculate_time_difference(200, 100).is_err());
    }

    #[test]
    fn test_time_adjusted() {
        assert_eq!(
            1200,
            super::time_adjusted("field", 2400, 1200, 60_000_000_000).unwrap()
        );
        assert_eq!(
            2400,
            super::time_adjusted("field", 2400, 1200, 30_000_000_000).unwrap()
        );
        assert_eq!(
            4800,
            super::time_adjusted("field", 2400, 1200, 15_000_000_000).unwrap()
        );
    }

    #[test]
    fn test_time_adjusted_first_higher_than_lower() {
        match super::time_adjusted("field", 1200, 2400, 60_000_000_000) {
            Err(ProbeError::UnexpectedContent(_)) => (),
            r => panic!("Unexpected result: {:?}", r),
        }
    }

    #[test]
    fn test_parse_u64() {
        assert_eq!(100, super::parse_u64("100").unwrap());
        assert!(super::parse_u64("something").is_err());
    }
}