use crate::state::State; use crate::stats::Stats; use std::net::IpAddr; struct SymbolTableElement { fg: &'static str, bg: &'static str, character: &'static str, } const GREEN_FG: &str = "\x1b[32m"; const ORANGE_FG: &str = "\x1b[38;5;208m"; const RED_FG: &str = "\x1b[31m"; const BLACK_BG: &str = "\x1b[40m"; const GREEN_BG: &str = "\x1b[42m"; const ORANGE_BG: &str = "\x1b[48;5;208m"; const ERASE_LINE_END: &str = "\x1b[0K"; const RESET: &str = "\x1b[0m"; const CHARS_TABLE: [SymbolTableElement; 25] = [ SymbolTableElement { fg: GREEN_FG, bg: BLACK_BG, character: "▁", }, SymbolTableElement { fg: GREEN_FG, bg: BLACK_BG, character: "▂", }, SymbolTableElement { fg: GREEN_FG, bg: BLACK_BG, character: "▃", }, SymbolTableElement { fg: GREEN_FG, bg: BLACK_BG, character: "▄", }, SymbolTableElement { fg: GREEN_FG, bg: BLACK_BG, character: "▅", }, SymbolTableElement { fg: GREEN_FG, bg: BLACK_BG, character: "▆", }, SymbolTableElement { fg: GREEN_FG, bg: BLACK_BG, character: "▇", }, SymbolTableElement { fg: GREEN_FG, bg: BLACK_BG, character: "█", }, SymbolTableElement { fg: ORANGE_FG, bg: GREEN_BG, character: "▁", }, SymbolTableElement { fg: ORANGE_FG, bg: GREEN_BG, character: "▂", }, SymbolTableElement { fg: ORANGE_FG, bg: GREEN_BG, character: "▃", }, SymbolTableElement { fg: ORANGE_FG, bg: GREEN_BG, character: "▄", }, SymbolTableElement { fg: ORANGE_FG, bg: GREEN_BG, character: "▅", }, SymbolTableElement { fg: ORANGE_FG, bg: GREEN_BG, character: "▆", }, SymbolTableElement { fg: ORANGE_FG, bg: GREEN_BG, character: "▇", }, SymbolTableElement { fg: ORANGE_FG, bg: GREEN_BG, character: "█", }, SymbolTableElement { fg: RED_FG, bg: ORANGE_BG, character: "▁", }, SymbolTableElement { fg: RED_FG, bg: ORANGE_BG, character: "▂", }, SymbolTableElement { fg: RED_FG, bg: ORANGE_BG, character: "▃", }, SymbolTableElement { fg: RED_FG, bg: ORANGE_BG, character: "▄", }, SymbolTableElement { fg: RED_FG, bg: ORANGE_BG, character: "▅", }, SymbolTableElement { fg: RED_FG, bg: ORANGE_BG, character: "▆", }, SymbolTableElement { fg: RED_FG, bg: ORANGE_BG, character: "▇", }, SymbolTableElement { fg: RED_FG, bg: ORANGE_BG, character: "█", }, SymbolTableElement { fg: RED_FG, bg: BLACK_BG, character: "?", }, ]; #[allow(clippy::unusual_byte_groupings)] const TO_HIDE_LEGEND_ELEMENTS: [u32; 26] = [ 0b000_000_000_000_0_000_000_000_000, 0b000_000_000_000_1_000_000_000_000, 0b000_000_001_000_0_000_100_000_000, 0b000_000_100_000_1_000_001_000_000, 0b000_010_000_100_0_001_000_010_000, 0b000_100_010_000_1_000_010_001_000, // 5 0b001_000_100_010_0_010_001_000_100, 0b010_001_000_100_1_001_000_100_010, 0b010_010_001_001_0_100_100_010_010, 0b010_010_010_010_1_010_010_010_010, 0b001_010_100_101_0_101_001_010_100, // 10 0b010_101_010_100_1_001_010_101_010, 0b010_101_010_101_0_101_010_101_010, 0b011_010_101_010_1_010_101_010_110, 0b011_010_101_011_0_110_101_010_110, 0b011_101_011_010_1_010_110_101_110, // 15 0b011_101_101_101_0_101_101_101_110, 0b011_101_110_110_1_011_011_101_110, 0b011_110_111_011_0_110_111_011_110, 0b011_101_111_011_1_110_111_101_110, 0b011_111_011_111_0_111_110_111_110, // 20 0b011_111_110_111_1_111_011_111_110, 0b011_111_111_111_0_111_111_111_110, 0b011_111_111_111_1_111_111_111_110, 0b111_111_111_111_1_111_111_111_110, 0b111_111_111_111_1_111_111_111_111, // 25 ]; const LEN_BY_NB_ELEMENT: [u32; 26] = [ 139, 133, 128, 122, 117, 111, 105, 100, 94, 88, 83, 78, 72, 66, 60, 55, 50, 44, 38, 32, 27, 21, 16, 10, 4, 0, ]; pub fn print_status_line(target_str: &String, ip: &IpAddr) { println!("PING {} ({})", target_str, ip); } pub fn print_legend_line() { let nb_cols: u32 = if let Some((w, _)) = term_size::dimensions() { w as u32 } else { 0 }; let mut index = 0; while LEN_BY_NB_ELEMENT[index] > nb_cols { index += 1 } let nb_elements_to_skip = index; for (index, element) in CHARS_TABLE.iter().enumerate() { if (TO_HIDE_LEGEND_ELEMENTS[nb_elements_to_skip]) & (1 << index) != 0 { continue; } print!( "{} {}{}{}\x1b[0m ", 10 * index, element.fg, element.bg, element.character ); } println!("{}", ERASE_LINE_END); } // TODO: Simplify this function pub fn print_ping_line(states: &Vec) { for state in states { match state { State::Received { rtt, .. } => { let (fg, bg, symbol) = get_symbol_and_colors_for_rrt(*rtt); print!("{}{}{}{}", fg, bg, symbol, RESET); } State::Lost => { let (fg, bg, symbol) = get_symbol_and_colors_for_rrt(250); print!("{}{}{}{}", fg, bg, symbol, RESET); } State::NotYetReceived { .. } => { // fg grey, bg black print!("\x1b[35;40m?\x1b[0m"); } State::SendError => { print!("!"); } } } println!("{}", ERASE_LINE_END); } fn get_symbol_and_colors_for_rrt(rrt: u64) -> (&'static str, &'static str, &'static str) { let index: usize = if rrt >= 240 { 24 } else { rrt / 10 } as usize; let SymbolTableElement { fg, bg, character } = CHARS_TABLE[index]; (fg, bg, character) } pub fn print_stats(stats: &Stats) { let total = stats.lost + stats.received; let percent_lost = if total > 0 { (stats.lost as f64 / total as f64) * 100.0 } else { 0.0 }; let mad_rtt_rounded = stats.mad_rtt.round() as u64; let mean_rtt_round = stats.avg_rtt.round() as u32; println!( "{}/{} ({:.1}%) | ⌊{}⌋ ⌈{}⌉ [{}] [Δ{}]ms{}", stats.lost, total, percent_lost, stats.min_rtt, stats.max_rtt, mean_rtt_round, mad_rtt_rounded, ERASE_LINE_END ); }