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}