Skip to main content

scanner_rust/
scanner_u8_slice.rs

1use std::{
2    char::REPLACEMENT_CHARACTER,
3    str::{FromStr, from_utf8, from_utf8_unchecked},
4};
5
6use utf8_width::*;
7
8use crate::{ScannerError, 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            let width = get_width(e);
124
125            match width {
126                0 => {
127                    p += 1;
128                },
129                1 => {
130                    match e {
131                        b'\n' => {
132                            let data = &self.data[self.position..p];
133
134                            if p + 1 < self.data_length && self.data[p + 1] == b'\r' {
135                                self.position = p + 2;
136                            } else {
137                                self.position = p + 1;
138                            }
139
140                            return Ok(Some(data));
141                        },
142                        b'\r' => {
143                            let data = &self.data[self.position..p];
144
145                            if p + 1 < self.data_length && self.data[p + 1] == b'\n' {
146                                self.position = p + 2;
147                            } else {
148                                self.position = p + 1;
149                            }
150
151                            return Ok(Some(data));
152                        },
153                        _ => (),
154                    }
155
156                    p += 1;
157                },
158                _ => {
159                    if p + width >= self.data_length {
160                        let data = &self.data[self.position..];
161
162                        self.position = self.data_length;
163
164                        return Ok(Some(data));
165                    } else {
166                        p += width;
167                    }
168                },
169            }
170
171            if p == self.data_length {
172                break;
173            }
174        }
175
176        let data = &self.data[self.position..p];
177
178        self.position = p;
179
180        Ok(Some(data))
181    }
182}
183
184impl<'a> ScannerU8Slice<'a> {
185    /// Skip the next whitespaces (`javaWhitespace`). If there is nothing to read, it will return `Ok(false)`.
186    ///
187    /// ```rust
188    /// use scanner_rust::ScannerU8Slice;
189    ///
190    /// let mut sc = ScannerU8Slice::new("1 2   c".as_bytes());
191    ///
192    /// assert_eq!(Some('1'), sc.next_char().unwrap());
193    /// assert_eq!(Some(' '), sc.next_char().unwrap());
194    /// assert_eq!(Some('2'), sc.next_char().unwrap());
195    /// assert_eq!(true, sc.skip_whitespaces().unwrap());
196    /// assert_eq!(Some('c'), sc.next_char().unwrap());
197    /// assert_eq!(false, sc.skip_whitespaces().unwrap());
198    /// ```
199    pub fn skip_whitespaces(&mut self) -> Result<bool, ScannerError> {
200        if self.position == self.data_length {
201            return Ok(false);
202        }
203
204        loop {
205            let e = self.data[self.position];
206
207            let width = get_width(e);
208
209            match width {
210                0 => {
211                    break;
212                },
213                1 => {
214                    if !is_whitespace_1(e) {
215                        break;
216                    }
217
218                    self.position += 1;
219                },
220                3 if self.position + width <= self.data_length
221                    && is_whitespace_3(
222                        self.data[self.position],
223                        self.data[self.position + 1],
224                        self.data[self.position + 2],
225                    ) =>
226                {
227                    self.position += 3;
228                },
229                _ => {
230                    break;
231                },
232            }
233
234            if self.position == self.data_length {
235                break;
236            }
237        }
238
239        Ok(true)
240    }
241
242    /// Read the next token separated by whitespaces. If there is nothing to read, it will return `Ok(None)`.
243    ///
244    /// ```rust
245    /// use scanner_rust::ScannerU8Slice;
246    ///
247    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
248    ///
249    /// assert_eq!(Some("123".as_bytes()), sc.next().unwrap());
250    /// assert_eq!(Some("456".as_bytes()), sc.next().unwrap());
251    /// assert_eq!(Some("789".as_bytes()), sc.next().unwrap());
252    /// assert_eq!(Some("中文".as_bytes()), sc.next().unwrap());
253    /// assert_eq!(None, sc.next().unwrap());
254    /// ```
255    #[allow(clippy::should_implement_trait)]
256    pub fn next(&mut self) -> Result<Option<&'a [u8]>, ScannerError> {
257        if !self.skip_whitespaces()? {
258            return Ok(None);
259        }
260
261        if self.position == self.data_length {
262            return Ok(None);
263        }
264
265        let mut p = self.position;
266
267        loop {
268            let e = self.data[p];
269
270            let width = get_width(e);
271
272            match width {
273                0 => {
274                    p += 1;
275                },
276                1 => {
277                    if is_whitespace_1(e) {
278                        let data = &self.data[self.position..p];
279
280                        self.position = p;
281
282                        return Ok(Some(data));
283                    }
284
285                    p += 1;
286                },
287                3 => {
288                    if p + width > self.data_length {
289                        let data = &self.data[self.position..];
290
291                        self.position = self.data_length;
292
293                        return Ok(Some(data));
294                    } else if is_whitespace_3(self.data[p], self.data[p + 1], self.data[p + 2]) {
295                        let data = &self.data[self.position..p];
296
297                        self.position = p;
298
299                        return Ok(Some(data));
300                    } else {
301                        p += 3;
302                    }
303                },
304                _ => {
305                    if p + width >= self.data_length {
306                        let data = &self.data[self.position..];
307
308                        self.position = self.data_length;
309
310                        return Ok(Some(data));
311                    } else {
312                        p += width;
313                    }
314                },
315            }
316
317            if p == self.data_length {
318                break;
319            }
320        }
321
322        let data = &self.data[self.position..p];
323
324        self.position = p;
325
326        Ok(Some(data))
327    }
328}
329
330impl<'a> ScannerU8Slice<'a> {
331    /// Read the next bytes. If there is nothing to read, it will return `Ok(None)`.
332    ///
333    /// ```rust
334    /// use scanner_rust::ScannerU8Slice;
335    ///
336    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
337    ///
338    /// assert_eq!(Some("123".as_bytes()), sc.next_bytes(3).unwrap());
339    /// assert_eq!(Some(" 456".as_bytes()), sc.next_bytes(4).unwrap());
340    /// assert_eq!(Some("\r\n789 ".as_bytes()), sc.next_bytes(6).unwrap());
341    /// assert_eq!(Some("中文".as_bytes()), sc.next().unwrap());
342    /// assert_eq!(Some(" ".as_bytes()), sc.next_bytes(2).unwrap());
343    /// assert_eq!(None, sc.next_bytes(2).unwrap());
344    /// ```
345    pub fn next_bytes(
346        &mut self,
347        max_number_of_bytes: usize,
348    ) -> Result<Option<&'a [u8]>, ScannerError> {
349        if self.position == self.data_length {
350            return Ok(None);
351        }
352
353        let dropping_bytes = max_number_of_bytes.min(self.data_length - self.position);
354
355        let data = &self.data[self.position..(self.position + dropping_bytes)];
356
357        self.position += dropping_bytes;
358
359        Ok(Some(data))
360    }
361
362    /// 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.
363    ///
364    /// ```rust
365    /// use scanner_rust::ScannerU8Slice;
366    ///
367    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
368    ///
369    /// assert_eq!(Some(7), sc.drop_next_bytes(7).unwrap());
370    /// assert_eq!(Some("".as_bytes()), sc.next_line().unwrap());
371    /// assert_eq!(Some("789 ".as_bytes()), sc.next_line().unwrap());
372    /// assert_eq!(Some(1), sc.drop_next_bytes(1).unwrap());
373    /// assert_eq!(Some(" 中文 ".as_bytes()), sc.next_line().unwrap());
374    /// assert_eq!(None, sc.drop_next_bytes(1).unwrap());
375    /// ```
376    pub fn drop_next_bytes(
377        &mut self,
378        max_number_of_bytes: usize,
379    ) -> Result<Option<usize>, ScannerError> {
380        if self.position == self.data_length {
381            return Ok(None);
382        }
383
384        let dropping_bytes = max_number_of_bytes.min(self.data_length - self.position);
385
386        self.position += dropping_bytes;
387
388        Ok(Some(dropping_bytes))
389    }
390}
391
392impl<'a> ScannerU8Slice<'a> {
393    /// Read the next data until it reaches a specific boundary. If there is nothing to read, it will return `Ok(None)`.
394    ///
395    /// ```rust
396    /// use scanner_rust::ScannerU8Slice;
397    ///
398    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
399    ///
400    /// assert_eq!(Some("123".as_bytes()), sc.next_until(" ").unwrap());
401    /// assert_eq!(Some("456\r".as_bytes()), sc.next_until("\n").unwrap());
402    /// assert_eq!(Some("78".as_bytes()), sc.next_until("9 ").unwrap());
403    /// assert_eq!(Some("\n\n 中文 ".as_bytes()), sc.next_until("kk").unwrap());
404    /// assert_eq!(None, sc.next().unwrap());
405    /// ```
406    pub fn next_until<D: ?Sized + AsRef<[u8]>>(
407        &mut self,
408        boundary: &D,
409    ) -> Result<Option<&'a [u8]>, ScannerError> {
410        if self.position == self.data_length {
411            return Ok(None);
412        }
413
414        let boundary = boundary.as_ref();
415        let boundary_length = boundary.len();
416
417        if boundary_length == 0 || boundary_length > self.data_length - self.position {
418            let data = &self.data[self.position..];
419
420            self.position = self.data_length;
421
422            return Ok(Some(data));
423        }
424
425        for i in self.position..=(self.data_length - boundary_length) {
426            let e = i + boundary_length;
427
428            if &self.data[i..e] == boundary {
429                let data = &self.data[self.position..i];
430
431                self.position = e;
432
433                return Ok(Some(data));
434            }
435        }
436
437        let data = &self.data[self.position..];
438
439        self.position = self.data_length;
440
441        Ok(Some(data))
442    }
443}
444
445impl<'a> ScannerU8Slice<'a> {
446    #[inline]
447    fn next_parse<T: FromStr>(&mut self) -> Result<Option<T>, ScannerError>
448    where
449        ScannerError: From<<T as FromStr>::Err>, {
450        let result = self.next()?;
451
452        match result {
453            // SAFETY: for malformed input `s` may not be valid UTF-8 (technically UB to treat as a `&str`), but it is only fed to a primitive `FromStr` that reads it as bytes, so an invalid token merely fails to parse; validation is skipped for speed.
454            Some(s) => Ok(Some(unsafe { from_utf8_unchecked(s) }.parse()?)),
455            None => Ok(None),
456        }
457    }
458}
459
460impl<'a> ScannerU8Slice<'a> {
461    #[inline]
462    fn next_until_parse<T: FromStr, D: ?Sized + AsRef<[u8]>>(
463        &mut self,
464        boundary: &D,
465    ) -> Result<Option<T>, ScannerError>
466    where
467        ScannerError: From<<T as FromStr>::Err>, {
468        let result = self.next_until(boundary)?;
469
470        match result {
471            // SAFETY: for malformed input `s` may not be valid UTF-8 (technically UB to treat as a `&str`), but it is only fed to a primitive `FromStr` that reads it as bytes, so an invalid token merely fails to parse; validation is skipped for speed.
472            Some(s) => Ok(Some(unsafe { from_utf8_unchecked(s) }.parse()?)),
473            None => Ok(None),
474        }
475    }
476}
477
478macro_rules! scanner_u8_slice_number_methods {
479    ($(($t:ty, $next:ident, $next_until:ident, $sample:literal, $v1:literal, $v2:literal)),+ $(,)?) => {
480        impl<'a> ScannerU8Slice<'a> {
481            $(
482                #[doc = concat!(
483                    "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```"
484                )]
485                #[inline]
486                pub fn $next(&mut self) -> Result<Option<$t>, ScannerError> {
487                    self.next_parse()
488                }
489            )+
490        }
491
492        impl<'a> ScannerU8Slice<'a> {
493            $(
494                #[doc = concat!(
495                    "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)`.\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```"
496                )]
497                #[inline]
498                pub fn $next_until<D: ?Sized + AsRef<[u8]>>(
499                    &mut self,
500                    boundary: &D,
501                ) -> Result<Option<$t>, ScannerError> {
502                    self.next_until_parse(boundary)
503                }
504            )+
505        }
506    };
507}
508
509scanner_u8_slice_number_methods! {
510    (u8, next_u8, next_u8_until, "1 2", 1, 2),
511    (u16, next_u16, next_u16_until, "1 2", 1, 2),
512    (u32, next_u32, next_u32_until, "1 2", 1, 2),
513    (u64, next_u64, next_u64_until, "1 2", 1, 2),
514    (u128, next_u128, next_u128_until, "1 2", 1, 2),
515    (usize, next_usize, next_usize_until, "1 2", 1, 2),
516    (i8, next_i8, next_i8_until, "1 2", 1, 2),
517    (i16, next_i16, next_i16_until, "1 2", 1, 2),
518    (i32, next_i32, next_i32_until, "1 2", 1, 2),
519    (i64, next_i64, next_i64_until, "1 2", 1, 2),
520    (i128, next_i128, next_i128_until, "1 2", 1, 2),
521    (isize, next_isize, next_isize_until, "1 2", 1, 2),
522    (f32, next_f32, next_f32_until, "1 2.5", 1.0, 2.5),
523    (f64, next_f64, next_f64_until, "1 2.5", 1.0, 2.5),
524}
525
526impl<'a> ScannerU8Slice<'a> {
527    /// 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.
528    ///
529    /// ```rust
530    /// use scanner_rust::ScannerU8Slice;
531    ///
532    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
533    ///
534    /// assert_eq!(Some(7), sc.drop_next_line().unwrap());
535    /// assert_eq!(Some("789 ".as_bytes()), sc.next_line().unwrap());
536    /// assert_eq!(Some(0), sc.drop_next_line().unwrap());
537    /// assert_eq!(Some(" 中文 ".as_bytes()), sc.next_line().unwrap());
538    /// assert_eq!(None, sc.drop_next_line().unwrap());
539    /// ```
540    #[inline]
541    pub fn drop_next_line(&mut self) -> Result<Option<usize>, ScannerError> {
542        Ok(self.next_line()?.map(<[u8]>::len))
543    }
544
545    /// 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.
546    ///
547    /// ```rust
548    /// use scanner_rust::ScannerU8Slice;
549    ///
550    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
551    ///
552    /// assert_eq!(Some(3), sc.drop_next().unwrap());
553    /// assert_eq!(Some("456".as_bytes()), sc.next().unwrap());
554    /// assert_eq!(Some(3), sc.drop_next().unwrap());
555    /// assert_eq!(Some("中文".as_bytes()), sc.next().unwrap());
556    /// assert_eq!(None, sc.drop_next().unwrap());
557    /// ```
558    #[inline]
559    pub fn drop_next(&mut self) -> Result<Option<usize>, ScannerError> {
560        Ok(self.next()?.map(<[u8]>::len))
561    }
562
563    /// 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.
564    ///
565    /// ```rust
566    /// use scanner_rust::ScannerU8Slice;
567    ///
568    /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
569    ///
570    /// assert_eq!(Some(7), sc.drop_next_until("\r\n").unwrap());
571    /// assert_eq!(Some("789 ".as_bytes()), sc.next_line().unwrap());
572    /// assert_eq!(Some(0), sc.drop_next_until("\n").unwrap());
573    /// assert_eq!(Some(" 中文 ".as_bytes()), sc.next_line().unwrap());
574    /// assert_eq!(None, sc.drop_next_until("").unwrap());
575    /// ```
576    #[inline]
577    pub fn drop_next_until<D: ?Sized + AsRef<[u8]>>(
578        &mut self,
579        boundary: &D,
580    ) -> Result<Option<usize>, ScannerError> {
581        Ok(self.next_until(boundary)?.map(<[u8]>::len))
582    }
583}
584
585impl<'a> Iterator for ScannerU8Slice<'a> {
586    type Item = &'a [u8];
587
588    #[inline]
589    fn next(&mut self) -> Option<Self::Item> {
590        self.next().unwrap_or(None)
591    }
592}