byte_unit/bit/
parse.rs

1use rust_decimal::prelude::*;
2
3use super::Bit;
4use crate::{common::get_char_from_bytes, unit::parse::read_xib, ParseError, ValueParseError};
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 += {
55                                            let mut d = Decimal::from(e - b'0');
56
57                                            d.set_scale(i)
58                                                .map_err(|_| ValueParseError::NumberTooLong)?;
59
60                                            d
61                                        };
62
63                                        i += 1;
64                                    },
65                                    _ => {
66                                        if i == 1 {
67                                            return Err(ValueParseError::NotNumber(unsafe {
68                                                get_char_from_bytes(e, bits)
69                                            })
70                                            .into());
71                                        }
72
73                                        match e {
74                                            b' ' => loop {
75                                                match bits.next() {
76                                                    Some(e) => match e {
77                                                        b' ' => (),
78                                                        _ => break 'outer Some(e),
79                                                    },
80                                                    None => break 'outer None,
81                                                }
82                                            },
83                                            _ => break 'outer Some(e),
84                                        }
85                                    },
86                                },
87                                None => {
88                                    if i == 1 {
89                                        return Err(ValueParseError::NotNumber(unsafe {
90                                            get_char_from_bytes(e, bits)
91                                        })
92                                        .into());
93                                    }
94
95                                    break 'outer None;
96                                },
97                            }
98                        }
99                    },
100                    b' ' => loop {
101                        match bits.next() {
102                            Some(e) => match e {
103                                b' ' => (),
104                                _ => break 'outer Some(e),
105                            },
106                            None => break 'outer None,
107                        }
108                    },
109                    _ => break 'outer Some(e),
110                },
111                None => break None,
112            }
113        };
114
115        let unit = read_xib(e, bits, false, false)?;
116
117        Self::from_decimal_with_unit(value, unit)
118            .ok_or_else(|| ValueParseError::ExceededBounds(value).into())
119    }
120}