wavepeek 0.5.0

Command-line tool for RTL waveform inspection with deterministic machine-friendly output.
Documentation
use std::str::FromStr;

const UNLIMITED_LITERAL: &str = "unlimited";

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum LimitArg {
    Numeric(usize),
    Unlimited,
}

impl LimitArg {
    pub const fn is_unlimited(&self) -> bool {
        matches!(self, Self::Unlimited)
    }

    pub const fn numeric(&self) -> Option<usize> {
        match self {
            Self::Numeric(value) => Some(*value),
            Self::Unlimited => None,
        }
    }
}

impl FromStr for LimitArg {
    type Err = String;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        if value == UNLIMITED_LITERAL {
            return Ok(Self::Unlimited);
        }

        value
            .parse::<usize>()
            .map(Self::Numeric)
            .map_err(|_| format!("expected a non-negative integer or '{UNLIMITED_LITERAL}'"))
    }
}

#[cfg(test)]
mod tests {
    use super::LimitArg;

    #[test]
    fn limit_arg_parses_numeric_values() {
        let parsed = "42".parse::<LimitArg>().expect("numeric parse should work");
        assert_eq!(parsed, LimitArg::Numeric(42));
        assert_eq!(parsed.numeric(), Some(42));
        assert!(!parsed.is_unlimited());
    }

    #[test]
    fn limit_arg_parses_unlimited_literal() {
        let parsed = "unlimited"
            .parse::<LimitArg>()
            .expect("unlimited parse should work");
        assert_eq!(parsed, LimitArg::Unlimited);
        assert_eq!(parsed.numeric(), None);
        assert!(parsed.is_unlimited());
    }

    #[test]
    fn limit_arg_rejects_invalid_literals() {
        let error = "1.5"
            .parse::<LimitArg>()
            .expect_err("invalid limit should fail");
        assert_eq!(error, "expected a non-negative integer or 'unlimited'");
    }
}