1 //! Common splitter for strings and slices
3 //! This module is private, so these items are effectively `pub(super)`
5 use crate::iter
::plumbing
::{Folder, UnindexedProducer}
;
7 /// Common producer for splitting on a predicate.
8 pub(super) struct SplitProducer
<'p
, P
, V
> {
12 /// Marks the endpoint beyond which we've already found no separators.
16 /// Helper trait so `&str`, `&[T]`, and `&mut [T]` can share `SplitProducer`.
17 pub(super) trait Fissile
<P
>: Sized
{
18 fn length(&self) -> usize;
19 fn midpoint(&self, end
: usize) -> usize;
20 fn find(&self, separator
: &P
, start
: usize, end
: usize) -> Option
<usize>;
21 fn rfind(&self, separator
: &P
, end
: usize) -> Option
<usize>;
22 fn split_once(self, index
: usize) -> (Self, Self);
23 fn fold_splits
<F
>(self, separator
: &P
, folder
: F
, skip_last
: bool
) -> F
29 impl<'p
, P
, V
> SplitProducer
<'p
, P
, V
>
33 pub(super) fn new(data
: V
, separator
: &'p P
) -> Self {
41 /// Common `fold_with` implementation, integrating `SplitTerminator`'s
42 /// need to sometimes skip its final empty item.
43 pub(super) fn fold_with
<F
>(self, folder
: F
, skip_last
: bool
) -> F
53 if tail
== data
.length() {
54 // No tail section, so just let `fold_splits` handle it.
55 data
.fold_splits(separator
, folder
, skip_last
)
56 } else if let Some(index
) = data
.rfind(separator
, tail
) {
57 // We found the last separator to complete the tail, so
58 // end with that slice after `fold_splits` finds the rest.
59 let (left
, right
) = data
.split_once(index
);
60 let folder
= left
.fold_splits(separator
, folder
, false);
61 if skip_last
|| folder
.full() {
67 // We know there are no separators at all. Return our whole data.
77 impl<'p
, P
, V
> UnindexedProducer
for SplitProducer
<'p
, P
, V
>
84 fn split(self) -> (Self, Option
<Self>) {
85 // Look forward for the separator, and failing that look backward.
86 let mid
= self.data
.midpoint(self.tail
);
87 let index
= match self.data
.find(self.separator
, mid
, self.tail
) {
88 Some(i
) => Some(mid
+ i
),
89 None
=> self.data
.rfind(self.separator
, mid
),
92 if let Some(index
) = index
{
93 let len
= self.data
.length();
94 let (left
, right
) = self.data
.split_once(index
);
96 let (left_tail
, right_tail
) = if index
< mid
{
97 // If we scanned backwards to find the separator, everything in
98 // the right side is exhausted, with no separators left to find.
101 let right_index
= len
- right
.length();
102 (mid
, self.tail
- right_index
)
105 // Create the left split before the separator.
106 let left
= SplitProducer
{
112 // Create the right split following the separator.
113 let right
= SplitProducer
{
121 // The search is exhausted, no more separators...
122 (SplitProducer { tail: 0, ..self }
, None
)
126 fn fold_with
<F
>(self, folder
: F
) -> F
128 F
: Folder
<Self::Item
>,
130 self.fold_with(folder
, false)