1 //! Common splitter for strings and slices
3 //! This module is private, so these items are effectively `pub(super)`
5 use iter
::plumbing
::{UnindexedProducer, Folder}
;
7 /// Common producer for splitting on a predicate.
8 pub struct SplitProducer
<'p
, 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 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
24 where F
: Folder
<Self>, Self: Send
;
27 impl<'p
, P
, V
> SplitProducer
<'p
, P
, V
>
28 where V
: Fissile
<P
> + Send
30 pub fn new(data
: V
, separator
: &'p P
) -> Self {
38 /// Common `fold_with` implementation, integrating `SplitTerminator`'s
39 /// need to sometimes skip its final empty item.
40 pub fn fold_with
<F
>(self, folder
: F
, skip_last
: bool
) -> F
43 let SplitProducer { data, separator, tail }
= self;
45 if tail
== data
.length() {
46 // No tail section, so just let `fold_splits` handle it.
47 data
.fold_splits(separator
, folder
, skip_last
)
49 } else if let Some(index
) = data
.rfind(separator
, tail
) {
50 // We found the last separator to complete the tail, so
51 // end with that slice after `fold_splits` finds the rest.
52 let (left
, right
) = data
.split_once(index
);
53 let folder
= left
.fold_splits(separator
, folder
, false);
54 if skip_last
|| folder
.full() {
61 // We know there are no separators at all. Return our whole data.
71 impl<'p
, P
, V
> UnindexedProducer
for SplitProducer
<'p
, P
, V
>
72 where V
: Fissile
<P
> + Send
,
77 fn split(self) -> (Self, Option
<Self>) {
78 // Look forward for the separator, and failing that look backward.
79 let mid
= self.data
.midpoint(self.tail
);
80 let index
= self.data
.find(self.separator
, mid
, self.tail
)
82 .or_else(|| self.data
.rfind(self.separator
, mid
));
84 if let Some(index
) = index
{
85 let len
= self.data
.length();
86 let (left
, right
) = self.data
.split_once(index
);
88 let (left_tail
, right_tail
) = if index
< mid
{
89 // If we scanned backwards to find the separator, everything in
90 // the right side is exhausted, with no separators left to find.
93 let right_index
= len
- right
.length();
94 (mid
, self.tail
- right_index
)
97 // Create the left split before the separator.
98 let left
= SplitProducer
{
104 // Create the right split following the separator.
105 let right
= SplitProducer
{
114 // The search is exhausted, no more separators...
115 (SplitProducer { tail: 0, ..self }
, None
)
119 fn fold_with
<F
>(self, folder
: F
) -> F
120 where F
: Folder
<Self::Item
>
122 self.fold_with(folder
, false)