Skip to content

Commit

Permalink
fix #124714 str.to_lowercase sigma handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcondiro committed May 5, 2024
1 parent 6d721dd commit 50d7b9d
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 8 deletions.
12 changes: 4 additions & 8 deletions library/alloc/src/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -368,21 +368,17 @@ impl str {
pub fn to_lowercase(&self) -> String {
let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_lowercase);

// Safety: we know this is a valid char boundary since
// out.len() is only progressed if ascii bytes are found
let rest = unsafe { self.get_unchecked(out.len()..) };

// Safety: We have written only valid ASCII to our vec
let mut s = unsafe { String::from_utf8_unchecked(out) };

for (i, c) in rest[..].char_indices() {
for (i, c) in self.char_indices().skip(s.len()) {
if c == 'Σ' {
// Σ maps to σ, except at the end of a word where it maps to ς.
// This is the only conditional (contextual) but language-independent mapping
// in `SpecialCasing.txt`,
// so hard-code it rather than have a generic "condition" mechanism.
// See https://github.com/rust-lang/rust/issues/26035
map_uppercase_sigma(rest, i, &mut s)
s.push(map_uppercase_sigma(&self, i));
} else {
match conversions::to_lower(c) {
[a, '\0', _] => s.push(a),
Expand All @@ -400,13 +396,13 @@ impl str {
}
return s;

fn map_uppercase_sigma(from: &str, i: usize, to: &mut String) {
fn map_uppercase_sigma(from: &str, i: usize) -> char {
// See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992
// for the definition of `Final_Sigma`.
debug_assert!('Σ'.len_utf8() == 2);
let is_word_final = case_ignorable_then_cased(from[..i].chars().rev())
&& !case_ignorable_then_cased(from[i + 2..].chars());
to.push_str(if is_word_final { "ς" } else { "σ" });
if is_word_final { 'ς' } else { 'σ' }
}

fn case_ignorable_then_cased<I: Iterator<Item = char>>(iter: I) -> bool {
Expand Down
3 changes: 3 additions & 0 deletions library/alloc/tests/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1848,6 +1848,9 @@ fn to_lowercase() {
assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α");
assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α");

// https://github.com/rust-lang/rust/issues/124714
assert_eq!("abcdefghijklmnopΣ".to_lowercase(), "abcdefghijklmnopς");

// a really long string that has it's lowercase form
// even longer. this tests that implementations don't assume
// an incorrect upper bound on allocations
Expand Down

0 comments on commit 50d7b9d

Please sign in to comment.