ifstat_rs/
opts.rs

1use clap::Parser;
2use std::env;
3
4const AUTHOR: &str = env!("CARGO_PKG_AUTHORS");
5const VERSION: &str = env!("CARGO_PKG_VERSION");
6const REPO_URL: &str = env!("CARGO_PKG_REPOSITORY");
7const LICENSE: &str = env!("CARGO_PKG_LICENSE");
8
9lazy_static::lazy_static! {
10    static ref LONG_VERSION: String = {
11        // Get build config
12        let commit_hash = option_env!("VERGEN_GIT_SHA").unwrap_or("unknown");
13        let git_dirty = option_env!("VERGEN_GIT_DIRTY").unwrap_or("unknown");
14        let build_timestamp = option_env!("VERGEN_BUILD_TIMESTAMP").unwrap_or("unknown");
15        let rust_version = option_env!("VERGEN_RUSTC_SEMVER").unwrap_or("unknown");
16        let target = env::var("TARGET").unwrap_or_else(|_| "unknown".to_string());
17
18        // Build git commit string
19        let commit_str = if commit_hash.starts_with("VERGEN") {
20            "non-git build".to_string()
21        } else {
22            let suffix = if git_dirty == "false" { "" } else { "-dirty" };
23            format!("{}{}", commit_hash, suffix)
24        };
25
26        format!(
27            "A tool to report network interface statistics.\n\n\
28            Author: {}\n\
29            Repo: {}\n\
30            License: {}\n\
31            Commit: {}\n\
32            Build Timestamp: {}\n\
33            Rust Version: {}\n\
34            Compilation Target: {}",
35            AUTHOR, REPO_URL, LICENSE, commit_str, build_timestamp, rust_version, target
36        )
37    };
38}
39
40#[derive(Parser)]
41#[clap(version = VERSION, author = AUTHOR, long_version = LONG_VERSION.as_str())]
42pub struct Opts {
43    /// Interfaces to monitor, separated by commas (e.g., "eth0,lo")
44    #[clap(short, long)]
45    pub interfaces: Option<String>,
46
47    /// Enables monitoring of all interfaces found for which statistics are available.
48    #[clap(short = 'a')]
49    pub monitor_all: bool,
50
51    /// Enables monitoring of loopback interfaces for which statistics are available.
52    #[clap(short = 'l')]
53    pub monitor_loopback: bool,
54
55    /// Hides interfaces with zero counters (default false on Linux/Mac, true in Windows).
56    #[clap(
57        short = 'z',
58        default_value_if("cfg(target_os = \"windows\")", "false", "true")
59    )]
60    pub hide_zero_counters: bool,
61
62    /// List all available network interfaces and exit
63    #[clap(long)]
64    pub list_interfaces: bool,
65
66    /// Delay before the first measurement in seconds (must be >= 0 if set)
67    #[arg(long, value_parser = parse_non_negative_f64)]
68    pub first_measurement: Option<f64>,
69
70    /// Delay between updates in seconds (must be > 0)
71    #[arg(default_value = "1", value_parser = parse_positive_f64)]
72    pub delay: f64,
73
74    /// Number of updates before stopping (must be > 0 if set)
75    #[arg(value_parser = parse_positive_u64)]
76    pub count: Option<u64>,
77}
78
79fn parse_positive_f64(src: &str) -> Result<f64, String> {
80    let val: f64 = src
81        .parse()
82        .map_err(|_| format!("`{}` is not a valid number", src))?;
83    if val <= 0.0 {
84        Err(format!("`{}` must be greater than 0", src))
85    } else {
86        Ok(val)
87    }
88}
89
90fn parse_non_negative_f64(src: &str) -> Result<f64, String> {
91    let val: f64 = src
92        .parse()
93        .map_err(|_| format!("`{}` is not a valid number", src))?;
94    if val < 0.0 {
95        Err(format!("`{}` must be greater than or equal to 0", src))
96    } else {
97        Ok(val)
98    }
99}
100
101fn parse_positive_u64(src: &str) -> Result<u64, String> {
102    let val: u64 = src
103        .parse()
104        .map_err(|_| format!("`{}` is not a valid number > 0", src))?;
105    if val == 0 {
106        Err(format!("`{}` must be greater than 0", src))
107    } else {
108        Ok(val)
109    }
110}