core_extensions/strings/
iterators.rs

1use super::StringExt;
2
3use std_::mem;
4use std_::str::CharIndices;
5
6#[inline(always)]
7fn next_split<'a, P, T: Eq + Clone>(
8    pred: &mut P,
9    s: &mut &'a str,
10    last: &mut T,
11) -> Option<KeyStr<'a, T>>
12where
13    P: FnMut(char) -> T,
14{
15    let mut next = last.clone();
16    if s.is_empty() {
17        return None;
18    }
19    let end = s
20        .find(|c| {
21            next = pred(c);
22            *last != next
23        })
24        .map_or(s.len(), |v| v);
25    let (ret, new_s) = s.split_at(end);
26    *s = new_s;
27    let key = mem::replace(last, next);
28    Some(KeyStr { str: ret, key })
29}
30
31#[inline(always)]
32fn next_rsplit<'a, P, T: Eq + Clone>(
33    pred: &mut P,
34    s: &mut &'a str,
35    last: &mut T,
36) -> Option<KeyStr<'a, T>>
37where
38    P: FnMut(char) -> T,
39{
40    let mut next = last.clone();
41    if s.is_empty() {
42        return None;
43    }
44    let left = s
45        .rfind(|c| {
46            next = pred(c);
47            *last != next
48        })
49        .map_or(0, |v| s.next_char_boundary(v));
50    let (new_s, ret) = s.split_at(left);
51    *s = new_s;
52    let key = mem::replace(last, next);
53    Some(KeyStr { str: ret, key })
54}
55
56//-------------------------------------------------------------------------------------------
57
58/// A pair of (string slice, key) returned by the 
59/// [RSplitWhile](struct.RSplitWhile.html)/
60/// [SplitWhile](struct.SplitWhile.html) iterators.
61#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
62pub struct KeyStr<'a, T> {
63    /// `str_slice` is a string slice for which all characters were mapped to `key` by a closure.
64    pub str: &'a str,
65    /// The value that all the chars in the string slice were mapped to.
66    pub key: T,
67}
68
69impl<'a, T> KeyStr<'a, T> {
70    /// Converts this into a key, string slice pair
71    pub fn into_pair(self)->(T,&'a str){
72        (self.key,self.str)
73    }
74}
75
76//-------------------------------------------------------------------------------------------
77
78/// Iterator over string slices,
79/// in which all the chars in each string were mapped to the same key by a closure.
80///
81/// Look [here](trait.StringExt.html#method.split_while) for examples.
82#[derive(Debug, Clone)]
83pub struct SplitWhile<'a, P, T> {
84    pub(super) mapper: P,
85    pub(super) s: &'a str,
86    pub(super) last_left: T,
87    pub(super) last_right: T,
88}
89
90impl<'a, P, T: Eq + Clone> Iterator for SplitWhile<'a, P, T>
91where
92    P: FnMut(char) -> T,
93{
94    type Item = KeyStr<'a, T>;
95    fn next(&mut self) -> Option<Self::Item> {
96        next_split(&mut self.mapper, &mut self.s, &mut self.last_left)
97    }
98}
99
100impl<'a, P, T: Eq + Clone> DoubleEndedIterator for SplitWhile<'a, P, T>
101where
102    P: FnMut(char) -> T,
103{
104    fn next_back(&mut self) -> Option<Self::Item> {
105        next_rsplit(&mut self.mapper, &mut self.s, &mut self.last_right)
106    }
107}
108
109//-------------------------------------------------------------------------------------------
110
111/// Iterator over string slices,
112/// in which all the chars in each string were mapped to the same key by a closure,
113/// iterating from the end.
114///
115/// Look [here](trait.StringExt.html#method.rsplit_while) for examples.
116#[derive(Debug, Clone)]
117pub struct RSplitWhile<'a, P, T> {
118    pub(super) mapper: P,
119    pub(super) s: &'a str,
120    pub(super) last_left: T,
121    pub(super) last_right: T,
122}
123
124impl<'a, P, T: Eq + Clone> Iterator for RSplitWhile<'a, P, T>
125where
126    P: FnMut(char) -> T,
127{
128    type Item = KeyStr<'a, T>;
129    fn next(&mut self) -> Option<Self::Item> {
130        next_rsplit(&mut self.mapper, &mut self.s, &mut self.last_right)
131    }
132}
133
134impl<'a, P, T: Eq + Clone> DoubleEndedIterator for RSplitWhile<'a, P, T>
135where
136    P: FnMut(char) -> T,
137{
138    fn next_back(&mut self) -> Option<Self::Item> {
139        next_split(&mut self.mapper, &mut self.s, &mut self.last_left)
140    }
141}
142
143//-------------------------------------------------------------------------------------------
144
145/// Like [`CharIndices`], which starts from an offset.
146///
147/// Look [here](trait.StringExt.html#method.char_indices_from) for examples.
148///
149/// # Motivation
150/// 
151/// The reason to use this instead of `string[from..].char_indices()` is that 
152/// this gives you the position of the characters in `string`, 
153/// while [`CharIndices`] gives you the position of the characters in `string[from..]`.
154/// 
155/// [`CharIndices`]: https://doc.rust-lang.org/std/str/struct.CharIndices.html
156#[derive(Clone, Debug)]
157pub struct CharIndicesFrom<'a> {
158    pub(super) offset: usize,
159    pub(super) iter: CharIndices<'a>,
160}
161
162impl<'a> Iterator for CharIndicesFrom<'a> {
163    type Item = (usize, char);
164
165    #[inline]
166    fn next(&mut self) -> Option<(usize, char)> {
167        self.iter.next().map(|(i, c)| (i + self.offset, c))
168    }
169
170    #[inline]
171    fn count(self) -> usize {
172        self.iter.count()
173    }
174
175    #[inline]
176    fn size_hint(&self) -> (usize, Option<usize>) {
177        self.iter.size_hint()
178    }
179
180    #[inline]
181    fn last(mut self) -> Option<(usize, char)> {
182        self.next_back()
183    }
184}
185
186impl<'a> DoubleEndedIterator for CharIndicesFrom<'a> {
187    #[inline]
188    fn next_back(&mut self) -> Option<(usize, char)> {
189        self.iter.next_back().map(|(i, c)| (i + self.offset, c))
190    }
191}
192
193impl<'a> CharIndicesFrom<'a> {
194    /// Returns the rest of the slice to be iterated over.
195    pub fn as_str(&self) -> &'a str {
196        self.iter.as_str()
197    }
198}