summaryrefslogtreecommitdiff
path: root/src/parse.rs
blob: d6e5dfad6ff6ac2ff652a493f551eeaf14b68c41 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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<Vec<$t>> 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<u128, LeakError> {
    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<LeakAmount, LeakError> {
    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::<f64>() 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<Self, Self::Err> {
        parse_file_size(s.to_lowercase().as_str())
    }
}