rusty-ping 0.1.0

A pretty ping/ICMP utility
pub struct Stats {
    /// Number of received packets (better names: `packets_received` or `received_count`)
    pub received: usize,
    /// Number of lost packets (total - received) (better names: `packets_lost` or `lost_count`)
    pub lost: usize,

    // Round-Time Trip
    pub min_rtt: u64,
    pub max_rtt: u64,
    pub avg_rtt: f64,
    /// Mean absolute difference (deviation) from the average
    pub mad_rtt: f64,
}

pub fn compute_stats(states: &[crate::state::State]) -> Option<Stats> {
    let mut rtts: Vec<u64> = Vec::new();

    let received = states
        .iter()
        .filter(|state| matches!(state, crate::state::State::Received { .. } | crate::state::State::NotYetReceived  { .. } ))
        .count();
    let lost = states.len() - received;

    if received == 0 {
        return None;
    }

    for state in states {
        if let crate::state::State::Received { rtt } = state {
            rtts.push(*rtt);
        }
    }

    // RTT stats
    let min_rtt = rtts.iter().min().copied().unwrap_or(0);
    let max_rtt = rtts.iter().max().copied().unwrap_or(0);

    let sum_rtt: u64 = rtts.iter().sum();
    let avg_rtt = sum_rtt as f64 / rtts.len() as f64;

    let mad_rtt: f64 = rtts
        .iter()
        .map(|&x| (x as f64 - avg_rtt).abs())
        .sum::<f64>()
        / rtts.len() as f64;

    Some(Stats {
        received,
        lost,
        min_rtt,
        max_rtt,
        avg_rtt,
        mad_rtt,
    })
}