use std::str::FromStr; use crate::{LeakError, LeakAmount}; macro_rules! from_num { ($t:ty) => { impl From<$t> for LeakAmount { fn from(num: $t) -> Self { Self { to_leak: num as u128 } } } impl From> for LeakAmount { fn from(vec: Vec<$t>) -> Self { let mut amount = 0; for i in vec { amount += i as u128; } Self { to_leak: amount } } } }; } from_num!(u128); from_num!(u64); from_num!(u32); from_num!(u16); from_num!(u8); from_num!(i128); from_num!(i64); from_num!(i32); from_num!(i16); from_num!(i8); from_num!(f32); from_num!(f64); from_num!(bool); fn parse_suffix(s: &str) -> Result { Ok(match s { // nepal "k" | "kb" => 1_000, "m" | "mb" => 1_000_000, "g" | "gb" => 1_000_000_000, "t" | "tb" => 1_000_000_000_000, "p" | "pb" => 1_000_000_000_000_000, "e" | "eb" => 1_000_000_000_000_000_000, "x" | "xb" => 1_000_000_000_000_000_000_000, "y" | "yb" => 1_000_000_000_000_000_000_000_000, "r" | "rb" => 1_000_000_000_000_000_000_000_000_000, "q" | "qb" => 1_000_000_000_000_000_000_000_000_000_000, "ki" | "kib" => 0x400, "mi" | "mib" => 0x0010_0000, "gi" | "gib" => 0x4000_0000, "ti" | "tib" => 0x0100_0000_0000, "pi" | "pib" => 0x0004_0000_0000_0000, "ei" | "eib" => 0x1000_0000_0000_0000, "xi" | "xib" => 0x0040_0000_0000_0000_0000, "yi" | "yib" => 0x0001_0000_0000_0000_0000_0000, "ri" | "rib" => 0x0400_0000_0000_0000_0000_0000, "qi" | "qib" => 0x0010_0000_0000_0000_0000_0000_0000, "" | "b" => 1, // uwu _ => return Err(LeakError::InvalidSuffix(s.into())) // such nepal }) } fn parse_file_size(s: &str) -> Result { let mut end = 0; for (i, c) in s.char_indices() { end = i; if !c.is_ascii_digit() && c != '.' { break; } } if end == 0 { if let Some(c) = s.chars().nth(0) { return Err(LeakError::Unexpected(c)) } } let num_text = &s[..end]; let suffix_text = &s[end..]; let Ok(num) = num_text.parse::() else { return Err(LeakError::InvalidNumber(num_text.into())) }; let multiplier = parse_suffix(suffix_text)?; Ok(LeakAmount { to_leak: (num * multiplier as f64) as u128 }) } impl FromStr for LeakAmount { type Err = LeakError; fn from_str(s: &str) -> Result { parse_file_size(s.to_lowercase().as_str()) } }