Fix #85462 by adding a marker flag

This will not affect ABI since the other variant of the enum is bigger.
It may break some code, but that would be very strange: usually people
don't continue after the first `Done` (or `None` for a normal iterator).
This commit is contained in:
Alexis Bourget 2021-07-11 17:45:12 +02:00
parent 4581c4ef6f
commit 101a146db9

View File

@ -928,6 +928,8 @@ struct EmptyNeedle {
end: usize, end: usize,
is_match_fw: bool, is_match_fw: bool,
is_match_bw: bool, is_match_bw: bool,
// Needed in case of an empty haystack, see #85462
is_finished: bool,
} }
impl<'a, 'b> StrSearcher<'a, 'b> { impl<'a, 'b> StrSearcher<'a, 'b> {
@ -941,6 +943,7 @@ fn new(haystack: &'a str, needle: &'b str) -> StrSearcher<'a, 'b> {
end: haystack.len(), end: haystack.len(),
is_match_fw: true, is_match_fw: true,
is_match_bw: true, is_match_bw: true,
is_finished: false,
}), }),
} }
} else { } else {
@ -966,13 +969,19 @@ fn haystack(&self) -> &'a str {
fn next(&mut self) -> SearchStep { fn next(&mut self) -> SearchStep {
match self.searcher { match self.searcher {
StrSearcherImpl::Empty(ref mut searcher) => { StrSearcherImpl::Empty(ref mut searcher) => {
if searcher.is_finished {
return SearchStep::Done;
}
// empty needle rejects every char and matches every empty string between them // empty needle rejects every char and matches every empty string between them
let is_match = searcher.is_match_fw; let is_match = searcher.is_match_fw;
searcher.is_match_fw = !searcher.is_match_fw; searcher.is_match_fw = !searcher.is_match_fw;
let pos = searcher.position; let pos = searcher.position;
match self.haystack[pos..].chars().next() { match self.haystack[pos..].chars().next() {
_ if is_match => SearchStep::Match(pos, pos), _ if is_match => SearchStep::Match(pos, pos),
None => SearchStep::Done, None => {
searcher.is_finished = true;
SearchStep::Done
}
Some(ch) => { Some(ch) => {
searcher.position += ch.len_utf8(); searcher.position += ch.len_utf8();
SearchStep::Reject(pos, searcher.position) SearchStep::Reject(pos, searcher.position)
@ -1045,12 +1054,18 @@ unsafe impl<'a, 'b> ReverseSearcher<'a> for StrSearcher<'a, 'b> {
fn next_back(&mut self) -> SearchStep { fn next_back(&mut self) -> SearchStep {
match self.searcher { match self.searcher {
StrSearcherImpl::Empty(ref mut searcher) => { StrSearcherImpl::Empty(ref mut searcher) => {
if searcher.is_finished {
return SearchStep::Done;
}
let is_match = searcher.is_match_bw; let is_match = searcher.is_match_bw;
searcher.is_match_bw = !searcher.is_match_bw; searcher.is_match_bw = !searcher.is_match_bw;
let end = searcher.end; let end = searcher.end;
match self.haystack[..end].chars().next_back() { match self.haystack[..end].chars().next_back() {
_ if is_match => SearchStep::Match(end, end), _ if is_match => SearchStep::Match(end, end),
None => SearchStep::Done, None => {
searcher.is_finished = true;
SearchStep::Done
}
Some(ch) => { Some(ch) => {
searcher.end -= ch.len_utf8(); searcher.end -= ch.len_utf8();
SearchStep::Reject(searcher.end, end) SearchStep::Reject(searcher.end, end)