use super::parse_size::{ParseSizeError, parse_size_u64, parse_size_u64_max};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SignPrefix {
Plus,
Minus,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SignedNum {
pub value: u64,
pub sign: Option<SignPrefix>,
}
impl SignedNum {
pub fn is_zero(&self) -> bool {
self.value == 0
}
pub fn has_plus(&self) -> bool {
self.sign == Some(SignPrefix::Plus)
}
pub fn has_minus(&self) -> bool {
self.sign == Some(SignPrefix::Minus)
}
}
pub fn parse_signed_num_max(src: &str) -> Result<SignedNum, ParseSizeError> {
let (sign, size_string) = strip_sign_prefix(src);
if size_string.is_empty() {
return Err(ParseSizeError::ParseFailure(src.to_string()));
}
let trimmed = size_string.trim_start_matches('0');
let value = if trimmed.is_empty() {
0
} else {
parse_size_u64_max(trimmed)?
};
Ok(SignedNum { value, sign })
}
pub fn parse_signed_num(src: &str) -> Result<SignedNum, ParseSizeError> {
let (sign, size_string) = strip_sign_prefix(src);
if size_string.is_empty() {
return Err(ParseSizeError::ParseFailure(src.to_string()));
}
let value = parse_size_u64(size_string)
.map_err(|_| ParseSizeError::ParseFailure(size_string.to_string()))?;
Ok(SignedNum { value, sign })
}
fn strip_sign_prefix(src: &str) -> (Option<SignPrefix>, &str) {
let trimmed = src.trim();
if let Some(rest) = trimmed.strip_prefix('+') {
(Some(SignPrefix::Plus), rest)
} else if let Some(rest) = trimmed.strip_prefix('-') {
(Some(SignPrefix::Minus), rest)
} else {
(None, trimmed)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_no_sign() {
let result = parse_signed_num_max("10").unwrap();
assert_eq!(result.value, 10);
assert_eq!(result.sign, None);
assert!(!result.has_plus());
assert!(!result.has_minus());
}
#[test]
fn test_plus_sign() {
let result = parse_signed_num_max("+10").unwrap();
assert_eq!(result.value, 10);
assert_eq!(result.sign, Some(SignPrefix::Plus));
assert!(result.has_plus());
assert!(!result.has_minus());
}
#[test]
fn test_minus_sign() {
let result = parse_signed_num_max("-10").unwrap();
assert_eq!(result.value, 10);
assert_eq!(result.sign, Some(SignPrefix::Minus));
assert!(!result.has_plus());
assert!(result.has_minus());
}
#[test]
fn test_with_suffix() {
let result = parse_signed_num_max("+5K").unwrap();
assert_eq!(result.value, 5 * 1024);
assert!(result.has_plus());
let result = parse_signed_num_max("-2M").unwrap();
assert_eq!(result.value, 2 * 1024 * 1024);
assert!(result.has_minus());
}
#[test]
fn test_zero() {
let result = parse_signed_num_max("0").unwrap();
assert_eq!(result.value, 0);
assert!(result.is_zero());
let result = parse_signed_num_max("+0").unwrap();
assert_eq!(result.value, 0);
assert!(result.is_zero());
assert!(result.has_plus());
let result = parse_signed_num_max("-0").unwrap();
assert_eq!(result.value, 0);
assert!(result.is_zero());
assert!(result.has_minus());
}
#[test]
fn test_leading_zeros() {
let result = parse_signed_num_max("007").unwrap();
assert_eq!(result.value, 7);
let result = parse_signed_num_max("+007").unwrap();
assert_eq!(result.value, 7);
assert!(result.has_plus());
let result = parse_signed_num_max("000").unwrap();
assert_eq!(result.value, 0);
}
#[test]
fn test_whitespace() {
let result = parse_signed_num_max(" 10 ").unwrap();
assert_eq!(result.value, 10);
let result = parse_signed_num_max(" +10 ").unwrap();
assert_eq!(result.value, 10);
assert!(result.has_plus());
}
#[test]
fn test_overflow_max() {
let result = parse_signed_num_max("99999999999999999999999999").unwrap();
assert_eq!(result.value, u64::MAX);
}
#[test]
fn test_invalid() {
assert!(parse_signed_num_max("").is_err());
assert!(parse_signed_num_max("abc").is_err());
assert!(parse_signed_num_max("++10").is_err());
}
}