未验证 提交 60625a6e 编写于 作者: M Matthias Krüger 提交者: GitHub

Rollup merge of #88858 - spektom:to_lower_upper_rev, r=dtolnay

Allow reverse iteration of lowercase'd/uppercase'd chars

The PR implements `DoubleEndedIterator` trait for `ToLowercase` and `ToUppercase`.

This enables reverse iteration of lowercase/uppercase variants of character sequences.
One of use cases:  determining whether a char sequence is a suffix of another one.

Example:

```rust
fn endswith_ignore_case(s1: &str, s2: &str) -> bool {
    for eob in s1
        .chars()
        .flat_map(|c| c.to_lowercase())
        .rev()
        .zip_longest(s2.chars().flat_map(|c| c.to_lowercase()).rev())
    {
        match eob {
            EitherOrBoth::Both(c1, c2) => {
                if c1 != c2 {
                    return false;
                }
            }
            EitherOrBoth::Left(_) => return true,
            EitherOrBoth::Right(_) => return false,
        }
    }
    true
}
```
......@@ -1183,6 +1183,37 @@ fn test_rev_iterator() {
assert_eq!(pos, v.len());
}
#[test]
fn test_to_lowercase_rev_iterator() {
let s = "AÖßÜ💩ΣΤΙΓΜΑΣDžfiİ";
let v = ['\u{307}', 'i', 'fi', 'dž', 'σ', 'α', 'μ', 'γ', 'ι', 'τ', 'σ', '💩', 'ü', 'ß', 'ö', 'a'];
let mut pos = 0;
let it = s.chars().flat_map(|c| c.to_lowercase()).rev();
for c in it {
assert_eq!(c, v[pos]);
pos += 1;
}
assert_eq!(pos, v.len());
}
#[test]
fn test_to_uppercase_rev_iterator() {
let s = "aößü💩στιγμαςDžfiᾀ";
let v =
['Ι', 'Ἀ', 'I', 'F', 'DŽ', 'Σ', 'Α', 'Μ', 'Γ', 'Ι', 'Τ', 'Σ', '💩', 'Ü', 'S', 'S', 'Ö', 'A'];
let mut pos = 0;
let it = s.chars().flat_map(|c| c.to_uppercase()).rev();
for c in it {
assert_eq!(c, v[pos]);
pos += 1;
}
assert_eq!(pos, v.len());
}
#[test]
#[cfg_attr(miri, ignore)] // Miri is too slow
fn test_chars_decoding() {
......
......@@ -393,6 +393,13 @@ fn size_hint(&self) -> (usize, Option<usize>) {
}
}
#[stable(feature = "case_mapping_double_ended", since = "1.59.0")]
impl DoubleEndedIterator for ToLowercase {
fn next_back(&mut self) -> Option<char> {
self.0.next_back()
}
}
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for ToLowercase {}
......@@ -420,6 +427,13 @@ fn size_hint(&self) -> (usize, Option<usize>) {
}
}
#[stable(feature = "case_mapping_double_ended", since = "1.59.0")]
impl DoubleEndedIterator for ToUppercase {
fn next_back(&mut self) -> Option<char> {
self.0.next_back()
}
}
#[stable(feature = "fused", since = "1.26.0")]
impl FusedIterator for ToUppercase {}
......@@ -479,6 +493,26 @@ fn size_hint(&self) -> (usize, Option<usize>) {
}
}
impl DoubleEndedIterator for CaseMappingIter {
fn next_back(&mut self) -> Option<char> {
match *self {
CaseMappingIter::Three(a, b, c) => {
*self = CaseMappingIter::Two(a, b);
Some(c)
}
CaseMappingIter::Two(b, c) => {
*self = CaseMappingIter::One(b);
Some(c)
}
CaseMappingIter::One(c) => {
*self = CaseMappingIter::Zero;
Some(c)
}
CaseMappingIter::Zero => None,
}
}
}
impl fmt::Display for CaseMappingIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
......
......@@ -103,6 +103,9 @@ fn lower(c: char) -> String {
let iter: String = c.to_lowercase().collect();
let disp: String = c.to_lowercase().to_string();
assert_eq!(iter, disp);
let iter_rev: String = c.to_lowercase().rev().collect();
let disp_rev: String = disp.chars().rev().collect();
assert_eq!(iter_rev, disp_rev);
iter
}
assert_eq!(lower('A'), "a");
......@@ -130,6 +133,9 @@ fn upper(c: char) -> String {
let iter: String = c.to_uppercase().collect();
let disp: String = c.to_uppercase().to_string();
assert_eq!(iter, disp);
let iter_rev: String = c.to_uppercase().rev().collect();
let disp_rev: String = disp.chars().rev().collect();
assert_eq!(iter_rev, disp_rev);
iter
}
assert_eq!(upper('a'), "A");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册