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