1use indexmap::IndexMap;
4
5use crate::net_stats::get_device_string_to_name_map;
6
7#[macro_export]
8macro_rules! test_debug {
9 ($($arg:tt)*) => {{
10 if std::env::var("RUST_TEST").is_ok() {
11 println!($($arg)*);
12 }
13 }};
14}
15
16pub fn filter_zero_counters(
18 stats: &IndexMap<String, (u64, u64)>,
19 interfaces: &[String],
20) -> Vec<String> {
21 interfaces
22 .iter()
23 .filter(|iface| {
24 if let Some(&(rx, tx)) = stats.get(*iface) {
25 rx != 0 || tx != 0
26 } else {
27 false
28 }
29 })
30 .cloned()
31 .collect()
32}
33
34pub fn shorten_name(name: &str) -> String {
36 if name.len() > 16 {
37 let start = name.find('\\').map(|i| i + 1).unwrap_or(0);
38 let name = &name[start..];
39
40 if let Some(start_idx) = name.find("TCPIP_{") {
42 let prefix_len = start_idx + 11; if prefix_len < name.len() {
44 let suffix_start = name.len().saturating_sub(5);
45 let prefix = &name[start_idx..prefix_len];
46 let suffix = &name[suffix_start..];
47
48 return format!("{}..{}", prefix, suffix);
49 }
50 }
51
52 if name.len() > 13 {
54 return format!("{}...", &name[..13]);
55 }
56 }
57 name.to_string()
59}
60
61pub fn print_headers(
63 interfaces: &[String],
64 writer: &mut dyn std::io::Write,
65 hide_zero_counters: bool,
66 stats: &IndexMap<String, (u64, u64)>,
67) -> std::io::Result<()> {
68 let interfaces = if hide_zero_counters {
69 filter_zero_counters(stats, interfaces)
70 } else {
71 interfaces.to_vec()
72 };
73
74 if interfaces.is_empty() {
75 return Ok(());
76 }
77
78 let width = 18; for (i, interface) in interfaces.iter().enumerate() {
80 let short_interface = shorten_name(interface);
81 let padded_name = format!("{:^width$}", short_interface, width = width);
82 write!(writer, "{}", padded_name)?;
83 if i < interfaces.len() - 1 {
84 write!(writer, " ")?; }
86 }
87 writeln!(writer)?;
88
89 for (i, _) in interfaces.iter().enumerate() {
90 write!(writer, "{:>8} {:>8}", "KB/s in", "KB/s out")?;
91 if i < interfaces.len() - 1 {
92 write!(writer, " ")?; }
94 }
95 writeln!(writer)?;
96
97 Ok(())
98}
99
100pub fn print_stats(
102 previous: &IndexMap<String, (u64, u64)>,
103 current: &IndexMap<String, (u64, u64)>,
104 interfaces: &[String],
105 writer: &mut dyn std::io::Write,
106 hide_zero_counters: bool,
107) -> std::io::Result<()> {
108 let interfaces = if hide_zero_counters {
109 filter_zero_counters(current, interfaces)
110 } else {
111 interfaces.to_vec()
112 };
113
114 for (i, interface) in interfaces.iter().enumerate() {
115 if let (Some(&(prev_rx, prev_tx)), Some(&(cur_rx, cur_tx))) =
116 (previous.get(interface), current.get(interface))
117 {
118 let rx_kbps = (cur_rx.saturating_sub(prev_rx)) as f64 / 1024.0;
119 let tx_kbps = (cur_tx.saturating_sub(prev_tx)) as f64 / 1024.0;
120 write!(writer, "{:>8.2} {:>8.2}", rx_kbps, tx_kbps)?;
121 if i < interfaces.len() - 1 {
122 write!(writer, " ")?; }
124 }
125 }
126 writeln!(writer)?;
127
128 Ok(())
129}
130
131pub fn print_net_devices(stats: &IndexMap<String, (u64, u64)>) {
133 let adapter_name_map = get_device_string_to_name_map();
135 if adapter_name_map.len() > 0 {
136 println!("{} adapters:", adapter_name_map.len());
137 for guid in adapter_name_map.keys() {
138 if let Some(friendly_name) = adapter_name_map.get(guid) {
139 println!("{} {}", guid, friendly_name);
140 }
141 }
142 }
143
144 println!("{} interfaces:", stats.len());
146
147 for iface in stats.keys() {
149 match adapter_name_map.get(iface) {
151 Some(adapter_name) => println!("{} ({})", iface, adapter_name),
152 None => println!("{}", iface),
153 }
154 }
155}