Skip to main content

scanner_rust/
scanner_u8_slice_ascii.rs

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