byte_unit/byte/
parse.rs

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