Skip to main content

scanner_rust/
scanner_str.rs

1use std::str::FromStr;
2
3use utf8_width::*;
4
5use crate::{ScannerError, whitespaces::*};
6
7/// A simple text scanner which can in-memory-ly parse primitive types and strings using UTF-8 from a string slice.
8#[derive(Debug)]
9pub struct ScannerStr<'a> {
10    text:        &'a str,
11    text_length: usize,
12    position:    usize,
13}
14
15impl<'a> ScannerStr<'a> {
16    /// Create a scanner from a string.
17    ///
18    /// ```rust
19    /// use std::io;
20    ///
21    /// use scanner_rust::ScannerStr;
22    ///
23    /// let mut sc = ScannerStr::new("123 456");
24    /// ```
25    #[inline]
26    pub fn new<S: ?Sized + AsRef<str>>(text: &S) -> ScannerStr<'_> {
27        let text = text.as_ref();
28
29        ScannerStr {
30            text,
31            text_length: text.len(),
32            position: 0,
33        }
34    }
35}
36
37impl<'a> ScannerStr<'a> {
38    /// Read the next UTF-8 character. If there is nothing to read, it will return `Ok(None)`.
39    ///
40    /// ```rust
41    /// use scanner_rust::ScannerStr;
42    ///
43    /// let mut sc = ScannerStr::new("5 c 中文");
44    ///
45    /// assert_eq!(Some('5'), sc.next_char().unwrap());
46    /// assert_eq!(Some(' '), sc.next_char().unwrap());
47    /// assert_eq!(Some('c'), sc.next_char().unwrap());
48    /// assert_eq!(Some(' '), sc.next_char().unwrap());
49    /// assert_eq!(Some('中'), sc.next_char().unwrap());
50    /// assert_eq!(Some('文'), sc.next_char().unwrap());
51    /// assert_eq!(None, sc.next_char().unwrap());
52    /// ```
53    pub fn next_char(&mut self) -> Result<Option<char>, ScannerError> {
54        if self.position == self.text_length {
55            return Ok(None);
56        }
57
58        let data = self.text.as_bytes();
59
60        let e = data[self.position];
61
62        let width = unsafe { get_width_assume_valid(e) };
63
64        match width {
65            1 => {
66                self.position += 1;
67
68                Ok(Some(e as char))
69            },
70            _ => {
71                let char_str = &self.text[self.position..(self.position + width)];
72
73                self.position += width;
74
75                Ok(char_str.chars().next())
76            },
77        }
78    }
79
80    /// 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)`.
81    ///
82    /// ```rust
83    /// use scanner_rust::ScannerStr;
84    ///
85    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
86    ///
87    /// assert_eq!(Some("123 456"), sc.next_line().unwrap());
88    /// assert_eq!(Some("789 "), sc.next_line().unwrap());
89    /// assert_eq!(Some(""), sc.next_line().unwrap());
90    /// assert_eq!(Some(" 中文 "), sc.next_line().unwrap());
91    /// ```
92    pub fn next_line(&mut self) -> Result<Option<&'a str>, ScannerError> {
93        if self.position == self.text_length {
94            return Ok(None);
95        }
96
97        let data = self.text.as_bytes();
98
99        let mut p = self.position;
100
101        loop {
102            let e = data[p];
103
104            let width = unsafe { get_width_assume_valid(e) };
105
106            match width {
107                1 => {
108                    match e {
109                        b'\n' => {
110                            let text = &self.text[self.position..p];
111
112                            if p + 1 < self.text_length && data[p + 1] == b'\r' {
113                                self.position = p + 2;
114                            } else {
115                                self.position = p + 1;
116                            }
117
118                            return Ok(Some(text));
119                        },
120                        b'\r' => {
121                            let text = &self.text[self.position..p];
122
123                            if p + 1 < self.text_length && data[p + 1] == b'\n' {
124                                self.position = p + 2;
125                            } else {
126                                self.position = p + 1;
127                            }
128
129                            return Ok(Some(text));
130                        },
131                        _ => (),
132                    }
133
134                    p += 1;
135                },
136                _ => {
137                    p += width;
138                },
139            }
140
141            if p == self.text_length {
142                break;
143            }
144        }
145
146        let text = &self.text[self.position..p];
147
148        self.position = p;
149
150        Ok(Some(text))
151    }
152}
153
154impl<'a> ScannerStr<'a> {
155    /// Skip the next whitespaces (`javaWhitespace`). If there is nothing to read, it will return `Ok(false)`.
156    ///
157    /// ```rust
158    /// use scanner_rust::ScannerStr;
159    ///
160    /// let mut sc = ScannerStr::new("1 2   c");
161    ///
162    /// assert_eq!(Some('1'), sc.next_char().unwrap());
163    /// assert_eq!(Some(' '), sc.next_char().unwrap());
164    /// assert_eq!(Some('2'), sc.next_char().unwrap());
165    /// assert_eq!(true, sc.skip_whitespaces().unwrap());
166    /// assert_eq!(Some('c'), sc.next_char().unwrap());
167    /// assert_eq!(false, sc.skip_whitespaces().unwrap());
168    /// ```
169    pub fn skip_whitespaces(&mut self) -> Result<bool, ScannerError> {
170        if self.position == self.text_length {
171            return Ok(false);
172        }
173
174        let data = self.text.as_bytes();
175
176        loop {
177            let e = data[self.position];
178
179            let width = unsafe { get_width_assume_valid(e) };
180
181            match width {
182                1 => {
183                    if !is_whitespace_1(e) {
184                        break;
185                    }
186
187                    self.position += 1;
188                },
189                3 => {
190                    if !is_whitespace_3(
191                        data[self.position],
192                        data[self.position + 1],
193                        data[self.position + 2],
194                    ) {
195                        break;
196                    }
197
198                    self.position += 3;
199                },
200                _ => {
201                    break;
202                },
203            }
204
205            if self.position == self.text_length {
206                break;
207            }
208        }
209
210        Ok(true)
211    }
212
213    /// Read the next token separated by whitespaces. If there is nothing to read, it will return `Ok(None)`.
214    ///
215    /// ```rust
216    /// use scanner_rust::ScannerStr;
217    ///
218    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
219    ///
220    /// assert_eq!(Some("123"), sc.next().unwrap());
221    /// assert_eq!(Some("456"), sc.next().unwrap());
222    /// assert_eq!(Some("789"), sc.next().unwrap());
223    /// assert_eq!(Some("中文"), sc.next().unwrap());
224    /// assert_eq!(None, sc.next().unwrap());
225    /// ```
226    #[allow(clippy::should_implement_trait)]
227    pub fn next(&mut self) -> Result<Option<&'a str>, ScannerError> {
228        if !self.skip_whitespaces()? {
229            return Ok(None);
230        }
231
232        if self.position == self.text_length {
233            return Ok(None);
234        }
235
236        let data = self.text.as_bytes();
237
238        let mut p = self.position;
239
240        loop {
241            let e = data[p];
242
243            let width = unsafe { get_width_assume_valid(e) };
244
245            match width {
246                1 => {
247                    if is_whitespace_1(e) {
248                        let text = &self.text[self.position..p];
249
250                        self.position = p;
251
252                        return Ok(Some(text));
253                    }
254
255                    p += 1;
256                },
257                3 => {
258                    if is_whitespace_3(data[p], data[p + 1], data[p + 2]) {
259                        let text = &self.text[self.position..p];
260
261                        self.position = p;
262
263                        return Ok(Some(text));
264                    } else {
265                        p += 3;
266                    }
267                },
268                _ => {
269                    p += width;
270                },
271            }
272
273            if p == self.text_length {
274                break;
275            }
276        }
277
278        let text = &self.text[self.position..p];
279
280        self.position = p;
281
282        Ok(Some(text))
283    }
284}
285
286impl<'a> ScannerStr<'a> {
287    /// Read the next text (as a string slice) with a specific max number of characters. If there is nothing to read, it will return `Ok(None)`.
288    ///
289    /// ```rust
290    /// use scanner_rust::ScannerStr;
291    ///
292    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
293    ///
294    /// assert_eq!(Some("123"), sc.next_str(3).unwrap());
295    /// assert_eq!(Some(" 456"), sc.next_str(4).unwrap());
296    /// assert_eq!(Some("\r\n789 "), sc.next_str(6).unwrap());
297    /// assert_eq!(Some("\n\n 中"), sc.next_str(4).unwrap());
298    /// assert_eq!(Some("文"), sc.next().unwrap());
299    /// assert_eq!(Some(" "), sc.next_str(2).unwrap());
300    /// assert_eq!(None, sc.next_str(2).unwrap());
301    /// ```
302    pub fn next_str(
303        &mut self,
304        max_number_of_characters: usize,
305    ) -> Result<Option<&'a str>, ScannerError> {
306        if self.position == self.text_length {
307            return Ok(None);
308        }
309
310        let data = self.text.as_bytes();
311
312        let mut p = self.position;
313        let mut c = 0;
314
315        while c < max_number_of_characters {
316            let width = unsafe { get_width_assume_valid(data[p]) };
317
318            p += width;
319
320            c += 1;
321
322            if p == self.text_length {
323                break;
324            }
325        }
326
327        let text = &self.text[self.position..p];
328
329        self.position = p;
330
331        Ok(Some(text))
332    }
333}
334
335impl<'a> ScannerStr<'a> {
336    /// Read the next text 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::ScannerStr;
342    ///
343    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
344    ///
345    /// assert_eq!(Some("123"), sc.next_until(" ").unwrap());
346    /// assert_eq!(Some("456\r"), sc.next_until("\n").unwrap());
347    /// assert_eq!(Some("78"), sc.next_until("9 ").unwrap());
348    /// assert_eq!(Some("\n\n 中文 "), sc.next_until("kk").unwrap());
349    /// assert_eq!(None, sc.next().unwrap());
350    /// ```
351    pub fn next_until<S: AsRef<str>>(
352        &mut self,
353        boundary: S,
354    ) -> Result<Option<&'a str>, ScannerError> {
355        if self.position == self.text_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.text_length - self.position {
363            let text = &self.text[self.position..];
364
365            self.position = self.text_length;
366
367            return Ok(Some(text));
368        }
369
370        if let Some(offset) = self.text[self.position..].find(boundary) {
371            let end = self.position + offset;
372            let text = &self.text[self.position..end];
373
374            self.position = end + boundary_length;
375
376            return Ok(Some(text));
377        }
378
379        let text = &self.text[self.position..];
380
381        self.position = self.text_length;
382
383        Ok(Some(text))
384    }
385}
386
387impl<'a> ScannerStr<'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(s.parse()?)),
396            None => Ok(None),
397        }
398    }
399}
400
401impl<'a> ScannerStr<'a> {
402    #[inline]
403    fn next_raw_parse<T: FromStr, S: AsRef<str>>(
404        &mut self,
405        boundary: S,
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(s.parse()?)),
413            None => Ok(None),
414        }
415    }
416}
417
418macro_rules! scanner_str_number_methods {
419    ($(($t:ty, $next:ident, $next_until:ident, $sample:literal, $v1:literal, $v2:literal)),+ $(,)?) => {
420        impl<'a> ScannerStr<'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::ScannerStr;\n\nlet mut sc = ScannerStr::new(", stringify!($sample), ");\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> ScannerStr<'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::ScannerStr;\n\nlet mut sc = ScannerStr::new(", stringify!($sample), ");\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<S: AsRef<str>>(
439                    &mut self,
440                    boundary: S,
441                ) -> Result<Option<$t>, ScannerError> {
442                    self.next_raw_parse(boundary)
443                }
444            )+
445        }
446    };
447}
448
449scanner_str_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> ScannerStr<'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::ScannerStr;
471    ///
472    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
473    ///
474    /// assert_eq!(Some(7), sc.drop_next_line().unwrap());
475    /// assert_eq!(Some("789 "), sc.next_line().unwrap());
476    /// assert_eq!(Some(0), sc.drop_next_line().unwrap());
477    /// assert_eq!(Some(" 中文 "), 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(str::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::ScannerStr;
489    ///
490    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
491    ///
492    /// assert_eq!(Some(3), sc.drop_next().unwrap());
493    /// assert_eq!(Some("456"), sc.next().unwrap());
494    /// assert_eq!(Some(3), sc.drop_next().unwrap());
495    /// assert_eq!(Some("中文"), 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(str::len))
501    }
502
503    /// Drop the next text 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 text, excluding the boundary.
504    ///
505    /// An empty boundary drops all remaining data.
506    ///
507    /// ```rust
508    /// use scanner_rust::ScannerStr;
509    ///
510    /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
511    ///
512    /// assert_eq!(Some(7), sc.drop_next_until("\r\n").unwrap());
513    /// assert_eq!(Some("789 "), sc.next_line().unwrap());
514    /// assert_eq!(Some(0), sc.drop_next_until("\n").unwrap());
515    /// assert_eq!(Some(" 中文 "), sc.next_line().unwrap());
516    /// assert_eq!(None, sc.drop_next_until("").unwrap());
517    /// ```
518    #[inline]
519    pub fn drop_next_until<S: AsRef<str>>(
520        &mut self,
521        boundary: S,
522    ) -> Result<Option<usize>, ScannerError> {
523        Ok(self.next_until(boundary)?.map(str::len))
524    }
525}
526
527impl<'a> Iterator for ScannerStr<'a> {
528    type Item = &'a str;
529
530    #[inline]
531    fn next(&mut self) -> Option<Self::Item> {
532        self.next().unwrap_or(None)
533    }
534}