Skip to main content

byte_unit/bit/
parse.rs

1use rust_decimal::prelude::*;
2
3use super::Bit;
4use crate::{ParseError, ValueParseError, common::get_char_from_bytes, unit::parse::read_xib};
5
6/// Associated functions for parsing strings.
7impl Bit {
8    /// Create a new `Bit` instance from a string.
9    /// The string may be `"10"`, `"10B"`, `"10M"`, `"10MB"`, `"10MiB"`, `"80b"`, `"80Mb"`, `"80Mbit"`.
10    ///
11    /// You can ignore the case of **"B"** (bit), which means **b** will still be treated as bits instead of bits.
12    ///
13    /// # Examples
14    ///
15    /// ```
16    /// # use byte_unit::Bit;
17    /// let bit = Bit::parse_str("123Kib").unwrap(); // 123 * 1024 bits
18    /// ```
19    pub fn parse_str<S: AsRef<str>>(s: S) -> Result<Self, ParseError> {
20        let s = s.as_ref().trim();
21
22        let mut bits = s.bytes();
23
24        let mut value = match bits.next() {
25            Some(e) => match e {
26                b'0'..=b'9' => Decimal::from(e - b'0'),
27                _ => {
28                    return Err(ValueParseError::NotNumber(unsafe {
29                        get_char_from_bytes(e, bits)
30                    })
31                    .into());
32                },
33            },
34            None => return Err(ValueParseError::NoValue.into()),
35        };
36
37        let e = 'outer: loop {
38            match bits.next() {
39                Some(e) => match e {
40                    b'0'..=b'9' => {
41                        value = value
42                            .checked_mul(Decimal::TEN)
43                            .ok_or(ValueParseError::NumberTooLong)?
44                            .checked_add(Decimal::from(e - b'0'))
45                            .ok_or(ValueParseError::NumberTooLong)?;
46                    },
47                    b'.' => {
48                        let mut i = 1u32;
49
50                        loop {
51                            match bits.next() {
52                                Some(e) => match e {
53                                    b'0'..=b'9' => {
54                                        value = value
55                                            .checked_add({
56                                                let mut d = Decimal::from(e - b'0');
57
58                                                d.set_scale(i)
59                                                    .map_err(|_| ValueParseError::NumberTooLong)?;
60
61                                                d
62                                            })
63                                            .ok_or(ValueParseError::NumberTooLong)?;
64
65                                        i += 1;
66                                    },
67                                    _ => {
68                                        if i == 1 {
69                                            return Err(ValueParseError::NotNumber(unsafe {
70                                                get_char_from_bytes(e, bits)
71                                            })
72                                            .into());
73                                        }
74
75                                        match e {
76                                            b' ' => loop {
77                                                match bits.next() {
78                                                    Some(e) => match e {
79                                                        b' ' => (),
80                                                        _ => break 'outer Some(e),
81                                                    },
82                                                    None => break 'outer None,
83                                                }
84                                            },
85                                            _ => break 'outer Some(e),
86                                        }
87                                    },
88                                },
89                                None => {
90                                    if i == 1 {
91                                        return Err(ValueParseError::NotNumber(unsafe {
92                                            get_char_from_bytes(e, bits)
93                                        })
94                                        .into());
95                                    }
96
97                                    break 'outer None;
98                                },
99                            }
100                        }
101                    },
102                    b' ' => loop {
103                        match bits.next() {
104                            Some(e) => match e {
105                                b' ' => (),
106                                _ => break 'outer Some(e),
107                            },
108                            None => break 'outer None,
109                        }
110                    },
111                    _ => break 'outer Some(e),
112                },
113                None => break None,
114            }
115        };
116
117        let unit = read_xib(e, bits, false, false)?;
118
119        Self::from_decimal_with_unit(value, unit)
120            .ok_or_else(|| ValueParseError::ExceededBounds(value).into())
121    }
122}