| //! Parallel iterator types for [strings][std::str] | 
 | //! | 
 | //! You will rarely need to interact with this module directly unless you need | 
 | //! to name one of the iterator types. | 
 | //! | 
 | //! Note: [`ParallelString::par_split()`] and [`par_split_terminator()`] | 
 | //! reference a `Pattern` trait which is not visible outside this crate. | 
 | //! This trait is intentionally kept private, for use only by Rayon itself. | 
 | //! It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, | 
 | //! and any function or closure `F: Fn(char) -> bool + Sync + Send`. | 
 | //! | 
 | //! [`ParallelString::par_split()`]: trait.ParallelString.html#method.par_split | 
 | //! [`par_split_terminator()`]: trait.ParallelString.html#method.par_split_terminator | 
 | //! | 
 | //! [std::str]: https://doc.rust-lang.org/stable/std/str/ | 
 |  | 
 | use crate::iter::plumbing::*; | 
 | use crate::iter::*; | 
 | use crate::split_producer::*; | 
 |  | 
 | /// Test if a byte is the start of a UTF-8 character. | 
 | /// (extracted from `str::is_char_boundary`) | 
 | #[inline] | 
 | fn is_char_boundary(b: u8) -> bool { | 
 |     // This is bit magic equivalent to: b < 128 || b >= 192 | 
 |     (b as i8) >= -0x40 | 
 | } | 
 |  | 
 | /// Find the index of a character boundary near the midpoint. | 
 | #[inline] | 
 | fn find_char_midpoint(chars: &str) -> usize { | 
 |     let mid = chars.len() / 2; | 
 |  | 
 |     // We want to split near the midpoint, but we need to find an actual | 
 |     // character boundary.  So we look at the raw bytes, first scanning | 
 |     // forward from the midpoint for a boundary, then trying backward. | 
 |     let (left, right) = chars.as_bytes().split_at(mid); | 
 |     match right.iter().copied().position(is_char_boundary) { | 
 |         Some(i) => mid + i, | 
 |         None => left | 
 |             .iter() | 
 |             .copied() | 
 |             .rposition(is_char_boundary) | 
 |             .unwrap_or(0), | 
 |     } | 
 | } | 
 |  | 
 | /// Try to split a string near the midpoint. | 
 | #[inline] | 
 | fn split(chars: &str) -> Option<(&str, &str)> { | 
 |     let index = find_char_midpoint(chars); | 
 |     if index > 0 { | 
 |         Some(chars.split_at(index)) | 
 |     } else { | 
 |         None | 
 |     } | 
 | } | 
 |  | 
 | /// Parallel extensions for strings. | 
 | pub trait ParallelString { | 
 |     /// Returns a plain string slice, which is used to implement the rest of | 
 |     /// the parallel methods. | 
 |     fn as_parallel_string(&self) -> &str; | 
 |  | 
 |     /// Returns a parallel iterator over the characters of a string. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let max = "hello".par_chars().max_by_key(|c| *c as i32); | 
 |     /// assert_eq!(Some('o'), max); | 
 |     /// ``` | 
 |     fn par_chars(&self) -> Chars<'_> { | 
 |         Chars { | 
 |             chars: self.as_parallel_string(), | 
 |         } | 
 |     } | 
 |  | 
 |     /// Returns a parallel iterator over the characters of a string, with their positions. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let min = "hello".par_char_indices().min_by_key(|&(_i, c)| c as i32); | 
 |     /// assert_eq!(Some((1, 'e')), min); | 
 |     /// ``` | 
 |     fn par_char_indices(&self) -> CharIndices<'_> { | 
 |         CharIndices { | 
 |             chars: self.as_parallel_string(), | 
 |         } | 
 |     } | 
 |  | 
 |     /// Returns a parallel iterator over the bytes of a string. | 
 |     /// | 
 |     /// Note that multi-byte sequences (for code points greater than `U+007F`) | 
 |     /// are produced as separate items, but will not be split across threads. | 
 |     /// If you would prefer an indexed iterator without that guarantee, consider | 
 |     /// `string.as_bytes().par_iter().copied()` instead. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let max = "hello".par_bytes().max(); | 
 |     /// assert_eq!(Some(b'o'), max); | 
 |     /// ``` | 
 |     fn par_bytes(&self) -> Bytes<'_> { | 
 |         Bytes { | 
 |             chars: self.as_parallel_string(), | 
 |         } | 
 |     } | 
 |  | 
 |     /// Returns a parallel iterator over a string encoded as UTF-16. | 
 |     /// | 
 |     /// Note that surrogate pairs (for code points greater than `U+FFFF`) are | 
 |     /// produced as separate items, but will not be split across threads. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// | 
 |     /// let max = "hello".par_encode_utf16().max(); | 
 |     /// assert_eq!(Some(b'o' as u16), max); | 
 |     /// | 
 |     /// let text = "Zażółć gęślą jaźń"; | 
 |     /// let utf8_len = text.len(); | 
 |     /// let utf16_len = text.par_encode_utf16().count(); | 
 |     /// assert!(utf16_len <= utf8_len); | 
 |     /// ``` | 
 |     fn par_encode_utf16(&self) -> EncodeUtf16<'_> { | 
 |         EncodeUtf16 { | 
 |             chars: self.as_parallel_string(), | 
 |         } | 
 |     } | 
 |  | 
 |     /// Returns a parallel iterator over substrings separated by a | 
 |     /// given character or predicate, similar to `str::split`. | 
 |     /// | 
 |     /// Note: the `Pattern` trait is private, for use only by Rayon itself. | 
 |     /// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, | 
 |     /// and any function or closure `F: Fn(char) -> bool + Sync + Send`. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let total = "1, 2, buckle, 3, 4, door" | 
 |     ///    .par_split(',') | 
 |     ///    .filter_map(|s| s.trim().parse::<i32>().ok()) | 
 |     ///    .sum(); | 
 |     /// assert_eq!(10, total); | 
 |     /// ``` | 
 |     fn par_split<P: Pattern>(&self, separator: P) -> Split<'_, P> { | 
 |         Split::new(self.as_parallel_string(), separator) | 
 |     } | 
 |  | 
 |     /// Returns a parallel iterator over substrings separated by a | 
 |     /// given character or predicate, keeping the matched part as a terminator | 
 |     /// of the substring similar to `str::split_inclusive`. | 
 |     /// | 
 |     /// Note: the `Pattern` trait is private, for use only by Rayon itself. | 
 |     /// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, | 
 |     /// and any function or closure `F: Fn(char) -> bool + Sync + Send`. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let lines: Vec<_> = "Mary had a little lamb\nlittle lamb\nlittle lamb." | 
 |     ///    .par_split_inclusive('\n') | 
 |     ///    .collect(); | 
 |     /// assert_eq!(lines, ["Mary had a little lamb\n", "little lamb\n", "little lamb."]); | 
 |     /// ``` | 
 |     fn par_split_inclusive<P: Pattern>(&self, separator: P) -> SplitInclusive<'_, P> { | 
 |         SplitInclusive::new(self.as_parallel_string(), separator) | 
 |     } | 
 |  | 
 |     /// Returns a parallel iterator over substrings terminated by a | 
 |     /// given character or predicate, similar to `str::split_terminator`. | 
 |     /// It's equivalent to `par_split`, except it doesn't produce an empty | 
 |     /// substring after a trailing terminator. | 
 |     /// | 
 |     /// Note: the `Pattern` trait is private, for use only by Rayon itself. | 
 |     /// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, | 
 |     /// and any function or closure `F: Fn(char) -> bool + Sync + Send`. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let parts: Vec<_> = "((1 + 3) * 2)" | 
 |     ///     .par_split_terminator(|c| c == '(' || c == ')') | 
 |     ///     .collect(); | 
 |     /// assert_eq!(vec!["", "", "1 + 3", " * 2"], parts); | 
 |     /// ``` | 
 |     fn par_split_terminator<P: Pattern>(&self, terminator: P) -> SplitTerminator<'_, P> { | 
 |         SplitTerminator::new(self.as_parallel_string(), terminator) | 
 |     } | 
 |  | 
 |     /// Returns a parallel iterator over the lines of a string, ending with an | 
 |     /// optional carriage return and with a newline (`\r\n` or just `\n`). | 
 |     /// The final line ending is optional, and line endings are not included in | 
 |     /// the output strings. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let lengths: Vec<_> = "hello world\nfizbuzz" | 
 |     ///     .par_lines() | 
 |     ///     .map(|l| l.len()) | 
 |     ///     .collect(); | 
 |     /// assert_eq!(vec![11, 7], lengths); | 
 |     /// ``` | 
 |     fn par_lines(&self) -> Lines<'_> { | 
 |         Lines(self.as_parallel_string()) | 
 |     } | 
 |  | 
 |     /// Returns a parallel iterator over the sub-slices of a string that are | 
 |     /// separated by any amount of whitespace. | 
 |     /// | 
 |     /// As with `str::split_whitespace`, 'whitespace' is defined according to | 
 |     /// the terms of the Unicode Derived Core Property `White_Space`. | 
 |     /// If you only want to split on ASCII whitespace instead, use | 
 |     /// [`par_split_ascii_whitespace`][`ParallelString::par_split_ascii_whitespace`]. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let longest = "which is the longest word?" | 
 |     ///     .par_split_whitespace() | 
 |     ///     .max_by_key(|word| word.len()); | 
 |     /// assert_eq!(Some("longest"), longest); | 
 |     /// ``` | 
 |     /// | 
 |     /// All kinds of whitespace are considered: | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let words: Vec<&str> = " Mary   had\ta\u{2009}little  \n\t lamb" | 
 |     ///     .par_split_whitespace() | 
 |     ///     .collect(); | 
 |     /// assert_eq!(words, ["Mary", "had", "a", "little", "lamb"]); | 
 |     /// ``` | 
 |     /// | 
 |     /// If the string is empty or all whitespace, the iterator yields no string slices: | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// assert_eq!("".par_split_whitespace().count(), 0); | 
 |     /// assert_eq!("   ".par_split_whitespace().count(), 0); | 
 |     /// ``` | 
 |     fn par_split_whitespace(&self) -> SplitWhitespace<'_> { | 
 |         SplitWhitespace(self.as_parallel_string()) | 
 |     } | 
 |  | 
 |     /// Returns a parallel iterator over the sub-slices of a string that are | 
 |     /// separated by any amount of ASCII whitespace. | 
 |     /// | 
 |     /// To split by Unicode `White_Space` instead, use | 
 |     /// [`par_split_whitespace`][`ParallelString::par_split_whitespace`]. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let longest = "which is the longest word?" | 
 |     ///     .par_split_ascii_whitespace() | 
 |     ///     .max_by_key(|word| word.len()); | 
 |     /// assert_eq!(Some("longest"), longest); | 
 |     /// ``` | 
 |     /// | 
 |     /// All kinds of ASCII whitespace are considered, but not Unicode `White_Space`: | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let words: Vec<&str> = " Mary   had\ta\u{2009}little  \n\t lamb" | 
 |     ///     .par_split_ascii_whitespace() | 
 |     ///     .collect(); | 
 |     /// assert_eq!(words, ["Mary", "had", "a\u{2009}little", "lamb"]); | 
 |     /// ``` | 
 |     /// | 
 |     /// If the string is empty or all ASCII whitespace, the iterator yields no string slices: | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// assert_eq!("".par_split_whitespace().count(), 0); | 
 |     /// assert_eq!("   ".par_split_whitespace().count(), 0); | 
 |     /// ``` | 
 |     fn par_split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_> { | 
 |         SplitAsciiWhitespace(self.as_parallel_string()) | 
 |     } | 
 |  | 
 |     /// Returns a parallel iterator over substrings that match a | 
 |     /// given character or predicate, similar to `str::matches`. | 
 |     /// | 
 |     /// Note: the `Pattern` trait is private, for use only by Rayon itself. | 
 |     /// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, | 
 |     /// and any function or closure `F: Fn(char) -> bool + Sync + Send`. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let total = "1, 2, buckle, 3, 4, door" | 
 |     ///    .par_matches(char::is_numeric) | 
 |     ///    .map(|s| s.parse::<i32>().expect("digit")) | 
 |     ///    .sum(); | 
 |     /// assert_eq!(10, total); | 
 |     /// ``` | 
 |     fn par_matches<P: Pattern>(&self, pattern: P) -> Matches<'_, P> { | 
 |         Matches { | 
 |             chars: self.as_parallel_string(), | 
 |             pattern, | 
 |         } | 
 |     } | 
 |  | 
 |     /// Returns a parallel iterator over substrings that match a given character | 
 |     /// or predicate, with their positions, similar to `str::match_indices`. | 
 |     /// | 
 |     /// Note: the `Pattern` trait is private, for use only by Rayon itself. | 
 |     /// It is implemented for `char`, `&[char]`, `[char; N]`, `&[char; N]`, | 
 |     /// and any function or closure `F: Fn(char) -> bool + Sync + Send`. | 
 |     /// | 
 |     /// # Examples | 
 |     /// | 
 |     /// ``` | 
 |     /// use rayon::prelude::*; | 
 |     /// let digits: Vec<_> = "1, 2, buckle, 3, 4, door" | 
 |     ///    .par_match_indices(char::is_numeric) | 
 |     ///    .collect(); | 
 |     /// assert_eq!(digits, vec![(0, "1"), (3, "2"), (14, "3"), (17, "4")]); | 
 |     /// ``` | 
 |     fn par_match_indices<P: Pattern>(&self, pattern: P) -> MatchIndices<'_, P> { | 
 |         MatchIndices { | 
 |             chars: self.as_parallel_string(), | 
 |             pattern, | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | impl ParallelString for str { | 
 |     #[inline] | 
 |     fn as_parallel_string(&self) -> &str { | 
 |         self | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// We hide the `Pattern` trait in a private module, as its API is not meant | 
 | /// for general consumption.  If we could have privacy on trait items, then it | 
 | /// would be nicer to have its basic existence and implementors public while | 
 | /// keeping all of the methods private. | 
 | mod private { | 
 |     use crate::iter::plumbing::Folder; | 
 |  | 
 |     /// Pattern-matching trait for `ParallelString`, somewhat like a mix of | 
 |     /// `std::str::pattern::{Pattern, Searcher}`. | 
 |     /// | 
 |     /// Implementing this trait is not permitted outside of `rayon`. | 
 |     pub trait Pattern: Sized + Sync + Send { | 
 |         private_decl! {} | 
 |         fn find_in(&self, haystack: &str) -> Option<usize>; | 
 |         fn rfind_in(&self, haystack: &str) -> Option<usize>; | 
 |         fn is_suffix_of(&self, haystack: &str) -> bool; | 
 |         fn fold_splits<'ch, F>(&self, haystack: &'ch str, folder: F, skip_last: bool) -> F | 
 |         where | 
 |             F: Folder<&'ch str>; | 
 |         fn fold_inclusive_splits<'ch, F>(&self, haystack: &'ch str, folder: F) -> F | 
 |         where | 
 |             F: Folder<&'ch str>; | 
 |         fn fold_matches<'ch, F>(&self, haystack: &'ch str, folder: F) -> F | 
 |         where | 
 |             F: Folder<&'ch str>; | 
 |         fn fold_match_indices<'ch, F>(&self, haystack: &'ch str, folder: F, base: usize) -> F | 
 |         where | 
 |             F: Folder<(usize, &'ch str)>; | 
 |     } | 
 | } | 
 | use self::private::Pattern; | 
 |  | 
 | #[inline] | 
 | fn offset<T>(base: usize) -> impl Fn((usize, T)) -> (usize, T) { | 
 |     move |(i, x)| (base + i, x) | 
 | } | 
 |  | 
 | macro_rules! impl_pattern { | 
 |     (&$self:ident => $pattern:expr) => { | 
 |         private_impl! {} | 
 |  | 
 |         #[inline] | 
 |         fn find_in(&$self, chars: &str) -> Option<usize> { | 
 |             chars.find($pattern) | 
 |         } | 
 |  | 
 |         #[inline] | 
 |         fn rfind_in(&$self, chars: &str) -> Option<usize> { | 
 |             chars.rfind($pattern) | 
 |         } | 
 |  | 
 |         #[inline] | 
 |         fn is_suffix_of(&$self, chars: &str) -> bool { | 
 |             chars.ends_with($pattern) | 
 |         } | 
 |  | 
 |         fn fold_splits<'ch, F>(&$self, chars: &'ch str, folder: F, skip_last: bool) -> F | 
 |         where | 
 |             F: Folder<&'ch str>, | 
 |         { | 
 |             let mut split = chars.split($pattern); | 
 |             if skip_last { | 
 |                 split.next_back(); | 
 |             } | 
 |             folder.consume_iter(split) | 
 |         } | 
 |  | 
 |         fn fold_inclusive_splits<'ch, F>(&$self, chars: &'ch str, folder: F) -> F | 
 |         where | 
 |             F: Folder<&'ch str>, | 
 |         { | 
 |             folder.consume_iter(chars.split_inclusive($pattern)) | 
 |         } | 
 |  | 
 |         fn fold_matches<'ch, F>(&$self, chars: &'ch str, folder: F) -> F | 
 |         where | 
 |             F: Folder<&'ch str>, | 
 |         { | 
 |             folder.consume_iter(chars.matches($pattern)) | 
 |         } | 
 |  | 
 |         fn fold_match_indices<'ch, F>(&$self, chars: &'ch str, folder: F, base: usize) -> F | 
 |         where | 
 |             F: Folder<(usize, &'ch str)>, | 
 |         { | 
 |             folder.consume_iter(chars.match_indices($pattern).map(offset(base))) | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | impl Pattern for char { | 
 |     impl_pattern!(&self => *self); | 
 | } | 
 |  | 
 | impl Pattern for &[char] { | 
 |     impl_pattern!(&self => *self); | 
 | } | 
 |  | 
 | // TODO (MSRV 1.75): use `*self` for array patterns too. | 
 | // - Needs `DoubleEndedSearcher` so `split.next_back()` works. | 
 |  | 
 | impl<const N: usize> Pattern for [char; N] { | 
 |     impl_pattern!(&self => self.as_slice()); | 
 | } | 
 |  | 
 | impl<const N: usize> Pattern for &[char; N] { | 
 |     impl_pattern!(&self => self.as_slice()); | 
 | } | 
 |  | 
 | impl<FN: Sync + Send + Fn(char) -> bool> Pattern for FN { | 
 |     impl_pattern!(&self => self); | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over the characters of a string | 
 | #[derive(Debug, Clone)] | 
 | pub struct Chars<'ch> { | 
 |     chars: &'ch str, | 
 | } | 
 |  | 
 | struct CharsProducer<'ch> { | 
 |     chars: &'ch str, | 
 | } | 
 |  | 
 | impl<'ch> ParallelIterator for Chars<'ch> { | 
 |     type Item = char; | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         bridge_unindexed(CharsProducer { chars: self.chars }, consumer) | 
 |     } | 
 | } | 
 |  | 
 | impl<'ch> UnindexedProducer for CharsProducer<'ch> { | 
 |     type Item = char; | 
 |  | 
 |     fn split(self) -> (Self, Option<Self>) { | 
 |         match split(self.chars) { | 
 |             Some((left, right)) => ( | 
 |                 CharsProducer { chars: left }, | 
 |                 Some(CharsProducer { chars: right }), | 
 |             ), | 
 |             None => (self, None), | 
 |         } | 
 |     } | 
 |  | 
 |     fn fold_with<F>(self, folder: F) -> F | 
 |     where | 
 |         F: Folder<Self::Item>, | 
 |     { | 
 |         folder.consume_iter(self.chars.chars()) | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over the characters of a string, with their positions | 
 | #[derive(Debug, Clone)] | 
 | pub struct CharIndices<'ch> { | 
 |     chars: &'ch str, | 
 | } | 
 |  | 
 | struct CharIndicesProducer<'ch> { | 
 |     index: usize, | 
 |     chars: &'ch str, | 
 | } | 
 |  | 
 | impl<'ch> ParallelIterator for CharIndices<'ch> { | 
 |     type Item = (usize, char); | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         let producer = CharIndicesProducer { | 
 |             index: 0, | 
 |             chars: self.chars, | 
 |         }; | 
 |         bridge_unindexed(producer, consumer) | 
 |     } | 
 | } | 
 |  | 
 | impl<'ch> UnindexedProducer for CharIndicesProducer<'ch> { | 
 |     type Item = (usize, char); | 
 |  | 
 |     fn split(self) -> (Self, Option<Self>) { | 
 |         match split(self.chars) { | 
 |             Some((left, right)) => ( | 
 |                 CharIndicesProducer { | 
 |                     chars: left, | 
 |                     ..self | 
 |                 }, | 
 |                 Some(CharIndicesProducer { | 
 |                     chars: right, | 
 |                     index: self.index + left.len(), | 
 |                 }), | 
 |             ), | 
 |             None => (self, None), | 
 |         } | 
 |     } | 
 |  | 
 |     fn fold_with<F>(self, folder: F) -> F | 
 |     where | 
 |         F: Folder<Self::Item>, | 
 |     { | 
 |         let base = self.index; | 
 |         folder.consume_iter(self.chars.char_indices().map(offset(base))) | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over the bytes of a string | 
 | #[derive(Debug, Clone)] | 
 | pub struct Bytes<'ch> { | 
 |     chars: &'ch str, | 
 | } | 
 |  | 
 | struct BytesProducer<'ch> { | 
 |     chars: &'ch str, | 
 | } | 
 |  | 
 | impl<'ch> ParallelIterator for Bytes<'ch> { | 
 |     type Item = u8; | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         bridge_unindexed(BytesProducer { chars: self.chars }, consumer) | 
 |     } | 
 | } | 
 |  | 
 | impl<'ch> UnindexedProducer for BytesProducer<'ch> { | 
 |     type Item = u8; | 
 |  | 
 |     fn split(self) -> (Self, Option<Self>) { | 
 |         match split(self.chars) { | 
 |             Some((left, right)) => ( | 
 |                 BytesProducer { chars: left }, | 
 |                 Some(BytesProducer { chars: right }), | 
 |             ), | 
 |             None => (self, None), | 
 |         } | 
 |     } | 
 |  | 
 |     fn fold_with<F>(self, folder: F) -> F | 
 |     where | 
 |         F: Folder<Self::Item>, | 
 |     { | 
 |         folder.consume_iter(self.chars.bytes()) | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over a string encoded as UTF-16 | 
 | #[derive(Debug, Clone)] | 
 | pub struct EncodeUtf16<'ch> { | 
 |     chars: &'ch str, | 
 | } | 
 |  | 
 | struct EncodeUtf16Producer<'ch> { | 
 |     chars: &'ch str, | 
 | } | 
 |  | 
 | impl<'ch> ParallelIterator for EncodeUtf16<'ch> { | 
 |     type Item = u16; | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         bridge_unindexed(EncodeUtf16Producer { chars: self.chars }, consumer) | 
 |     } | 
 | } | 
 |  | 
 | impl<'ch> UnindexedProducer for EncodeUtf16Producer<'ch> { | 
 |     type Item = u16; | 
 |  | 
 |     fn split(self) -> (Self, Option<Self>) { | 
 |         match split(self.chars) { | 
 |             Some((left, right)) => ( | 
 |                 EncodeUtf16Producer { chars: left }, | 
 |                 Some(EncodeUtf16Producer { chars: right }), | 
 |             ), | 
 |             None => (self, None), | 
 |         } | 
 |     } | 
 |  | 
 |     fn fold_with<F>(self, folder: F) -> F | 
 |     where | 
 |         F: Folder<Self::Item>, | 
 |     { | 
 |         folder.consume_iter(self.chars.encode_utf16()) | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over substrings separated by a pattern | 
 | #[derive(Debug, Clone)] | 
 | pub struct Split<'ch, P: Pattern> { | 
 |     chars: &'ch str, | 
 |     separator: P, | 
 | } | 
 |  | 
 | impl<'ch, P: Pattern> Split<'ch, P> { | 
 |     fn new(chars: &'ch str, separator: P) -> Self { | 
 |         Split { chars, separator } | 
 |     } | 
 | } | 
 |  | 
 | impl<'ch, P: Pattern> ParallelIterator for Split<'ch, P> { | 
 |     type Item = &'ch str; | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         let producer = SplitProducer::new(self.chars, &self.separator); | 
 |         bridge_unindexed(producer, consumer) | 
 |     } | 
 | } | 
 |  | 
 | /// Implement support for `SplitProducer`. | 
 | impl<'ch, P: Pattern> Fissile<P> for &'ch str { | 
 |     fn length(&self) -> usize { | 
 |         self.len() | 
 |     } | 
 |  | 
 |     fn midpoint(&self, end: usize) -> usize { | 
 |         // First find a suitable UTF-8 boundary. | 
 |         find_char_midpoint(&self[..end]) | 
 |     } | 
 |  | 
 |     fn find(&self, separator: &P, start: usize, end: usize) -> Option<usize> { | 
 |         separator.find_in(&self[start..end]) | 
 |     } | 
 |  | 
 |     fn rfind(&self, separator: &P, end: usize) -> Option<usize> { | 
 |         separator.rfind_in(&self[..end]) | 
 |     } | 
 |  | 
 |     fn split_once<const INCL: bool>(self, index: usize) -> (Self, Self) { | 
 |         if INCL { | 
 |             // include the separator in the left side | 
 |             let separator = self[index..].chars().next().unwrap(); | 
 |             self.split_at(index + separator.len_utf8()) | 
 |         } else { | 
 |             let (left, right) = self.split_at(index); | 
 |             let mut right_iter = right.chars(); | 
 |             right_iter.next(); // skip the separator | 
 |             (left, right_iter.as_str()) | 
 |         } | 
 |     } | 
 |  | 
 |     fn fold_splits<F, const INCL: bool>(self, separator: &P, folder: F, skip_last: bool) -> F | 
 |     where | 
 |         F: Folder<Self>, | 
 |     { | 
 |         if INCL { | 
 |             debug_assert!(!skip_last); | 
 |             separator.fold_inclusive_splits(self, folder) | 
 |         } else { | 
 |             separator.fold_splits(self, folder, skip_last) | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over substrings separated by a pattern | 
 | #[derive(Debug, Clone)] | 
 | pub struct SplitInclusive<'ch, P: Pattern> { | 
 |     chars: &'ch str, | 
 |     separator: P, | 
 | } | 
 |  | 
 | impl<'ch, P: Pattern> SplitInclusive<'ch, P> { | 
 |     fn new(chars: &'ch str, separator: P) -> Self { | 
 |         SplitInclusive { chars, separator } | 
 |     } | 
 | } | 
 |  | 
 | impl<'ch, P: Pattern> ParallelIterator for SplitInclusive<'ch, P> { | 
 |     type Item = &'ch str; | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         let producer = SplitInclusiveProducer::new_incl(self.chars, &self.separator); | 
 |         bridge_unindexed(producer, consumer) | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over substrings separated by a terminator pattern | 
 | #[derive(Debug, Clone)] | 
 | pub struct SplitTerminator<'ch, P: Pattern> { | 
 |     chars: &'ch str, | 
 |     terminator: P, | 
 | } | 
 |  | 
 | struct SplitTerminatorProducer<'ch, 'sep, P: Pattern> { | 
 |     splitter: SplitProducer<'sep, P, &'ch str>, | 
 |     skip_last: bool, | 
 | } | 
 |  | 
 | impl<'ch, P: Pattern> SplitTerminator<'ch, P> { | 
 |     fn new(chars: &'ch str, terminator: P) -> Self { | 
 |         SplitTerminator { chars, terminator } | 
 |     } | 
 | } | 
 |  | 
 | impl<'ch, 'sep, P: Pattern + 'sep> SplitTerminatorProducer<'ch, 'sep, P> { | 
 |     fn new(chars: &'ch str, terminator: &'sep P) -> Self { | 
 |         SplitTerminatorProducer { | 
 |             splitter: SplitProducer::new(chars, terminator), | 
 |             skip_last: chars.is_empty() || terminator.is_suffix_of(chars), | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | impl<'ch, P: Pattern> ParallelIterator for SplitTerminator<'ch, P> { | 
 |     type Item = &'ch str; | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         let producer = SplitTerminatorProducer::new(self.chars, &self.terminator); | 
 |         bridge_unindexed(producer, consumer) | 
 |     } | 
 | } | 
 |  | 
 | impl<'ch, 'sep, P: Pattern + 'sep> UnindexedProducer for SplitTerminatorProducer<'ch, 'sep, P> { | 
 |     type Item = &'ch str; | 
 |  | 
 |     fn split(mut self) -> (Self, Option<Self>) { | 
 |         let (left, right) = self.splitter.split(); | 
 |         self.splitter = left; | 
 |         let right = right.map(|right| { | 
 |             let skip_last = self.skip_last; | 
 |             self.skip_last = false; | 
 |             SplitTerminatorProducer { | 
 |                 splitter: right, | 
 |                 skip_last, | 
 |             } | 
 |         }); | 
 |         (self, right) | 
 |     } | 
 |  | 
 |     fn fold_with<F>(self, folder: F) -> F | 
 |     where | 
 |         F: Folder<Self::Item>, | 
 |     { | 
 |         self.splitter.fold_with(folder, self.skip_last) | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over lines in a string | 
 | #[derive(Debug, Clone)] | 
 | pub struct Lines<'ch>(&'ch str); | 
 |  | 
 | #[inline] | 
 | fn no_carriage_return(line: &str) -> &str { | 
 |     line.strip_suffix('\r').unwrap_or(line) | 
 | } | 
 |  | 
 | impl<'ch> ParallelIterator for Lines<'ch> { | 
 |     type Item = &'ch str; | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         self.0 | 
 |             .par_split_terminator('\n') | 
 |             .map(no_carriage_return) | 
 |             .drive_unindexed(consumer) | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over substrings separated by whitespace | 
 | #[derive(Debug, Clone)] | 
 | pub struct SplitWhitespace<'ch>(&'ch str); | 
 |  | 
 | #[inline] | 
 | fn not_empty(s: &&str) -> bool { | 
 |     !s.is_empty() | 
 | } | 
 |  | 
 | impl<'ch> ParallelIterator for SplitWhitespace<'ch> { | 
 |     type Item = &'ch str; | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         self.0 | 
 |             .par_split(char::is_whitespace) | 
 |             .filter(not_empty) | 
 |             .drive_unindexed(consumer) | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over substrings separated by ASCII whitespace | 
 | #[derive(Debug, Clone)] | 
 | pub struct SplitAsciiWhitespace<'ch>(&'ch str); | 
 |  | 
 | #[inline] | 
 | fn is_ascii_whitespace(c: char) -> bool { | 
 |     c.is_ascii_whitespace() | 
 | } | 
 |  | 
 | impl<'ch> ParallelIterator for SplitAsciiWhitespace<'ch> { | 
 |     type Item = &'ch str; | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         self.0 | 
 |             .par_split(is_ascii_whitespace) | 
 |             .filter(not_empty) | 
 |             .drive_unindexed(consumer) | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over substrings that match a pattern | 
 | #[derive(Debug, Clone)] | 
 | pub struct Matches<'ch, P: Pattern> { | 
 |     chars: &'ch str, | 
 |     pattern: P, | 
 | } | 
 |  | 
 | struct MatchesProducer<'ch, 'pat, P: Pattern> { | 
 |     chars: &'ch str, | 
 |     pattern: &'pat P, | 
 | } | 
 |  | 
 | impl<'ch, P: Pattern> ParallelIterator for Matches<'ch, P> { | 
 |     type Item = &'ch str; | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         let producer = MatchesProducer { | 
 |             chars: self.chars, | 
 |             pattern: &self.pattern, | 
 |         }; | 
 |         bridge_unindexed(producer, consumer) | 
 |     } | 
 | } | 
 |  | 
 | impl<'ch, 'pat, P: Pattern> UnindexedProducer for MatchesProducer<'ch, 'pat, P> { | 
 |     type Item = &'ch str; | 
 |  | 
 |     fn split(self) -> (Self, Option<Self>) { | 
 |         match split(self.chars) { | 
 |             Some((left, right)) => ( | 
 |                 MatchesProducer { | 
 |                     chars: left, | 
 |                     ..self | 
 |                 }, | 
 |                 Some(MatchesProducer { | 
 |                     chars: right, | 
 |                     ..self | 
 |                 }), | 
 |             ), | 
 |             None => (self, None), | 
 |         } | 
 |     } | 
 |  | 
 |     fn fold_with<F>(self, folder: F) -> F | 
 |     where | 
 |         F: Folder<Self::Item>, | 
 |     { | 
 |         self.pattern.fold_matches(self.chars, folder) | 
 |     } | 
 | } | 
 |  | 
 | // ///////////////////////////////////////////////////////////////////////// | 
 |  | 
 | /// Parallel iterator over substrings that match a pattern, with their positions | 
 | #[derive(Debug, Clone)] | 
 | pub struct MatchIndices<'ch, P: Pattern> { | 
 |     chars: &'ch str, | 
 |     pattern: P, | 
 | } | 
 |  | 
 | struct MatchIndicesProducer<'ch, 'pat, P: Pattern> { | 
 |     index: usize, | 
 |     chars: &'ch str, | 
 |     pattern: &'pat P, | 
 | } | 
 |  | 
 | impl<'ch, P: Pattern> ParallelIterator for MatchIndices<'ch, P> { | 
 |     type Item = (usize, &'ch str); | 
 |  | 
 |     fn drive_unindexed<C>(self, consumer: C) -> C::Result | 
 |     where | 
 |         C: UnindexedConsumer<Self::Item>, | 
 |     { | 
 |         let producer = MatchIndicesProducer { | 
 |             index: 0, | 
 |             chars: self.chars, | 
 |             pattern: &self.pattern, | 
 |         }; | 
 |         bridge_unindexed(producer, consumer) | 
 |     } | 
 | } | 
 |  | 
 | impl<'ch, 'pat, P: Pattern> UnindexedProducer for MatchIndicesProducer<'ch, 'pat, P> { | 
 |     type Item = (usize, &'ch str); | 
 |  | 
 |     fn split(self) -> (Self, Option<Self>) { | 
 |         match split(self.chars) { | 
 |             Some((left, right)) => ( | 
 |                 MatchIndicesProducer { | 
 |                     chars: left, | 
 |                     ..self | 
 |                 }, | 
 |                 Some(MatchIndicesProducer { | 
 |                     chars: right, | 
 |                     index: self.index + left.len(), | 
 |                     ..self | 
 |                 }), | 
 |             ), | 
 |             None => (self, None), | 
 |         } | 
 |     } | 
 |  | 
 |     fn fold_with<F>(self, folder: F) -> F | 
 |     where | 
 |         F: Folder<Self::Item>, | 
 |     { | 
 |         self.pattern | 
 |             .fold_match_indices(self.chars, folder, self.index) | 
 |     } | 
 | } |