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 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)`.
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 /// ```rust
339 /// use scanner_rust::ScannerStr;
340 ///
341 /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
342 ///
343 /// assert_eq!(Some("123"), sc.next_until(" ").unwrap());
344 /// assert_eq!(Some("456\r"), sc.next_until("\n").unwrap());
345 /// assert_eq!(Some("78"), sc.next_until("9 ").unwrap());
346 /// assert_eq!(Some("\n\n 中文 "), sc.next_until("kk").unwrap());
347 /// assert_eq!(None, sc.next().unwrap());
348 /// ```
349 pub fn next_until<S: AsRef<str>>(
350 &mut self,
351 boundary: S,
352 ) -> Result<Option<&'a str>, ScannerError> {
353 if self.position == self.text_length {
354 return Ok(None);
355 }
356
357 let boundary = boundary.as_ref().as_bytes();
358 let boundary_length = boundary.len();
359
360 if boundary_length == 0 || boundary_length > self.text_length - self.position {
361 let text = &self.text[self.position..];
362
363 self.position = self.text_length;
364
365 return Ok(Some(text));
366 }
367
368 let data = self.text.as_bytes();
369
370 for i in self.position..=(self.text_length - boundary_length) {
371 let e = i + boundary_length;
372
373 if &data[i..e] == boundary {
374 let text = &self.text[self.position..i];
375
376 self.position = e;
377
378 return Ok(Some(text));
379 }
380 }
381
382 let text = &self.text[self.position..];
383
384 self.position = self.text_length;
385
386 Ok(Some(text))
387 }
388}
389
390impl<'a> ScannerStr<'a> {
391 #[inline]
392 fn next_parse<T: FromStr>(&mut self) -> Result<Option<T>, ScannerError>
393 where
394 ScannerError: From<<T as FromStr>::Err>, {
395 let result = self.next()?;
396
397 match result {
398 Some(s) => Ok(Some(s.parse()?)),
399 None => Ok(None),
400 }
401 }
402}
403
404impl<'a> ScannerStr<'a> {
405 #[inline]
406 fn next_raw_parse<T: FromStr, S: AsRef<str>>(
407 &mut self,
408 boundary: S,
409 ) -> Result<Option<T>, ScannerError>
410 where
411 ScannerError: From<<T as FromStr>::Err>, {
412 let result = self.next_until(boundary)?;
413
414 match result {
415 Some(s) => Ok(Some(s.parse()?)),
416 None => Ok(None),
417 }
418 }
419}
420
421macro_rules! scanner_str_number_methods {
422 ($(($t:ty, $next:ident, $next_until:ident, $sample:literal, $v1:literal, $v2:literal)),+ $(,)?) => {
423 impl<'a> ScannerStr<'a> {
424 $(
425 #[doc = concat!(
426 "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```"
427 )]
428 #[inline]
429 pub fn $next(&mut self) -> Result<Option<$t>, ScannerError> {
430 self.next_parse()
431 }
432 )+
433 }
434
435 impl<'a> ScannerStr<'a> {
436 $(
437 #[doc = concat!(
438 "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::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```"
439 )]
440 #[inline]
441 pub fn $next_until<S: AsRef<str>>(
442 &mut self,
443 boundary: S,
444 ) -> Result<Option<$t>, ScannerError> {
445 self.next_raw_parse(boundary)
446 }
447 )+
448 }
449 };
450}
451
452scanner_str_number_methods! {
453 (u8, next_u8, next_u8_until, "1 2", 1, 2),
454 (u16, next_u16, next_u16_until, "1 2", 1, 2),
455 (u32, next_u32, next_u32_until, "1 2", 1, 2),
456 (u64, next_u64, next_u64_until, "1 2", 1, 2),
457 (u128, next_u128, next_u128_until, "1 2", 1, 2),
458 (usize, next_usize, next_usize_until, "1 2", 1, 2),
459 (i8, next_i8, next_i8_until, "1 2", 1, 2),
460 (i16, next_i16, next_i16_until, "1 2", 1, 2),
461 (i32, next_i32, next_i32_until, "1 2", 1, 2),
462 (i64, next_i64, next_i64_until, "1 2", 1, 2),
463 (i128, next_i128, next_i128_until, "1 2", 1, 2),
464 (isize, next_isize, next_isize_until, "1 2", 1, 2),
465 (f32, next_f32, next_f32_until, "1 2.5", 1.0, 2.5),
466 (f64, next_f64, next_f64_until, "1 2.5", 1.0, 2.5),
467}
468
469impl<'a> ScannerStr<'a> {
470 /// 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.
471 ///
472 /// ```rust
473 /// use scanner_rust::ScannerStr;
474 ///
475 /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
476 ///
477 /// assert_eq!(Some(7), sc.drop_next_line().unwrap());
478 /// assert_eq!(Some("789 "), sc.next_line().unwrap());
479 /// assert_eq!(Some(0), sc.drop_next_line().unwrap());
480 /// assert_eq!(Some(" 中文 "), sc.next_line().unwrap());
481 /// assert_eq!(None, sc.drop_next_line().unwrap());
482 /// ```
483 #[inline]
484 pub fn drop_next_line(&mut self) -> Result<Option<usize>, ScannerError> {
485 Ok(self.next_line()?.map(str::len))
486 }
487
488 /// 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.
489 ///
490 /// ```rust
491 /// use scanner_rust::ScannerStr;
492 ///
493 /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
494 ///
495 /// assert_eq!(Some(3), sc.drop_next().unwrap());
496 /// assert_eq!(Some("456"), sc.next().unwrap());
497 /// assert_eq!(Some(3), sc.drop_next().unwrap());
498 /// assert_eq!(Some("中文"), sc.next().unwrap());
499 /// assert_eq!(None, sc.drop_next().unwrap());
500 /// ```
501 #[inline]
502 pub fn drop_next(&mut self) -> Result<Option<usize>, ScannerError> {
503 Ok(self.next()?.map(str::len))
504 }
505
506 /// 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.
507 ///
508 /// ```rust
509 /// use scanner_rust::ScannerStr;
510 ///
511 /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
512 ///
513 /// assert_eq!(Some(7), sc.drop_next_until("\r\n").unwrap());
514 /// assert_eq!(Some("789 "), sc.next_line().unwrap());
515 /// assert_eq!(Some(0), sc.drop_next_until("\n").unwrap());
516 /// assert_eq!(Some(" 中文 "), sc.next_line().unwrap());
517 /// assert_eq!(None, sc.drop_next_until("").unwrap());
518 /// ```
519 #[inline]
520 pub fn drop_next_until<S: AsRef<str>>(
521 &mut self,
522 boundary: S,
523 ) -> Result<Option<usize>, ScannerError> {
524 Ok(self.next_until(boundary)?.map(str::len))
525 }
526}
527
528impl<'a> Iterator for ScannerStr<'a> {
529 type Item = &'a str;
530
531 #[inline]
532 fn next(&mut self) -> Option<Self::Item> {
533 self.next().unwrap_or(None)
534 }
535}