robotrt-cli 0.1.0-beta.1

RobotRT modular robotics runtime and middleware components.
use std::path::PathBuf;

pub fn parse_report_path(args: &[String], default_path: &str) -> Result<PathBuf, String> {
    let mut idx = 0usize;
    while idx < args.len() {
        if args[idx] == "--report" {
            if idx + 1 >= args.len() {
                return Err(String::from("missing value for --report"));
            }
            return Ok(PathBuf::from(&args[idx + 1]));
        }
        idx += 1;
    }
    Ok(PathBuf::from(default_path))
}

pub fn has_flag(args: &[String], flag: &str) -> bool {
    args.iter().any(|arg| arg == flag)
}

pub fn is_help_token(arg: &str) -> bool {
    matches!(arg, "help" | "--help" | "-h")
}

pub fn option_value(args: &[String], option: &str) -> Option<String> {
    let mut idx = 0usize;
    while idx + 1 < args.len() {
        if args[idx] == option {
            return Some(args[idx + 1].clone());
        }
        idx += 1;
    }
    None
}

pub fn parse_usize_option(args: &[String], option: &str, default: usize) -> Result<usize, String> {
    let Some(raw) = option_value(args, option) else {
        return Ok(default);
    };
    raw.parse::<usize>()
        .map_err(|err| format!("invalid value for {option}: {raw} ({err})"))
}

pub fn parse_u64_option(args: &[String], option: &str, default: u64) -> Result<u64, String> {
    let Some(raw) = option_value(args, option) else {
        return Ok(default);
    };
    raw.parse::<u64>()
        .map_err(|err| format!("invalid value for {option}: {raw} ({err})"))
}

pub fn first_positional(args: &[String]) -> Option<String> {
    let mut idx = 0usize;
    while idx < args.len() {
        let token = &args[idx];
        if token.starts_with('-') {
            if option_takes_value(token) {
                idx += 2;
            } else {
                idx += 1;
            }
            continue;
        }
        return Some(token.clone());
    }
    None
}

fn option_takes_value(option: &str) -> bool {
    matches!(
        option,
        "--report"
            | "--endpoint"
            | "--timeout-ms"
            | "--input"
            | "--output"
            | "--bind"
            | "--source"
            | "--count"
            | "--topic"
            | "--domain"
            | "--speed"
            | "--limit"
            | "--iterations"
            | "--interval-ms"
            | "--format"
            | "--alert-template"
            | "--template"
            | "--topic-warn-utilization"
            | "--topic-critical-utilization"
            | "--baseline-report"
            | "--baseline-endpoint"
            | "--baseline-timeout-ms"
            | "--policy"
            | "--project"
            | "--reports"
            | "--endpoints"
            | "--baseline-reports"
            | "--baseline-endpoints"
            | "--input-bag"
            | "--obs-format"
            | "--profile-template"
            | "--target-schema"
            | "--projects"
            | "--projects-file"
            | "--backup"
            | "--scan-root"
            | "--filter-schema"
            | "--filter-template"
            | "--batch-report"
            | "--severity-map"
            | "--file"
            | "--task"
            | "--profile"
            | "--overlay"
            | "--group"
            | "--max-parallel"
            | "--state-file"
            | "--mode"
    )
}