Coverage Report

Created: 2023-04-25 07:07

/rust/registry/src/index.crates.io-6f17d22bba15001f/rayon-1.5.2/src/str.rs
Line
Count
Source (jump to first uncovered line)
1
//! Parallel iterator types for [strings][std::str]
2
//!
3
//! You will rarely need to interact with this module directly unless you need
4
//! to name one of the iterator types.
5
//!
6
//! Note: [`ParallelString::par_split()`] and [`par_split_terminator()`]
7
//! reference a `Pattern` trait which is not visible outside this crate.
8
//! This trait is intentionally kept private, for use only by Rayon itself.
9
//! It is implemented for `char`, `&[char]`, and any function or closure
10
//! `F: Fn(char) -> bool + Sync + Send`.
11
//!
12
//! [`ParallelString::par_split()`]: trait.ParallelString.html#method.par_split
13
//! [`par_split_terminator()`]: trait.ParallelString.html#method.par_split_terminator
14
//!
15
//! [std::str]: https://doc.rust-lang.org/stable/std/str/
16
17
use crate::iter::plumbing::*;
18
use crate::iter::*;
19
use crate::split_producer::*;
20
21
/// Test if a byte is the start of a UTF-8 character.
22
/// (extracted from `str::is_char_boundary`)
23
#[inline]
24
0
fn is_char_boundary(b: u8) -> bool {
25
0
    // This is bit magic equivalent to: b < 128 || b >= 192
26
0
    (b as i8) >= -0x40
27
0
}
28
29
/// Find the index of a character boundary near the midpoint.
30
#[inline]
31
0
fn find_char_midpoint(chars: &str) -> usize {
32
0
    let mid = chars.len() / 2;
33
0
34
0
    // We want to split near the midpoint, but we need to find an actual
35
0
    // character boundary.  So we look at the raw bytes, first scanning
36
0
    // forward from the midpoint for a boundary, then trying backward.
37
0
    let (left, right) = chars.as_bytes().split_at(mid);
38
0
    match right.iter().copied().position(is_char_boundary) {
39
0
        Some(i) => mid + i,
40
0
        None => left
41
0
            .iter()
42
0
            .copied()
43
0
            .rposition(is_char_boundary)
44
0
            .unwrap_or(0),
45
    }
46
0
}
47
48
/// Try to split a string near the midpoint.
49
#[inline]
50
0
fn split(chars: &str) -> Option<(&str, &str)> {
51
0
    let index = find_char_midpoint(chars);
52
0
    if index > 0 {
53
0
        Some(chars.split_at(index))
54
    } else {
55
0
        None
56
    }
57
0
}
58
59
/// Parallel extensions for strings.
60
pub trait ParallelString {
61
    /// Returns a plain string slice, which is used to implement the rest of
62
    /// the parallel methods.
63
    fn as_parallel_string(&self) -> &str;
64
65
    /// Returns a parallel iterator over the characters of a string.
66
    ///
67
    /// # Examples
68
    ///
69
    /// ```
70
    /// use rayon::prelude::*;
71
    /// let max = "hello".par_chars().max_by_key(|c| *c as i32);
72
    /// assert_eq!(Some('o'), max);
73
    /// ```
74
0
    fn par_chars(&self) -> Chars<'_> {
75
0
        Chars {
76
0
            chars: self.as_parallel_string(),
77
0
        }
78
0
    }
79
80
    /// Returns a parallel iterator over the characters of a string, with their positions.
81
    ///
82
    /// # Examples
83
    ///
84
    /// ```
85
    /// use rayon::prelude::*;
86
    /// let min = "hello".par_char_indices().min_by_key(|&(_i, c)| c as i32);
87
    /// assert_eq!(Some((1, 'e')), min);
88
    /// ```
89
0
    fn par_char_indices(&self) -> CharIndices<'_> {
90
0
        CharIndices {
91
0
            chars: self.as_parallel_string(),
92
0
        }
93
0
    }
94
95
    /// Returns a parallel iterator over the bytes of a string.
96
    ///
97
    /// Note that multi-byte sequences (for code points greater than `U+007F`)
98
    /// are produced as separate items, but will not be split across threads.
99
    /// If you would prefer an indexed iterator without that guarantee, consider
100
    /// `string.as_bytes().par_iter().copied()` instead.
101
    ///
102
    /// # Examples
103
    ///
104
    /// ```
105
    /// use rayon::prelude::*;
106
    /// let max = "hello".par_bytes().max();
107
    /// assert_eq!(Some(b'o'), max);
108
    /// ```
109
0
    fn par_bytes(&self) -> Bytes<'_> {
110
0
        Bytes {
111
0
            chars: self.as_parallel_string(),
112
0
        }
113
0
    }
114
115
    /// Returns a parallel iterator over a string encoded as UTF-16.
116
    ///
117
    /// Note that surrogate pairs (for code points greater than `U+FFFF`) are
118
    /// produced as separate items, but will not be split across threads.
119
    ///
120
    /// # Examples
121
    ///
122
    /// ```
123
    /// use rayon::prelude::*;
124
    ///
125
    /// let max = "hello".par_encode_utf16().max();
126
    /// assert_eq!(Some(b'o' as u16), max);
127
    ///
128
    /// let text = "Zażółć gęślą jaźń";
129
    /// let utf8_len = text.len();
130
    /// let utf16_len = text.par_encode_utf16().count();
131
    /// assert!(utf16_len <= utf8_len);
132
    /// ```
133
0
    fn par_encode_utf16(&self) -> EncodeUtf16<'_> {
134
0
        EncodeUtf16 {
135
0
            chars: self.as_parallel_string(),
136
0
        }
137
0
    }
138
139
    /// Returns a parallel iterator over substrings separated by a
140
    /// given character or predicate, similar to `str::split`.
141
    ///
142
    /// Note: the `Pattern` trait is private, for use only by Rayon itself.
143
    /// It is implemented for `char`, `&[char]`, and any function or closure
144
    /// `F: Fn(char) -> bool + Sync + Send`.
145
    ///
146
    /// # Examples
147
    ///
148
    /// ```
149
    /// use rayon::prelude::*;
150
    /// let total = "1, 2, buckle, 3, 4, door"
151
    ///    .par_split(',')
152
    ///    .filter_map(|s| s.trim().parse::<i32>().ok())
153
    ///    .sum();
154
    /// assert_eq!(10, total);
155
    /// ```
156
0
    fn par_split<P: Pattern>(&self, separator: P) -> Split<'_, P> {
157
0
        Split::new(self.as_parallel_string(), separator)
158
0
    }
159
160
    /// Returns a parallel iterator over substrings terminated by a
161
    /// given character or predicate, similar to `str::split_terminator`.
162
    /// It's equivalent to `par_split`, except it doesn't produce an empty
163
    /// substring after a trailing terminator.
164
    ///
165
    /// Note: the `Pattern` trait is private, for use only by Rayon itself.
166
    /// It is implemented for `char`, `&[char]`, and any function or closure
167
    /// `F: Fn(char) -> bool + Sync + Send`.
168
    ///
169
    /// # Examples
170
    ///
171
    /// ```
172
    /// use rayon::prelude::*;
173
    /// let parts: Vec<_> = "((1 + 3) * 2)"
174
    ///     .par_split_terminator(|c| c == '(' || c == ')')
175
    ///     .collect();
176
    /// assert_eq!(vec!["", "", "1 + 3", " * 2"], parts);
177
    /// ```
178
0
    fn par_split_terminator<P: Pattern>(&self, terminator: P) -> SplitTerminator<'_, P> {
179
0
        SplitTerminator::new(self.as_parallel_string(), terminator)
180
0
    }
181
182
    /// Returns a parallel iterator over the lines of a string, ending with an
183
    /// optional carriage return and with a newline (`\r\n` or just `\n`).
184
    /// The final line ending is optional, and line endings are not included in
185
    /// the output strings.
186
    ///
187
    /// # Examples
188
    ///
189
    /// ```
190
    /// use rayon::prelude::*;
191
    /// let lengths: Vec<_> = "hello world\nfizbuzz"
192
    ///     .par_lines()
193
    ///     .map(|l| l.len())
194
    ///     .collect();
195
    /// assert_eq!(vec![11, 7], lengths);
196
    /// ```
197
0
    fn par_lines(&self) -> Lines<'_> {
198
0
        Lines(self.as_parallel_string())
199
0
    }
200
201
    /// Returns a parallel iterator over the sub-slices of a string that are
202
    /// separated by any amount of whitespace.
203
    ///
204
    /// As with `str::split_whitespace`, 'whitespace' is defined according to
205
    /// the terms of the Unicode Derived Core Property `White_Space`.
206
    ///
207
    /// # Examples
208
    ///
209
    /// ```
210
    /// use rayon::prelude::*;
211
    /// let longest = "which is the longest word?"
212
    ///     .par_split_whitespace()
213
    ///     .max_by_key(|word| word.len());
214
    /// assert_eq!(Some("longest"), longest);
215
    /// ```
216
0
    fn par_split_whitespace(&self) -> SplitWhitespace<'_> {
217
0
        SplitWhitespace(self.as_parallel_string())
218
0
    }
219
220
    /// Returns a parallel iterator over substrings that match a
221
    /// given character or predicate, similar to `str::matches`.
222
    ///
223
    /// Note: the `Pattern` trait is private, for use only by Rayon itself.
224
    /// It is implemented for `char`, `&[char]`, and any function or closure
225
    /// `F: Fn(char) -> bool + Sync + Send`.
226
    ///
227
    /// # Examples
228
    ///
229
    /// ```
230
    /// use rayon::prelude::*;
231
    /// let total = "1, 2, buckle, 3, 4, door"
232
    ///    .par_matches(char::is_numeric)
233
    ///    .map(|s| s.parse::<i32>().expect("digit"))
234
    ///    .sum();
235
    /// assert_eq!(10, total);
236
    /// ```
237
0
    fn par_matches<P: Pattern>(&self, pattern: P) -> Matches<'_, P> {
238
0
        Matches {
239
0
            chars: self.as_parallel_string(),
240
0
            pattern,
241
0
        }
242
0
    }
243
244
    /// Returns a parallel iterator over substrings that match a given character
245
    /// or predicate, with their positions, similar to `str::match_indices`.
246
    ///
247
    /// Note: the `Pattern` trait is private, for use only by Rayon itself.
248
    /// It is implemented for `char`, `&[char]`, and any function or closure
249
    /// `F: Fn(char) -> bool + Sync + Send`.
250
    ///
251
    /// # Examples
252
    ///
253
    /// ```
254
    /// use rayon::prelude::*;
255
    /// let digits: Vec<_> = "1, 2, buckle, 3, 4, door"
256
    ///    .par_match_indices(char::is_numeric)
257
    ///    .collect();
258
    /// assert_eq!(digits, vec![(0, "1"), (3, "2"), (14, "3"), (17, "4")]);
259
    /// ```
260
0
    fn par_match_indices<P: Pattern>(&self, pattern: P) -> MatchIndices<'_, P> {
261
0
        MatchIndices {
262
0
            chars: self.as_parallel_string(),
263
0
            pattern,
264
0
        }
265
0
    }
266
}
267
268
impl ParallelString for str {
269
    #[inline]
270
0
    fn as_parallel_string(&self) -> &str {
271
0
        self
272
0
    }
273
}
274
275
// /////////////////////////////////////////////////////////////////////////
276
277
/// We hide the `Pattern` trait in a private module, as its API is not meant
278
/// for general consumption.  If we could have privacy on trait items, then it
279
/// would be nicer to have its basic existence and implementors public while
280
/// keeping all of the methods private.
281
mod private {
282
    use crate::iter::plumbing::Folder;
283
284
    /// Pattern-matching trait for `ParallelString`, somewhat like a mix of
285
    /// `std::str::pattern::{Pattern, Searcher}`.
286
    ///
287
    /// Implementing this trait is not permitted outside of `rayon`.
288
    pub trait Pattern: Sized + Sync + Send {
289
        private_decl! {}
290
        fn find_in(&self, haystack: &str) -> Option<usize>;
291
        fn rfind_in(&self, haystack: &str) -> Option<usize>;
292
        fn is_suffix_of(&self, haystack: &str) -> bool;
293
        fn fold_splits<'ch, F>(&self, haystack: &'ch str, folder: F, skip_last: bool) -> F
294
        where
295
            F: Folder<&'ch str>;
296
        fn fold_matches<'ch, F>(&self, haystack: &'ch str, folder: F) -> F
297
        where
298
            F: Folder<&'ch str>;
299
        fn fold_match_indices<'ch, F>(&self, haystack: &'ch str, folder: F, base: usize) -> F
300
        where
301
            F: Folder<(usize, &'ch str)>;
302
    }
303
}
304
use self::private::Pattern;
305
306
#[inline]
307
0
fn offset<T>(base: usize) -> impl Fn((usize, T)) -> (usize, T) {
308
0
    move |(i, x)| (base + i, x)
309
0
}
310
311
macro_rules! impl_pattern {
312
    (&$self:ident => $pattern:expr) => {
313
        private_impl! {}
314
315
        #[inline]
316
0
        fn find_in(&$self, chars: &str) -> Option<usize> {
317
0
            chars.find($pattern)
318
0
        }
Unexecuted instantiation: <char as rayon::str::private::Pattern>::find_in
Unexecuted instantiation: <_ as rayon::str::private::Pattern>::find_in
Unexecuted instantiation: <&[char] as rayon::str::private::Pattern>::find_in
319
320
        #[inline]
321
0
        fn rfind_in(&$self, chars: &str) -> Option<usize> {
322
0
            chars.rfind($pattern)
323
0
        }
Unexecuted instantiation: <_ as rayon::str::private::Pattern>::rfind_in
Unexecuted instantiation: <&[char] as rayon::str::private::Pattern>::rfind_in
Unexecuted instantiation: <char as rayon::str::private::Pattern>::rfind_in
324
325
        #[inline]
326
0
        fn is_suffix_of(&$self, chars: &str) -> bool {
327
0
            chars.ends_with($pattern)
328
0
        }
Unexecuted instantiation: <char as rayon::str::private::Pattern>::is_suffix_of
Unexecuted instantiation: <_ as rayon::str::private::Pattern>::is_suffix_of
Unexecuted instantiation: <&[char] as rayon::str::private::Pattern>::is_suffix_of
329
330
0
        fn fold_splits<'ch, F>(&$self, chars: &'ch str, folder: F, skip_last: bool) -> F
331
0
        where
332
0
            F: Folder<&'ch str>,
333
0
        {
334
0
            let mut split = chars.split($pattern);
335
0
            if skip_last {
336
0
                split.next_back();
337
0
            }
338
0
            folder.consume_iter(split)
339
0
        }
Unexecuted instantiation: <_ as rayon::str::private::Pattern>::fold_splits::<_>
Unexecuted instantiation: <char as rayon::str::private::Pattern>::fold_splits::<_>
Unexecuted instantiation: <&[char] as rayon::str::private::Pattern>::fold_splits::<_>
340
341
0
        fn fold_matches<'ch, F>(&$self, chars: &'ch str, folder: F) -> F
342
0
        where
343
0
            F: Folder<&'ch str>,
344
0
        {
345
0
            folder.consume_iter(chars.matches($pattern))
346
0
        }
Unexecuted instantiation: <&[char] as rayon::str::private::Pattern>::fold_matches::<_>
Unexecuted instantiation: <char as rayon::str::private::Pattern>::fold_matches::<_>
Unexecuted instantiation: <_ as rayon::str::private::Pattern>::fold_matches::<_>
347
348
0
        fn fold_match_indices<'ch, F>(&$self, chars: &'ch str, folder: F, base: usize) -> F
349
0
        where
350
0
            F: Folder<(usize, &'ch str)>,
351
0
        {
352
0
            folder.consume_iter(chars.match_indices($pattern).map(offset(base)))
353
0
        }
Unexecuted instantiation: <&[char] as rayon::str::private::Pattern>::fold_match_indices::<_>
Unexecuted instantiation: <char as rayon::str::private::Pattern>::fold_match_indices::<_>
Unexecuted instantiation: <_ as rayon::str::private::Pattern>::fold_match_indices::<_>
354
    }
355
}
356
357
impl Pattern for char {
358
    impl_pattern!(&self => *self);
359
}
360
361
impl Pattern for &[char] {
362
    impl_pattern!(&self => *self);
363
}
364
365
impl<FN: Sync + Send + Fn(char) -> bool> Pattern for FN {
366
    impl_pattern!(&self => self);
367
}
368
369
// /////////////////////////////////////////////////////////////////////////
370
371
/// Parallel iterator over the characters of a string
372
0
#[derive(Debug, Clone)]
373
pub struct Chars<'ch> {
374
    chars: &'ch str,
375
}
376
377
struct CharsProducer<'ch> {
378
    chars: &'ch str,
379
}
380
381
impl<'ch> ParallelIterator for Chars<'ch> {
382
    type Item = char;
383
384
0
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
385
0
    where
386
0
        C: UnindexedConsumer<Self::Item>,
387
0
    {
388
0
        bridge_unindexed(CharsProducer { chars: self.chars }, consumer)
389
0
    }
390
}
391
392
impl<'ch> UnindexedProducer for CharsProducer<'ch> {
393
    type Item = char;
394
395
0
    fn split(self) -> (Self, Option<Self>) {
396
0
        match split(self.chars) {
397
0
            Some((left, right)) => (
398
0
                CharsProducer { chars: left },
399
0
                Some(CharsProducer { chars: right }),
400
0
            ),
401
0
            None => (self, None),
402
        }
403
0
    }
404
405
0
    fn fold_with<F>(self, folder: F) -> F
406
0
    where
407
0
        F: Folder<Self::Item>,
408
0
    {
409
0
        folder.consume_iter(self.chars.chars())
410
0
    }
411
}
412
413
// /////////////////////////////////////////////////////////////////////////
414
415
/// Parallel iterator over the characters of a string, with their positions
416
0
#[derive(Debug, Clone)]
417
pub struct CharIndices<'ch> {
418
    chars: &'ch str,
419
}
420
421
struct CharIndicesProducer<'ch> {
422
    index: usize,
423
    chars: &'ch str,
424
}
425
426
impl<'ch> ParallelIterator for CharIndices<'ch> {
427
    type Item = (usize, char);
428
429
0
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
430
0
    where
431
0
        C: UnindexedConsumer<Self::Item>,
432
0
    {
433
0
        let producer = CharIndicesProducer {
434
0
            index: 0,
435
0
            chars: self.chars,
436
0
        };
437
0
        bridge_unindexed(producer, consumer)
438
0
    }
439
}
440
441
impl<'ch> UnindexedProducer for CharIndicesProducer<'ch> {
442
    type Item = (usize, char);
443
444
0
    fn split(self) -> (Self, Option<Self>) {
445
0
        match split(self.chars) {
446
0
            Some((left, right)) => (
447
0
                CharIndicesProducer {
448
0
                    chars: left,
449
0
                    ..self
450
0
                },
451
0
                Some(CharIndicesProducer {
452
0
                    chars: right,
453
0
                    index: self.index + left.len(),
454
0
                }),
455
0
            ),
456
0
            None => (self, None),
457
        }
458
0
    }
459
460
0
    fn fold_with<F>(self, folder: F) -> F
461
0
    where
462
0
        F: Folder<Self::Item>,
463
0
    {
464
0
        let base = self.index;
465
0
        folder.consume_iter(self.chars.char_indices().map(offset(base)))
466
0
    }
467
}
468
469
// /////////////////////////////////////////////////////////////////////////
470
471
/// Parallel iterator over the bytes of a string
472
0
#[derive(Debug, Clone)]
473
pub struct Bytes<'ch> {
474
    chars: &'ch str,
475
}
476
477
struct BytesProducer<'ch> {
478
    chars: &'ch str,
479
}
480
481
impl<'ch> ParallelIterator for Bytes<'ch> {
482
    type Item = u8;
483
484
0
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
485
0
    where
486
0
        C: UnindexedConsumer<Self::Item>,
487
0
    {
488
0
        bridge_unindexed(BytesProducer { chars: self.chars }, consumer)
489
0
    }
490
}
491
492
impl<'ch> UnindexedProducer for BytesProducer<'ch> {
493
    type Item = u8;
494
495
0
    fn split(self) -> (Self, Option<Self>) {
496
0
        match split(self.chars) {
497
0
            Some((left, right)) => (
498
0
                BytesProducer { chars: left },
499
0
                Some(BytesProducer { chars: right }),
500
0
            ),
501
0
            None => (self, None),
502
        }
503
0
    }
504
505
0
    fn fold_with<F>(self, folder: F) -> F
506
0
    where
507
0
        F: Folder<Self::Item>,
508
0
    {
509
0
        folder.consume_iter(self.chars.bytes())
510
0
    }
511
}
512
513
// /////////////////////////////////////////////////////////////////////////
514
515
/// Parallel iterator over a string encoded as UTF-16
516
0
#[derive(Debug, Clone)]
517
pub struct EncodeUtf16<'ch> {
518
    chars: &'ch str,
519
}
520
521
struct EncodeUtf16Producer<'ch> {
522
    chars: &'ch str,
523
}
524
525
impl<'ch> ParallelIterator for EncodeUtf16<'ch> {
526
    type Item = u16;
527
528
0
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
529
0
    where
530
0
        C: UnindexedConsumer<Self::Item>,
531
0
    {
532
0
        bridge_unindexed(EncodeUtf16Producer { chars: self.chars }, consumer)
533
0
    }
534
}
535
536
impl<'ch> UnindexedProducer for EncodeUtf16Producer<'ch> {
537
    type Item = u16;
538
539
0
    fn split(self) -> (Self, Option<Self>) {
540
0
        match split(self.chars) {
541
0
            Some((left, right)) => (
542
0
                EncodeUtf16Producer { chars: left },
543
0
                Some(EncodeUtf16Producer { chars: right }),
544
0
            ),
545
0
            None => (self, None),
546
        }
547
0
    }
548
549
0
    fn fold_with<F>(self, folder: F) -> F
550
0
    where
551
0
        F: Folder<Self::Item>,
552
0
    {
553
0
        folder.consume_iter(self.chars.encode_utf16())
554
0
    }
555
}
556
557
// /////////////////////////////////////////////////////////////////////////
558
559
/// Parallel iterator over substrings separated by a pattern
560
0
#[derive(Debug, Clone)]
561
pub struct Split<'ch, P: Pattern> {
562
    chars: &'ch str,
563
    separator: P,
564
}
565
566
impl<'ch, P: Pattern> Split<'ch, P> {
567
0
    fn new(chars: &'ch str, separator: P) -> Self {
568
0
        Split { chars, separator }
569
0
    }
570
}
571
572
impl<'ch, P: Pattern> ParallelIterator for Split<'ch, P> {
573
    type Item = &'ch str;
574
575
0
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
576
0
    where
577
0
        C: UnindexedConsumer<Self::Item>,
578
0
    {
579
0
        let producer = SplitProducer::new(self.chars, &self.separator);
580
0
        bridge_unindexed(producer, consumer)
581
0
    }
582
}
583
584
/// Implement support for `SplitProducer`.
585
impl<'ch, P: Pattern> Fissile<P> for &'ch str {
586
0
    fn length(&self) -> usize {
587
0
        self.len()
588
0
    }
589
590
0
    fn midpoint(&self, end: usize) -> usize {
591
0
        // First find a suitable UTF-8 boundary.
592
0
        find_char_midpoint(&self[..end])
593
0
    }
594
595
0
    fn find(&self, separator: &P, start: usize, end: usize) -> Option<usize> {
596
0
        separator.find_in(&self[start..end])
597
0
    }
598
599
0
    fn rfind(&self, separator: &P, end: usize) -> Option<usize> {
600
0
        separator.rfind_in(&self[..end])
601
0
    }
602
603
0
    fn split_once(self, index: usize) -> (Self, Self) {
604
0
        let (left, right) = self.split_at(index);
605
0
        let mut right_iter = right.chars();
606
0
        right_iter.next(); // skip the separator
607
0
        (left, right_iter.as_str())
608
0
    }
609
610
0
    fn fold_splits<F>(self, separator: &P, folder: F, skip_last: bool) -> F
611
0
    where
612
0
        F: Folder<Self>,
613
0
    {
614
0
        separator.fold_splits(self, folder, skip_last)
615
0
    }
616
}
617
618
// /////////////////////////////////////////////////////////////////////////
619
620
/// Parallel iterator over substrings separated by a terminator pattern
621
0
#[derive(Debug, Clone)]
622
pub struct SplitTerminator<'ch, P: Pattern> {
623
    chars: &'ch str,
624
    terminator: P,
625
}
626
627
struct SplitTerminatorProducer<'ch, 'sep, P: Pattern> {
628
    splitter: SplitProducer<'sep, P, &'ch str>,
629
    skip_last: bool,
630
}
631
632
impl<'ch, P: Pattern> SplitTerminator<'ch, P> {
633
0
    fn new(chars: &'ch str, terminator: P) -> Self {
634
0
        SplitTerminator { chars, terminator }
635
0
    }
636
}
637
638
impl<'ch, 'sep, P: Pattern + 'sep> SplitTerminatorProducer<'ch, 'sep, P> {
639
0
    fn new(chars: &'ch str, terminator: &'sep P) -> Self {
640
0
        SplitTerminatorProducer {
641
0
            splitter: SplitProducer::new(chars, terminator),
642
0
            skip_last: chars.is_empty() || terminator.is_suffix_of(chars),
643
        }
644
0
    }
645
}
646
647
impl<'ch, P: Pattern> ParallelIterator for SplitTerminator<'ch, P> {
648
    type Item = &'ch str;
649
650
0
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
651
0
    where
652
0
        C: UnindexedConsumer<Self::Item>,
653
0
    {
654
0
        let producer = SplitTerminatorProducer::new(self.chars, &self.terminator);
655
0
        bridge_unindexed(producer, consumer)
656
0
    }
657
}
658
659
impl<'ch, 'sep, P: Pattern + 'sep> UnindexedProducer for SplitTerminatorProducer<'ch, 'sep, P> {
660
    type Item = &'ch str;
661
662
0
    fn split(mut self) -> (Self, Option<Self>) {
663
0
        let (left, right) = self.splitter.split();
664
0
        self.splitter = left;
665
0
        let right = right.map(|right| {
666
0
            let skip_last = self.skip_last;
667
0
            self.skip_last = false;
668
0
            SplitTerminatorProducer {
669
0
                splitter: right,
670
0
                skip_last,
671
0
            }
672
0
        });
673
0
        (self, right)
674
0
    }
675
676
0
    fn fold_with<F>(self, folder: F) -> F
677
0
    where
678
0
        F: Folder<Self::Item>,
679
0
    {
680
0
        self.splitter.fold_with(folder, self.skip_last)
681
0
    }
682
}
683
684
// /////////////////////////////////////////////////////////////////////////
685
686
/// Parallel iterator over lines in a string
687
0
#[derive(Debug, Clone)]
688
pub struct Lines<'ch>(&'ch str);
689
690
#[inline]
691
0
fn no_carriage_return(line: &str) -> &str {
692
0
    if line.ends_with('\r') {
693
0
        &line[..line.len() - 1]
694
    } else {
695
0
        line
696
    }
697
0
}
698
699
impl<'ch> ParallelIterator for Lines<'ch> {
700
    type Item = &'ch str;
701
702
0
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
703
0
    where
704
0
        C: UnindexedConsumer<Self::Item>,
705
0
    {
706
0
        self.0
707
0
            .par_split_terminator('\n')
708
0
            .map(no_carriage_return)
709
0
            .drive_unindexed(consumer)
710
0
    }
711
}
712
713
// /////////////////////////////////////////////////////////////////////////
714
715
/// Parallel iterator over substrings separated by whitespace
716
0
#[derive(Debug, Clone)]
717
pub struct SplitWhitespace<'ch>(&'ch str);
718
719
#[inline]
720
0
fn not_empty(s: &&str) -> bool {
721
0
    !s.is_empty()
722
0
}
723
724
impl<'ch> ParallelIterator for SplitWhitespace<'ch> {
725
    type Item = &'ch str;
726
727
0
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
728
0
    where
729
0
        C: UnindexedConsumer<Self::Item>,
730
0
    {
731
0
        self.0
732
0
            .par_split(char::is_whitespace)
733
0
            .filter(not_empty)
734
0
            .drive_unindexed(consumer)
735
0
    }
736
}
737
738
// /////////////////////////////////////////////////////////////////////////
739
740
/// Parallel iterator over substrings that match a pattern
741
0
#[derive(Debug, Clone)]
742
pub struct Matches<'ch, P: Pattern> {
743
    chars: &'ch str,
744
    pattern: P,
745
}
746
747
struct MatchesProducer<'ch, 'pat, P: Pattern> {
748
    chars: &'ch str,
749
    pattern: &'pat P,
750
}
751
752
impl<'ch, P: Pattern> ParallelIterator for Matches<'ch, P> {
753
    type Item = &'ch str;
754
755
0
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
756
0
    where
757
0
        C: UnindexedConsumer<Self::Item>,
758
0
    {
759
0
        let producer = MatchesProducer {
760
0
            chars: self.chars,
761
0
            pattern: &self.pattern,
762
0
        };
763
0
        bridge_unindexed(producer, consumer)
764
0
    }
765
}
766
767
impl<'ch, 'pat, P: Pattern> UnindexedProducer for MatchesProducer<'ch, 'pat, P> {
768
    type Item = &'ch str;
769
770
0
    fn split(self) -> (Self, Option<Self>) {
771
0
        match split(self.chars) {
772
0
            Some((left, right)) => (
773
0
                MatchesProducer {
774
0
                    chars: left,
775
0
                    ..self
776
0
                },
777
0
                Some(MatchesProducer {
778
0
                    chars: right,
779
0
                    ..self
780
0
                }),
781
0
            ),
782
0
            None => (self, None),
783
        }
784
0
    }
785
786
0
    fn fold_with<F>(self, folder: F) -> F
787
0
    where
788
0
        F: Folder<Self::Item>,
789
0
    {
790
0
        self.pattern.fold_matches(self.chars, folder)
791
0
    }
792
}
793
794
// /////////////////////////////////////////////////////////////////////////
795
796
/// Parallel iterator over substrings that match a pattern, with their positions
797
0
#[derive(Debug, Clone)]
798
pub struct MatchIndices<'ch, P: Pattern> {
799
    chars: &'ch str,
800
    pattern: P,
801
}
802
803
struct MatchIndicesProducer<'ch, 'pat, P: Pattern> {
804
    index: usize,
805
    chars: &'ch str,
806
    pattern: &'pat P,
807
}
808
809
impl<'ch, P: Pattern> ParallelIterator for MatchIndices<'ch, P> {
810
    type Item = (usize, &'ch str);
811
812
0
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
813
0
    where
814
0
        C: UnindexedConsumer<Self::Item>,
815
0
    {
816
0
        let producer = MatchIndicesProducer {
817
0
            index: 0,
818
0
            chars: self.chars,
819
0
            pattern: &self.pattern,
820
0
        };
821
0
        bridge_unindexed(producer, consumer)
822
0
    }
823
}
824
825
impl<'ch, 'pat, P: Pattern> UnindexedProducer for MatchIndicesProducer<'ch, 'pat, P> {
826
    type Item = (usize, &'ch str);
827
828
0
    fn split(self) -> (Self, Option<Self>) {
829
0
        match split(self.chars) {
830
0
            Some((left, right)) => (
831
0
                MatchIndicesProducer {
832
0
                    chars: left,
833
0
                    ..self
834
0
                },
835
0
                Some(MatchIndicesProducer {
836
0
                    chars: right,
837
0
                    index: self.index + left.len(),
838
0
                    ..self
839
0
                }),
840
0
            ),
841
0
            None => (self, None),
842
        }
843
0
    }
844
845
0
    fn fold_with<F>(self, folder: F) -> F
846
0
    where
847
0
        F: Folder<Self::Item>,
848
0
    {
849
0
        self.pattern
850
0
            .fold_match_indices(self.chars, folder, self.index)
851
0
    }
852
}