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}