Skip to main content

scanner_rust/
scanner_u8_slice.rs

1use std::{
2    char::REPLACEMENT_CHARACTER,
3    str::{FromStr, from_utf8},
4};
5
6use utf8_width::*;
7
8use crate::{ScannerError, kmp::find_boundary, text::numeric_text, whitespaces::*};
9
10/// A simple text scanner which can in-memory-ly parse primitive types and strings using UTF-8 from a byte slice.
11#[derive(Debug)]
12pub struct ScannerU8Slice<'a> {
13    data:        &'a [u8],
14    data_length: usize,
15    position:    usize,
16}
17
18impl<'a> ScannerU8Slice<'a> {
19    /// Create a scanner from in-memory bytes.
20    ///
21    /// ```rust
22    /// use std::io;
23    ///
24    /// use scanner_rust::ScannerU8Slice;
25    ///
26    /// let mut sc = ScannerU8Slice::new(b"123 456");
27    /// ```
28    #[inline]
29    pub fn new<D: ?Sized + AsRef<[u8]>>(data: &D) -> ScannerU8Slice<'_> {
30        let data = data.as_ref();
31
32        ScannerU8Slice {
33            data,
34            data_length: data.len(),
35            position: 0,
36        }
37    }
38}
39
40impl<'a> ScannerU8Slice<'a> {
41    /// Read the next char. If the data is not a correct char, it will return a `Ok(Some(REPLACEMENT_CHARACTER))` which is �. If there is nothing to read, it will return `Ok(None)`.
42    ///
43    /// ```rust
44    /// use scanner_rust::ScannerU8Slice;
45    ///
46    /// let mut sc = ScannerU8Slice::new("5 c 中文".as_bytes());
47    ///
48    /// assert_eq!(Some('5'), sc.next_char().unwrap());
49    /// assert_eq!(Some(' '), sc.next_char().unwrap());
50    /// assert_eq!(Some('c'), sc.next_char().unwrap());
51    /// assert_eq!(Some(' '), sc.next_char().unwrap());
52    /// assert_eq!(Some('中'), sc.next_char().unwrap());
53    /// assert_eq!(Some('文'), sc.next_char().unwrap());
54    /// assert_eq!(None, sc.next_char().unwrap());
55    /// ```
56    pub fn next_char(&mut self) -> Result<Option<char>, ScannerError> {
57        if self.position == self.data_length {
58            return Ok(None);
59        }
60
61        let e = self.data[self.position];
62
63        let width = get_width(e);
64
65        match width {
66            0 => {
67                self.position += 1;
68
69                Ok(Some(REPLACEMENT_CHARACTER))
70            },
71            1 => {
72                self.position += 1;
73
74                Ok(Some(e as char))
75            },
76            _ => {
77                if self.position + width > self.data_length {
78                    self.position += 1;
79
80                    Ok(Some(REPLACEMENT_CHARACTER))
81                } else {
82                    let char_str_bytes = &self.data[self.position..(self.position + width)];
83
84                    match from_utf8(char_str_bytes) {
85                        Ok(char_str) => {
86                            self.position += width;
87
88                            Ok(char_str.chars().next())
89                        },
90                        Err(_) => {
91                            self.position += 1;
92
93                            Ok(Some(REPLACEMENT_CHARACTER))
94                        },
95                    }
96                }
97            },
98        }
99    }
100
101    /// Read the next line but not include the trailing line character (or line characters like `CrLf`(`\r\n`)). If there is nothing to read, it will return `Ok(None)`.
102    ///
103    /// ```rust
104    /// use scanner_rust::ScannerU8Slice;
105    ///
106    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
107    ///
108    /// assert_eq!(Some("123 456".as_bytes()), sc.next_line().unwrap());
109    /// assert_eq!(Some("789 ".as_bytes()), sc.next_line().unwrap());
110    /// assert_eq!(Some("".as_bytes()), sc.next_line().unwrap());
111    /// assert_eq!(Some(" 中文 ".as_bytes()), sc.next_line().unwrap());
112    /// ```
113    pub fn next_line(&mut self) -> Result<Option<&'a [u8]>, ScannerError> {
114        if self.position == self.data_length {
115            return Ok(None);
116        }
117
118        let mut p = self.position;
119
120        loop {
121            let e = self.data[p];
122
123            match e {
124                b'\n' => {
125                    let data = &self.data[self.position..p];
126
127                    if p + 1 < self.data_length && self.data[p + 1] == b'\r' {
128                        self.position = p + 2;
129                    } else {
130                        self.position = p + 1;
131                    }
132
133                    return Ok(Some(data));
134                },
135                b'\r' => {
136                    let data = &self.data[self.position..p];
137
138                    if p + 1 < self.data_length && self.data[p + 1] == b'\n' {
139                        self.position = p + 2;
140                    } else {
141                        self.position = p + 1;
142                    }
143
144                    return Ok(Some(data));
145                },
146                _ => (),
147            }
148
149            p += 1;
150
151            if p == self.data_length {
152                break;
153            }
154        }
155
156        let data = &self.data[self.position..p];
157
158        self.position = p;
159
160        Ok(Some(data))
161    }
162}
163
164impl<'a> ScannerU8Slice<'a> {
165    /// Skip the next whitespaces (`javaWhitespace`). If there is nothing to read, it will return `Ok(false)`.
166    ///
167    /// ```rust
168    /// use scanner_rust::ScannerU8Slice;
169    ///
170    /// let mut sc = ScannerU8Slice::new("1 2   c".as_bytes());
171    ///
172    /// assert_eq!(Some('1'), sc.next_char().unwrap());
173    /// assert_eq!(Some(' '), sc.next_char().unwrap());
174    /// assert_eq!(Some('2'), sc.next_char().unwrap());
175    /// assert_eq!(true, sc.skip_whitespaces().unwrap());
176    /// assert_eq!(Some('c'), sc.next_char().unwrap());
177    /// assert_eq!(false, sc.skip_whitespaces().unwrap());
178    /// ```
179    pub fn skip_whitespaces(&mut self) -> Result<bool, ScannerError> {
180        if self.position == self.data_length {
181            return Ok(false);
182        }
183
184        loop {
185            let e = self.data[self.position];
186
187            let width = get_width(e);
188
189            match width {
190                0 => {
191                    break;
192                },
193                1 => {
194                    if !is_whitespace_1(e) {
195                        break;
196                    }
197
198                    self.position += 1;
199                },
200                3 if self.position + width <= self.data_length
201                    && is_whitespace_3(
202                        self.data[self.position],
203                        self.data[self.position + 1],
204                        self.data[self.position + 2],
205                    ) =>
206                {
207                    self.position += 3;
208                },
209                _ => {
210                    break;
211                },
212            }
213
214            if self.position == self.data_length {
215                break;
216            }
217        }
218
219        Ok(true)
220    }
221
222    /// Read the next token separated by whitespaces. If there is nothing to read, it will return `Ok(None)`.
223    ///
224    /// ```rust
225    /// use scanner_rust::ScannerU8Slice;
226    ///
227    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
228    ///
229    /// assert_eq!(Some("123".as_bytes()), sc.next().unwrap());
230    /// assert_eq!(Some("456".as_bytes()), sc.next().unwrap());
231    /// assert_eq!(Some("789".as_bytes()), sc.next().unwrap());
232    /// assert_eq!(Some("中文".as_bytes()), sc.next().unwrap());
233    /// assert_eq!(None, sc.next().unwrap());
234    /// ```
235    #[allow(clippy::should_implement_trait)]
236    pub fn next(&mut self) -> Result<Option<&'a [u8]>, ScannerError> {
237        if !self.skip_whitespaces()? || self.position == self.data_length {
238            return Ok(None);
239        }
240
241        let mut p = self.position;
242
243        while p < self.data_length {
244            let e = self.data[p];
245            let width = get_width(e);
246
247            if is_whitespace_1(e)
248                || (width == 3
249                    && self.data_length - p >= 3
250                    && is_whitespace_3(self.data[p], self.data[p + 1], self.data[p + 2]))
251            {
252                break;
253            }
254
255            if width > 1
256                && self.data_length - p >= width
257                && self.data[(p + 1)..(p + width)].iter().all(|byte| byte & 0xC0 == 0x80)
258            {
259                p += width;
260            } else {
261                p += 1;
262            }
263        }
264
265        let data = &self.data[self.position..p];
266
267        self.position = p;
268
269        Ok(Some(data))
270    }
271}
272
273impl<'a> ScannerU8Slice<'a> {
274    /// Read the next bytes. If there is nothing to read, it will return `Ok(None)`.
275    ///
276    /// ```rust
277    /// use scanner_rust::ScannerU8Slice;
278    ///
279    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
280    ///
281    /// assert_eq!(Some("123".as_bytes()), sc.next_bytes(3).unwrap());
282    /// assert_eq!(Some(" 456".as_bytes()), sc.next_bytes(4).unwrap());
283    /// assert_eq!(Some("\r\n789 ".as_bytes()), sc.next_bytes(6).unwrap());
284    /// assert_eq!(Some("中文".as_bytes()), sc.next().unwrap());
285    /// assert_eq!(Some(" ".as_bytes()), sc.next_bytes(2).unwrap());
286    /// assert_eq!(None, sc.next_bytes(2).unwrap());
287    /// ```
288    pub fn next_bytes(
289        &mut self,
290        max_number_of_bytes: usize,
291    ) -> Result<Option<&'a [u8]>, ScannerError> {
292        if self.position == self.data_length {
293            return Ok(None);
294        }
295
296        let dropping_bytes = max_number_of_bytes.min(self.data_length - self.position);
297
298        let data = &self.data[self.position..(self.position + dropping_bytes)];
299
300        self.position += dropping_bytes;
301
302        Ok(Some(data))
303    }
304
305    /// Drop the next N bytes. If there is nothing to read, it will return `Ok(None)`. If there is something to read, it will return `Ok(Some(i))`. The `i` is the length of the actually dropped bytes.
306    ///
307    /// ```rust
308    /// use scanner_rust::ScannerU8Slice;
309    ///
310    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
311    ///
312    /// assert_eq!(Some(7), sc.drop_next_bytes(7).unwrap());
313    /// assert_eq!(Some("".as_bytes()), sc.next_line().unwrap());
314    /// assert_eq!(Some("789 ".as_bytes()), sc.next_line().unwrap());
315    /// assert_eq!(Some(1), sc.drop_next_bytes(1).unwrap());
316    /// assert_eq!(Some(" 中文 ".as_bytes()), sc.next_line().unwrap());
317    /// assert_eq!(None, sc.drop_next_bytes(1).unwrap());
318    /// ```
319    pub fn drop_next_bytes(
320        &mut self,
321        max_number_of_bytes: usize,
322    ) -> Result<Option<usize>, ScannerError> {
323        if self.position == self.data_length {
324            return Ok(None);
325        }
326
327        let dropping_bytes = max_number_of_bytes.min(self.data_length - self.position);
328
329        self.position += dropping_bytes;
330
331        Ok(Some(dropping_bytes))
332    }
333}
334
335impl<'a> ScannerU8Slice<'a> {
336    /// Read the next data until it reaches a specific boundary. If there is nothing to read, it will return `Ok(None)`.
337    ///
338    /// An empty boundary reads all remaining data.
339    ///
340    /// ```rust
341    /// use scanner_rust::ScannerU8Slice;
342    ///
343    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
344    ///
345    /// assert_eq!(Some("123".as_bytes()), sc.next_until(" ").unwrap());
346    /// assert_eq!(Some("456\r".as_bytes()), sc.next_until("\n").unwrap());
347    /// assert_eq!(Some("78".as_bytes()), sc.next_until("9 ").unwrap());
348    /// assert_eq!(Some("\n\n 中文 ".as_bytes()), sc.next_until("kk").unwrap());
349    /// assert_eq!(None, sc.next().unwrap());
350    /// ```
351    pub fn next_until<D: ?Sized + AsRef<[u8]>>(
352        &mut self,
353        boundary: &D,
354    ) -> Result<Option<&'a [u8]>, ScannerError> {
355        if self.position == self.data_length {
356            return Ok(None);
357        }
358
359        let boundary = boundary.as_ref();
360        let boundary_length = boundary.len();
361
362        if boundary_length == 0 || boundary_length > self.data_length - self.position {
363            let data = &self.data[self.position..];
364
365            self.position = self.data_length;
366
367            return Ok(Some(data));
368        }
369
370        if let Some(offset) = find_boundary(&self.data[self.position..], boundary) {
371            let end = self.position + offset;
372            let data = &self.data[self.position..end];
373
374            self.position = end + boundary_length;
375
376            return Ok(Some(data));
377        }
378
379        let data = &self.data[self.position..];
380
381        self.position = self.data_length;
382
383        Ok(Some(data))
384    }
385}
386
387impl<'a> ScannerU8Slice<'a> {
388    #[inline]
389    fn next_parse<T: FromStr>(&mut self) -> Result<Option<T>, ScannerError>
390    where
391        ScannerError: From<<T as FromStr>::Err>, {
392        let result = self.next()?;
393
394        match result {
395            Some(s) => Ok(Some(numeric_text(s).parse()?)),
396            None => Ok(None),
397        }
398    }
399}
400
401impl<'a> ScannerU8Slice<'a> {
402    #[inline]
403    fn next_until_parse<T: FromStr, D: ?Sized + AsRef<[u8]>>(
404        &mut self,
405        boundary: &D,
406    ) -> Result<Option<T>, ScannerError>
407    where
408        ScannerError: From<<T as FromStr>::Err>, {
409        let result = self.next_until(boundary)?;
410
411        match result {
412            Some(s) => Ok(Some(numeric_text(s).parse()?)),
413            None => Ok(None),
414        }
415    }
416}
417
418macro_rules! scanner_u8_slice_number_methods {
419    ($(($t:ty, $next:ident, $next_until:ident, $sample:literal, $v1:literal, $v2:literal)),+ $(,)?) => {
420        impl<'a> ScannerU8Slice<'a> {
421            $(
422                #[doc = concat!(
423                    "Read the next token separated by whitespaces and parse it to a `", stringify!($t), "` value. If there is nothing to read, it will return `Ok(None)`.\n\n```rust\nuse scanner_rust::ScannerU8Slice;\n\nlet mut sc = ScannerU8Slice::new(", stringify!($sample), ".as_bytes());\n\nassert_eq!(Some(", stringify!($v1), "), sc.", stringify!($next), "().unwrap());\nassert_eq!(Some(", stringify!($v2), "), sc.", stringify!($next), "().unwrap());\n```"
424                )]
425                #[inline]
426                pub fn $next(&mut self) -> Result<Option<$t>, ScannerError> {
427                    self.next_parse()
428                }
429            )+
430        }
431
432        impl<'a> ScannerU8Slice<'a> {
433            $(
434                #[doc = concat!(
435                    "Read the next text until it reaches a specific boundary and parse it to a `", stringify!($t), "` value. If there is nothing to read, it will return `Ok(None)`. An empty boundary reads all remaining data before parsing.\n\n```rust\nuse scanner_rust::ScannerU8Slice;\n\nlet mut sc = ScannerU8Slice::new(", stringify!($sample), ".as_bytes());\n\nassert_eq!(Some(", stringify!($v1), "), sc.", stringify!($next_until), "(\" \").unwrap());\nassert_eq!(Some(", stringify!($v2), "), sc.", stringify!($next_until), "(\" \").unwrap());\n```"
436                )]
437                #[inline]
438                pub fn $next_until<D: ?Sized + AsRef<[u8]>>(
439                    &mut self,
440                    boundary: &D,
441                ) -> Result<Option<$t>, ScannerError> {
442                    self.next_until_parse(boundary)
443                }
444            )+
445        }
446    };
447}
448
449scanner_u8_slice_number_methods! {
450    (u8, next_u8, next_u8_until, "1 2", 1, 2),
451    (u16, next_u16, next_u16_until, "1 2", 1, 2),
452    (u32, next_u32, next_u32_until, "1 2", 1, 2),
453    (u64, next_u64, next_u64_until, "1 2", 1, 2),
454    (u128, next_u128, next_u128_until, "1 2", 1, 2),
455    (usize, next_usize, next_usize_until, "1 2", 1, 2),
456    (i8, next_i8, next_i8_until, "1 2", 1, 2),
457    (i16, next_i16, next_i16_until, "1 2", 1, 2),
458    (i32, next_i32, next_i32_until, "1 2", 1, 2),
459    (i64, next_i64, next_i64_until, "1 2", 1, 2),
460    (i128, next_i128, next_i128_until, "1 2", 1, 2),
461    (isize, next_isize, next_isize_until, "1 2", 1, 2),
462    (f32, next_f32, next_f32_until, "1 2.5", 1.0, 2.5),
463    (f64, next_f64, next_f64_until, "1 2.5", 1.0, 2.5),
464}
465
466impl<'a> ScannerU8Slice<'a> {
467    /// Drop the next line but not include the trailing line character (or line characters like `CrLf`(`\r\n`)). If there is nothing to read, it will return `Ok(None)`. If there is something to read, it will return `Ok(Some(i))`. The `i` is the length (in bytes) of the dropped line.
468    ///
469    /// ```rust
470    /// use scanner_rust::ScannerU8Slice;
471    ///
472    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
473    ///
474    /// assert_eq!(Some(7), sc.drop_next_line().unwrap());
475    /// assert_eq!(Some("789 ".as_bytes()), sc.next_line().unwrap());
476    /// assert_eq!(Some(0), sc.drop_next_line().unwrap());
477    /// assert_eq!(Some(" 中文 ".as_bytes()), sc.next_line().unwrap());
478    /// assert_eq!(None, sc.drop_next_line().unwrap());
479    /// ```
480    #[inline]
481    pub fn drop_next_line(&mut self) -> Result<Option<usize>, ScannerError> {
482        Ok(self.next_line()?.map(<[u8]>::len))
483    }
484
485    /// Drop the next token separated by whitespaces. If there is nothing to read, it will return `Ok(None)`. If there is something to read, it will return `Ok(Some(i))`. The `i` is the length (in bytes) of the dropped token.
486    ///
487    /// ```rust
488    /// use scanner_rust::ScannerU8Slice;
489    ///
490    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
491    ///
492    /// assert_eq!(Some(3), sc.drop_next().unwrap());
493    /// assert_eq!(Some("456".as_bytes()), sc.next().unwrap());
494    /// assert_eq!(Some(3), sc.drop_next().unwrap());
495    /// assert_eq!(Some("中文".as_bytes()), sc.next().unwrap());
496    /// assert_eq!(None, sc.drop_next().unwrap());
497    /// ```
498    #[inline]
499    pub fn drop_next(&mut self) -> Result<Option<usize>, ScannerError> {
500        Ok(self.next()?.map(<[u8]>::len))
501    }
502
503    /// Drop the next data until it reaches a specific boundary. If there is nothing to read, it will return `Ok(None)`. If there is something to read, it will return `Ok(Some(i))`. The `i` is the length (in bytes) of the dropped data, excluding the boundary.
504    ///
505    /// An empty boundary drops all remaining data.
506    ///
507    /// ```rust
508    /// use scanner_rust::ScannerU8Slice;
509    ///
510    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
511    ///
512    /// assert_eq!(Some(7), sc.drop_next_until("\r\n").unwrap());
513    /// assert_eq!(Some("789 ".as_bytes()), sc.next_line().unwrap());
514    /// assert_eq!(Some(0), sc.drop_next_until("\n").unwrap());
515    /// assert_eq!(Some(" 中文 ".as_bytes()), sc.next_line().unwrap());
516    /// assert_eq!(None, sc.drop_next_until("").unwrap());
517    /// ```
518    #[inline]
519    pub fn drop_next_until<D: ?Sized + AsRef<[u8]>>(
520        &mut self,
521        boundary: &D,
522    ) -> Result<Option<usize>, ScannerError> {
523        Ok(self.next_until(boundary)?.map(<[u8]>::len))
524    }
525}
526
527impl<'a> Iterator for ScannerU8Slice<'a> {
528    type Item = &'a [u8];
529
530    #[inline]
531    fn next(&mut self) -> Option<Self::Item> {
532        self.next().unwrap_or(None)
533    }
534}