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