modcli/
validate.rs

1//! Lightweight validation helpers for common CLI patterns.
2
3use crate::args;
4use crate::error::ModCliError;
5use std::path::Path;
6use std::str::FromStr;
7
8/// Ensure a key is present: `--key` (flag) or `--key <val>` / `--key=<val>`.
9pub fn require(argsv: &[String], name: &str) -> Result<(), ModCliError> {
10    if args::flag(argsv, name) || args::get_string(argsv, name).is_some() {
11        Ok(())
12    } else {
13        Err(ModCliError::InvalidUsage(format!(
14            "missing required argument: {name}"
15        )))
16    }
17}
18
19/// Parse a typed value from `--key`, ensuring it falls in an optional inclusive range.
20pub fn parse_in_range<T>(
21    argsv: &[String],
22    name: &str,
23    min: Option<T>,
24    max: Option<T>,
25) -> Result<T, ModCliError>
26where
27    T: FromStr + PartialOrd + Copy + std::fmt::Display,
28{
29    let val: T = args::get_int(argsv, name)?; // uses FromStr
30    if let Some(lo) = min {
31        if val < lo {
32            return Err(ModCliError::InvalidUsage(format!(
33                "{name} below minimum ({val} < {lo})"
34            )));
35        }
36    }
37    if let Some(hi) = max {
38        if val > hi {
39            return Err(ModCliError::InvalidUsage(format!(
40                "{name} above maximum ({val} > {hi})"
41            )));
42        }
43    }
44    Ok(val)
45}
46
47/// Validate that a path exists (file or dir).
48pub fn path_exists(p: &str) -> Result<(), ModCliError> {
49    if Path::new(p).exists() {
50        Ok(())
51    } else {
52        Err(ModCliError::InvalidUsage(format!(
53            "path does not exist: {p}"
54        )))
55    }
56}
57
58/// Validate that a path is a file.
59pub fn path_is_file(p: &str) -> Result<(), ModCliError> {
60    let path = Path::new(p);
61    if path.is_file() {
62        Ok(())
63    } else {
64        Err(ModCliError::InvalidUsage(format!("not a file: {p}")))
65    }
66}
67
68/// Validate that a path is a directory.
69pub fn path_is_dir(p: &str) -> Result<(), ModCliError> {
70    let path = Path::new(p);
71    if path.is_dir() {
72        Ok(())
73    } else {
74        Err(ModCliError::InvalidUsage(format!("not a directory: {p}")))
75    }
76}