summaryrefslogtreecommitdiff
path: root/src/parse.rs
blob: edfd9c5cf402666bc371b0367a4c719dc1a604c1 (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
use std::str::FromStr;
use crate::{error::PissError, PissAmount};

impl<T> From<T> for PissAmount 
where T: Into<u128> {
    fn from(num: T) -> PissAmount {
        PissAmount {
            to_piss: num.into()
        } 
    }  
}

fn parse_suffix(s: &str) -> Result<u128, PissError> {
    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" => 0x100000,
        "gi" | "gib" => 0x40000000,
        "ti" | "tib" => 0x10000000000,
        "pi" | "pib" => 0x4000000000000,
        "ei" | "eib" => 0x1000000000000000,
        "xi" | "xib" => 0x400000000000000000,
        "yi" | "yib" => 0x100000000000000000000,
        "ri" | "rib" => 0x40000000000000000000000,
        "qi" | "qib" => 0x10000000000000000000000000,
        "" | "b" => 1, // uwu
        _ => return Err(PissError::InvalidSuffix(s.into())) // such nepal
    })
}

fn parse_file_size(s: &str) -> Result<PissAmount, PissError> {
    let mut end = 0;
    for (i, c) in s.char_indices() {
        if c.is_digit(10) || c == '.' { continue; }
        end = i;
        break;
    }

    let num_text = &s[..end];
    let suffix_text = &s[end..];
    
    let Ok(num) = num_text.parse::<f64>() else {
        return Err(PissError::InvalidNumber(num_text.into()))
    };

    if num <= 0f64 {
        return Err(PissError::NumberNotPositive)
    } 

    let multiplier = parse_suffix(suffix_text)?;
    
    Ok(PissAmount {
        to_piss: (num * multiplier as f64) as u128
    })
}

impl FromStr for PissAmount {
    type Err = PissError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        parse_file_size(s)
    }
}