Skip to main content

byte_unit/unit/
parse.rs

1use core::str::Bytes;
2
3use super::Unit;
4use crate::{UnitParseError, common::get_char_from_bytes};
5
6/// Associated functions for parsing strings.
7impl Unit {
8    /// Create a new `Unit` instance from a string.
9    /// The string may be `""`, `"B"`, `"M"`, `"MB"`, `"MiB"`, `"b"`, `"Mb"`, `"Mbit"`.
10    ///
11    /// You can ignore the case of **"B"** (byte), which means **b** will still be treated as bytes instead of bits.
12    ///
13    /// If the input string is empty, it will return `B` if `prefer_byte` is true; otherwise, it will return `b`. Similarly, if the string is not empty but it does not explicitly contains `"B"`, `"b"`, or `"bit"`, it will imply the base is `"B"` if `prefer_byte` is true; otherwise, imply the base is `"b"`.
14    ///
15    /// # Examples
16    ///
17    /// ```
18    /// # use byte_unit::Unit;
19    /// let unit = Unit::parse_str("Kib", true, true).unwrap(); // KiB
20    /// ```
21    ///
22    /// ```
23    /// # use byte_unit::Unit;
24    /// let unit = Unit::parse_str("Kib", false, true).unwrap(); // Kibit
25    /// ```
26    pub fn parse_str<S: AsRef<str>>(
27        s: S,
28        ignore_case: bool,
29        prefer_byte: bool,
30    ) -> Result<Self, UnitParseError> {
31        let s = s.as_ref().trim();
32
33        let mut bytes = s.bytes();
34
35        read_xib(bytes.next(), bytes, ignore_case, prefer_byte)
36    }
37}
38
39pub(crate) fn read_xib(
40    e: Option<u8>,
41    bytes: Bytes,
42    ignore_case: bool,
43    prefer_byte: bool,
44) -> Result<Unit, UnitParseError> {
45    match e {
46        Some(e) => match e.to_ascii_uppercase() {
47            b'B' => {
48                let byte = read_b(bytes, if ignore_case { true } else { e == b'B' })?;
49
50                if byte { Ok(Unit::B) } else { Ok(Unit::Bit) }
51            },
52            b'K' => {
53                let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?;
54
55                if i {
56                    if byte { Ok(Unit::KiB) } else { Ok(Unit::Kibit) }
57                } else if byte {
58                    Ok(Unit::KB)
59                } else {
60                    Ok(Unit::Kbit)
61                }
62            },
63            b'M' => {
64                let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?;
65
66                if i {
67                    if byte { Ok(Unit::MiB) } else { Ok(Unit::Mibit) }
68                } else if byte {
69                    Ok(Unit::MB)
70                } else {
71                    Ok(Unit::Mbit)
72                }
73            },
74            b'G' => {
75                let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?;
76
77                if i {
78                    if byte { Ok(Unit::GiB) } else { Ok(Unit::Gibit) }
79                } else if byte {
80                    Ok(Unit::GB)
81                } else {
82                    Ok(Unit::Gbit)
83                }
84            },
85            b'T' => {
86                let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?;
87
88                if i {
89                    if byte { Ok(Unit::TiB) } else { Ok(Unit::Tibit) }
90                } else if byte {
91                    Ok(Unit::TB)
92                } else {
93                    Ok(Unit::Tbit)
94                }
95            },
96            b'P' => {
97                let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?;
98
99                if i {
100                    if byte { Ok(Unit::PiB) } else { Ok(Unit::Pibit) }
101                } else if byte {
102                    Ok(Unit::PB)
103                } else {
104                    Ok(Unit::Pbit)
105                }
106            },
107            b'E' => {
108                let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?;
109
110                if i {
111                    if byte { Ok(Unit::EiB) } else { Ok(Unit::Eibit) }
112                } else if byte {
113                    Ok(Unit::EB)
114                } else {
115                    Ok(Unit::Ebit)
116                }
117            },
118            #[cfg(feature = "u128")]
119            b'Z' => {
120                let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?;
121
122                if i {
123                    if byte { Ok(Unit::ZiB) } else { Ok(Unit::Zibit) }
124                } else if byte {
125                    Ok(Unit::ZB)
126                } else {
127                    Ok(Unit::Zbit)
128                }
129            },
130            #[cfg(feature = "u128")]
131            b'Y' => {
132                let (i, byte) = read_ib(bytes, ignore_case, prefer_byte)?;
133
134                if i {
135                    if byte { Ok(Unit::YiB) } else { Ok(Unit::Yibit) }
136                } else if byte {
137                    Ok(Unit::YB)
138                } else {
139                    Ok(Unit::Ybit)
140                }
141            },
142            _ => {
143                #[cfg(feature = "u128")]
144                {
145                    Err(UnitParseError {
146                        character:                unsafe { get_char_from_bytes(e, bytes) },
147                        expected_characters:      &['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'],
148                        also_expect_no_character: true,
149                    })
150                }
151                #[cfg(not(feature = "u128"))]
152                {
153                    Err(UnitParseError {
154                        character:                unsafe { get_char_from_bytes(e, bytes) },
155                        expected_characters:      &['B', 'K', 'M', 'G', 'T', 'P', 'E'],
156                        also_expect_no_character: true,
157                    })
158                }
159            },
160        },
161        None => Ok(if prefer_byte { Unit::B } else { Unit::Bit }),
162    }
163}
164fn read_ib(
165    mut bytes: Bytes,
166    ignore_case: bool,
167    default_upper_case: bool,
168) -> Result<(bool, bool), UnitParseError> {
169    match bytes.next() {
170        Some(mut e) => {
171            let i = e == b'i' || e == b'I';
172
173            if i {
174                match bytes.next() {
175                    Some(ne) => e = ne,
176                    None => return Ok((true, default_upper_case)),
177                }
178            }
179
180            match e {
181                b'b' | b'B' => Ok((i, read_b(bytes, if ignore_case { true } else { e == b'B' })?)),
182                _ => {
183                    let expected_characters: &[char] = if ignore_case {
184                        if default_upper_case { &['B'] } else { &['b'] }
185                    } else {
186                        &['B', 'b']
187                    };
188
189                    Err(UnitParseError {
190                        character: unsafe { get_char_from_bytes(e, bytes) },
191                        expected_characters,
192                        also_expect_no_character: true,
193                    })
194                },
195            }
196        },
197        None => Ok((false, default_upper_case)),
198    }
199}
200
201fn read_b(mut bytes: Bytes, byte: bool) -> Result<bool, UnitParseError> {
202    match bytes.next() {
203        Some(e) => match e.to_ascii_lowercase() {
204            b'i' => match bytes.next() {
205                Some(e) => match e.to_ascii_lowercase() {
206                    b't' => match bytes.next() {
207                        Some(e) => match e.to_ascii_lowercase() {
208                            b's' => match bytes.next() {
209                                Some(e) => Err(UnitParseError {
210                                    character:                unsafe {
211                                        get_char_from_bytes(e, bytes)
212                                    },
213                                    expected_characters:      &[],
214                                    also_expect_no_character: true,
215                                }),
216                                None => Ok(false),
217                            },
218                            _ => Err(UnitParseError {
219                                character:                unsafe { get_char_from_bytes(e, bytes) },
220                                expected_characters:      &['s'],
221                                also_expect_no_character: true,
222                            }),
223                        },
224                        None => Ok(false),
225                    },
226                    _ => Err(UnitParseError {
227                        character:                unsafe { get_char_from_bytes(e, bytes) },
228                        expected_characters:      &['t'],
229                        also_expect_no_character: false,
230                    }),
231                },
232                None => Err(UnitParseError {
233                    character:                'i',
234                    expected_characters:      &[],
235                    also_expect_no_character: true,
236                }),
237            },
238            _ => Err(UnitParseError {
239                character:                unsafe { get_char_from_bytes(e, bytes) },
240                expected_characters:      &['i'],
241                also_expect_no_character: true,
242            }),
243        },
244        None => Ok(byte),
245    }
246}