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 UTF-8 character. 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 /// An empty boundary reads all remaining data.
339 ///
340 /// ```rust
341 /// use scanner_rust::ScannerStr;
342 ///
343 /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
344 ///
345 /// assert_eq!(Some("123"), sc.next_until(" ").unwrap());
346 /// assert_eq!(Some("456\r"), sc.next_until("\n").unwrap());
347 /// assert_eq!(Some("78"), sc.next_until("9 ").unwrap());
348 /// assert_eq!(Some("\n\n 中文 "), sc.next_until("kk").unwrap());
349 /// assert_eq!(None, sc.next().unwrap());
350 /// ```
351 pub fn next_until<S: AsRef<str>>(
352 &mut self,
353 boundary: S,
354 ) -> Result<Option<&'a str>, ScannerError> {
355 if self.position == self.text_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.text_length - self.position {
363 let text = &self.text[self.position..];
364
365 self.position = self.text_length;
366
367 return Ok(Some(text));
368 }
369
370 if let Some(offset) = self.text[self.position..].find(boundary) {
371 let end = self.position + offset;
372 let text = &self.text[self.position..end];
373
374 self.position = end + boundary_length;
375
376 return Ok(Some(text));
377 }
378
379 let text = &self.text[self.position..];
380
381 self.position = self.text_length;
382
383 Ok(Some(text))
384 }
385}
386
387impl<'a> ScannerStr<'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(s.parse()?)),
396 None => Ok(None),
397 }
398 }
399}
400
401impl<'a> ScannerStr<'a> {
402 #[inline]
403 fn next_raw_parse<T: FromStr, S: AsRef<str>>(
404 &mut self,
405 boundary: S,
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(s.parse()?)),
413 None => Ok(None),
414 }
415 }
416}
417
418macro_rules! scanner_str_number_methods {
419 ($(($t:ty, $next:ident, $next_until:ident, $sample:literal, $v1:literal, $v2:literal)),+ $(,)?) => {
420 impl<'a> ScannerStr<'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::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```"
424 )]
425 #[inline]
426 pub fn $next(&mut self) -> Result<Option<$t>, ScannerError> {
427 self.next_parse()
428 }
429 )+
430 }
431
432 impl<'a> ScannerStr<'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::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```"
436 )]
437 #[inline]
438 pub fn $next_until<S: AsRef<str>>(
439 &mut self,
440 boundary: S,
441 ) -> Result<Option<$t>, ScannerError> {
442 self.next_raw_parse(boundary)
443 }
444 )+
445 }
446 };
447}
448
449scanner_str_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> ScannerStr<'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::ScannerStr;
471 ///
472 /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
473 ///
474 /// assert_eq!(Some(7), sc.drop_next_line().unwrap());
475 /// assert_eq!(Some("789 "), sc.next_line().unwrap());
476 /// assert_eq!(Some(0), sc.drop_next_line().unwrap());
477 /// assert_eq!(Some(" 中文 "), 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(str::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::ScannerStr;
489 ///
490 /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
491 ///
492 /// assert_eq!(Some(3), sc.drop_next().unwrap());
493 /// assert_eq!(Some("456"), sc.next().unwrap());
494 /// assert_eq!(Some(3), sc.drop_next().unwrap());
495 /// assert_eq!(Some("中文"), 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(str::len))
501 }
502
503 /// 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.
504 ///
505 /// An empty boundary drops all remaining data.
506 ///
507 /// ```rust
508 /// use scanner_rust::ScannerStr;
509 ///
510 /// let mut sc = ScannerStr::new("123 456\r\n789 \n\n 中文 ");
511 ///
512 /// assert_eq!(Some(7), sc.drop_next_until("\r\n").unwrap());
513 /// assert_eq!(Some("789 "), sc.next_line().unwrap());
514 /// assert_eq!(Some(0), sc.drop_next_until("\n").unwrap());
515 /// assert_eq!(Some(" 中文 "), sc.next_line().unwrap());
516 /// assert_eq!(None, sc.drop_next_until("").unwrap());
517 /// ```
518 #[inline]
519 pub fn drop_next_until<S: AsRef<str>>(
520 &mut self,
521 boundary: S,
522 ) -> Result<Option<usize>, ScannerError> {
523 Ok(self.next_until(boundary)?.map(str::len))
524 }
525}
526
527impl<'a> Iterator for ScannerStr<'a> {
528 type Item = &'a str;
529
530 #[inline]
531 fn next(&mut self) -> Option<Self::Item> {
532 self.next().unwrap_or(None)
533 }
534}