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}