scanner_rust/scanner_u8_slice.rs
1use std::{
2 char::REPLACEMENT_CHARACTER,
3 str::{FromStr, from_utf8},
4};
5
6use utf8_width::*;
7
8use crate::{ScannerError, kmp::find_boundary, text::numeric_text, 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 match e {
124 b'\n' => {
125 let data = &self.data[self.position..p];
126
127 if p + 1 < self.data_length && self.data[p + 1] == b'\r' {
128 self.position = p + 2;
129 } else {
130 self.position = p + 1;
131 }
132
133 return Ok(Some(data));
134 },
135 b'\r' => {
136 let data = &self.data[self.position..p];
137
138 if p + 1 < self.data_length && self.data[p + 1] == b'\n' {
139 self.position = p + 2;
140 } else {
141 self.position = p + 1;
142 }
143
144 return Ok(Some(data));
145 },
146 _ => (),
147 }
148
149 p += 1;
150
151 if p == self.data_length {
152 break;
153 }
154 }
155
156 let data = &self.data[self.position..p];
157
158 self.position = p;
159
160 Ok(Some(data))
161 }
162}
163
164impl<'a> ScannerU8Slice<'a> {
165 /// Skip the next whitespaces (`javaWhitespace`). If there is nothing to read, it will return `Ok(false)`.
166 ///
167 /// ```rust
168 /// use scanner_rust::ScannerU8Slice;
169 ///
170 /// let mut sc = ScannerU8Slice::new("1 2 c".as_bytes());
171 ///
172 /// assert_eq!(Some('1'), sc.next_char().unwrap());
173 /// assert_eq!(Some(' '), sc.next_char().unwrap());
174 /// assert_eq!(Some('2'), sc.next_char().unwrap());
175 /// assert_eq!(true, sc.skip_whitespaces().unwrap());
176 /// assert_eq!(Some('c'), sc.next_char().unwrap());
177 /// assert_eq!(false, sc.skip_whitespaces().unwrap());
178 /// ```
179 pub fn skip_whitespaces(&mut self) -> Result<bool, ScannerError> {
180 if self.position == self.data_length {
181 return Ok(false);
182 }
183
184 loop {
185 let e = self.data[self.position];
186
187 let width = get_width(e);
188
189 match width {
190 0 => {
191 break;
192 },
193 1 => {
194 if !is_whitespace_1(e) {
195 break;
196 }
197
198 self.position += 1;
199 },
200 3 if self.position + width <= self.data_length
201 && is_whitespace_3(
202 self.data[self.position],
203 self.data[self.position + 1],
204 self.data[self.position + 2],
205 ) =>
206 {
207 self.position += 3;
208 },
209 _ => {
210 break;
211 },
212 }
213
214 if self.position == self.data_length {
215 break;
216 }
217 }
218
219 Ok(true)
220 }
221
222 /// Read the next token separated by whitespaces. If there is nothing to read, it will return `Ok(None)`.
223 ///
224 /// ```rust
225 /// use scanner_rust::ScannerU8Slice;
226 ///
227 /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
228 ///
229 /// assert_eq!(Some("123".as_bytes()), sc.next().unwrap());
230 /// assert_eq!(Some("456".as_bytes()), sc.next().unwrap());
231 /// assert_eq!(Some("789".as_bytes()), sc.next().unwrap());
232 /// assert_eq!(Some("中文".as_bytes()), sc.next().unwrap());
233 /// assert_eq!(None, sc.next().unwrap());
234 /// ```
235 #[allow(clippy::should_implement_trait)]
236 pub fn next(&mut self) -> Result<Option<&'a [u8]>, ScannerError> {
237 if !self.skip_whitespaces()? || self.position == self.data_length {
238 return Ok(None);
239 }
240
241 let mut p = self.position;
242
243 while p < self.data_length {
244 let e = self.data[p];
245 let width = get_width(e);
246
247 if is_whitespace_1(e)
248 || (width == 3
249 && self.data_length - p >= 3
250 && is_whitespace_3(self.data[p], self.data[p + 1], self.data[p + 2]))
251 {
252 break;
253 }
254
255 if width > 1
256 && self.data_length - p >= width
257 && self.data[(p + 1)..(p + width)].iter().all(|byte| byte & 0xC0 == 0x80)
258 {
259 p += width;
260 } else {
261 p += 1;
262 }
263 }
264
265 let data = &self.data[self.position..p];
266
267 self.position = p;
268
269 Ok(Some(data))
270 }
271}
272
273impl<'a> ScannerU8Slice<'a> {
274 /// Read the next bytes. If there is nothing to read, it will return `Ok(None)`.
275 ///
276 /// ```rust
277 /// use scanner_rust::ScannerU8Slice;
278 ///
279 /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
280 ///
281 /// assert_eq!(Some("123".as_bytes()), sc.next_bytes(3).unwrap());
282 /// assert_eq!(Some(" 456".as_bytes()), sc.next_bytes(4).unwrap());
283 /// assert_eq!(Some("\r\n789 ".as_bytes()), sc.next_bytes(6).unwrap());
284 /// assert_eq!(Some("中文".as_bytes()), sc.next().unwrap());
285 /// assert_eq!(Some(" ".as_bytes()), sc.next_bytes(2).unwrap());
286 /// assert_eq!(None, sc.next_bytes(2).unwrap());
287 /// ```
288 pub fn next_bytes(
289 &mut self,
290 max_number_of_bytes: usize,
291 ) -> Result<Option<&'a [u8]>, ScannerError> {
292 if self.position == self.data_length {
293 return Ok(None);
294 }
295
296 let dropping_bytes = max_number_of_bytes.min(self.data_length - self.position);
297
298 let data = &self.data[self.position..(self.position + dropping_bytes)];
299
300 self.position += dropping_bytes;
301
302 Ok(Some(data))
303 }
304
305 /// 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.
306 ///
307 /// ```rust
308 /// use scanner_rust::ScannerU8Slice;
309 ///
310 /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
311 ///
312 /// assert_eq!(Some(7), sc.drop_next_bytes(7).unwrap());
313 /// assert_eq!(Some("".as_bytes()), sc.next_line().unwrap());
314 /// assert_eq!(Some("789 ".as_bytes()), sc.next_line().unwrap());
315 /// assert_eq!(Some(1), sc.drop_next_bytes(1).unwrap());
316 /// assert_eq!(Some(" 中文 ".as_bytes()), sc.next_line().unwrap());
317 /// assert_eq!(None, sc.drop_next_bytes(1).unwrap());
318 /// ```
319 pub fn drop_next_bytes(
320 &mut self,
321 max_number_of_bytes: usize,
322 ) -> Result<Option<usize>, ScannerError> {
323 if self.position == self.data_length {
324 return Ok(None);
325 }
326
327 let dropping_bytes = max_number_of_bytes.min(self.data_length - self.position);
328
329 self.position += dropping_bytes;
330
331 Ok(Some(dropping_bytes))
332 }
333}
334
335impl<'a> ScannerU8Slice<'a> {
336 /// Read the next data 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::ScannerU8Slice;
342 ///
343 /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
344 ///
345 /// assert_eq!(Some("123".as_bytes()), sc.next_until(" ").unwrap());
346 /// assert_eq!(Some("456\r".as_bytes()), sc.next_until("\n").unwrap());
347 /// assert_eq!(Some("78".as_bytes()), sc.next_until("9 ").unwrap());
348 /// assert_eq!(Some("\n\n 中文 ".as_bytes()), sc.next_until("kk").unwrap());
349 /// assert_eq!(None, sc.next().unwrap());
350 /// ```
351 pub fn next_until<D: ?Sized + AsRef<[u8]>>(
352 &mut self,
353 boundary: &D,
354 ) -> Result<Option<&'a [u8]>, ScannerError> {
355 if self.position == self.data_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.data_length - self.position {
363 let data = &self.data[self.position..];
364
365 self.position = self.data_length;
366
367 return Ok(Some(data));
368 }
369
370 if let Some(offset) = find_boundary(&self.data[self.position..], boundary) {
371 let end = self.position + offset;
372 let data = &self.data[self.position..end];
373
374 self.position = end + boundary_length;
375
376 return Ok(Some(data));
377 }
378
379 let data = &self.data[self.position..];
380
381 self.position = self.data_length;
382
383 Ok(Some(data))
384 }
385}
386
387impl<'a> ScannerU8Slice<'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(numeric_text(s).parse()?)),
396 None => Ok(None),
397 }
398 }
399}
400
401impl<'a> ScannerU8Slice<'a> {
402 #[inline]
403 fn next_until_parse<T: FromStr, D: ?Sized + AsRef<[u8]>>(
404 &mut self,
405 boundary: &D,
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(numeric_text(s).parse()?)),
413 None => Ok(None),
414 }
415 }
416}
417
418macro_rules! scanner_u8_slice_number_methods {
419 ($(($t:ty, $next:ident, $next_until:ident, $sample:literal, $v1:literal, $v2:literal)),+ $(,)?) => {
420 impl<'a> ScannerU8Slice<'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::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```"
424 )]
425 #[inline]
426 pub fn $next(&mut self) -> Result<Option<$t>, ScannerError> {
427 self.next_parse()
428 }
429 )+
430 }
431
432 impl<'a> ScannerU8Slice<'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::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```"
436 )]
437 #[inline]
438 pub fn $next_until<D: ?Sized + AsRef<[u8]>>(
439 &mut self,
440 boundary: &D,
441 ) -> Result<Option<$t>, ScannerError> {
442 self.next_until_parse(boundary)
443 }
444 )+
445 }
446 };
447}
448
449scanner_u8_slice_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> ScannerU8Slice<'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::ScannerU8Slice;
471 ///
472 /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
473 ///
474 /// assert_eq!(Some(7), sc.drop_next_line().unwrap());
475 /// assert_eq!(Some("789 ".as_bytes()), sc.next_line().unwrap());
476 /// assert_eq!(Some(0), sc.drop_next_line().unwrap());
477 /// assert_eq!(Some(" 中文 ".as_bytes()), 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(<[u8]>::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::ScannerU8Slice;
489 ///
490 /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
491 ///
492 /// assert_eq!(Some(3), sc.drop_next().unwrap());
493 /// assert_eq!(Some("456".as_bytes()), sc.next().unwrap());
494 /// assert_eq!(Some(3), sc.drop_next().unwrap());
495 /// assert_eq!(Some("中文".as_bytes()), 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(<[u8]>::len))
501 }
502
503 /// 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.
504 ///
505 /// An empty boundary drops all remaining data.
506 ///
507 /// ```rust
508 /// use scanner_rust::ScannerU8Slice;
509 ///
510 /// let mut sc = ScannerU8Slice::new("123 456\r\n789 \n\n 中文 ".as_bytes());
511 ///
512 /// assert_eq!(Some(7), sc.drop_next_until("\r\n").unwrap());
513 /// assert_eq!(Some("789 ".as_bytes()), sc.next_line().unwrap());
514 /// assert_eq!(Some(0), sc.drop_next_until("\n").unwrap());
515 /// assert_eq!(Some(" 中文 ".as_bytes()), sc.next_line().unwrap());
516 /// assert_eq!(None, sc.drop_next_until("").unwrap());
517 /// ```
518 #[inline]
519 pub fn drop_next_until<D: ?Sized + AsRef<[u8]>>(
520 &mut self,
521 boundary: &D,
522 ) -> Result<Option<usize>, ScannerError> {
523 Ok(self.next_until(boundary)?.map(<[u8]>::len))
524 }
525}
526
527impl<'a> Iterator for ScannerU8Slice<'a> {
528 type Item = &'a [u8];
529
530 #[inline]
531 fn next(&mut self) -> Option<Self::Item> {
532 self.next().unwrap_or(None)
533 }
534}