Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions library/core/src/char/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -852,6 +852,9 @@ impl char {
/// `Lowercase` is described in Chapter 4 (Character Properties) of the [Unicode Standard] and
/// specified in the [Unicode Character Database][ucd] [`DerivedCoreProperties.txt`].
///
/// For any `c: char`, `c.is_lowercase()` implies `c.to_lowercase() == c`.
/// However, the reverse is not necessarily true, even for cased characters.
///
/// [Unicode Standard]: https://www.unicode.org/versions/latest/
/// [ucd]: https://www.unicode.org/reports/tr44/
/// [`DerivedCoreProperties.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt
Expand Down Expand Up @@ -896,6 +899,9 @@ impl char {
/// (Character Properties) of the [Unicode Standard] and specified in the [Unicode Character
/// Database][ucd] [`UnicodeData.txt`].
///
/// For any `c: char`, `c.is_titlecase()` implies `c.to_titlecase() == c`.
/// However, the reverse is not usually true, even for cased characters.
///
/// [Unicode Standard]: https://www.unicode.org/versions/latest/
/// [ucd]: https://www.unicode.org/reports/tr44/
/// [`UnicodeData.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt
Expand Down Expand Up @@ -928,6 +934,9 @@ impl char {
/// `Uppercase` is described in Chapter 4 (Character Properties) of the [Unicode Standard] and
/// specified in the [Unicode Character Database][ucd] [`DerivedCoreProperties.txt`].
///
/// For any `c: char`, `c.is_uppercase()` implies `c.to_uppercase() == c`.
/// However, the reverse is not necessarily true, even for cased characters.
///
/// [Unicode Standard]: https://www.unicode.org/versions/latest/
/// [ucd]: https://www.unicode.org/reports/tr44/
/// [`DerivedCoreProperties.txt`]: https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt
Expand Down Expand Up @@ -1139,7 +1148,8 @@ impl char {
}

/// Returns an iterator that yields the lowercase mapping of this `char` as one or more
/// `char`s.
/// `char`s. The iterator also has implementations of [`Display`][core::fmt::Display],
/// [`PartialEq`], and [`Eq`].
///
/// If this `char` does not have a lowercase mapping, the iterator yields the same `char`.
///
Expand Down Expand Up @@ -1197,6 +1207,13 @@ impl char {
/// // convert into themselves.
/// assert_eq!('山'.to_lowercase().to_string(), "山");
/// ```
///
/// Check if a string is in lowercase:
///
/// ```
/// let s = "abcde\u{0301} 山";
/// assert!(s.chars().all(|c| c.to_lowercase() == c));
/// ```
#[must_use = "this returns the lowercased character as a new iterator, \
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
Expand All @@ -1206,7 +1223,8 @@ impl char {
}

/// Returns an iterator that yields the titlecase mapping of this `char` as one or more
/// `char`s.
/// `char`s. The iterator also has implementations of [`Display`][core::fmt::Display],
/// [`PartialEq`], and [`Eq`].
///
/// This is usually, but not always, equivalent to the uppercase mapping
/// returned by [`Self::to_uppercase`]. Prefer this method when seeking to capitalize
Expand Down Expand Up @@ -1274,6 +1292,21 @@ impl char {
/// assert_eq!('山'.to_titlecase().to_string(), "山");
/// ```
///
/// Check if a word is in titlecase:
///
/// ```
/// #![feature(titlecase)]
/// let word = "Dross";
/// let mut chars = word.chars();
/// let first_cased_char = chars.find(|c| c.is_cased());
/// let word_is_in_titlecase = if let Some(f) = first_cased_char {
/// f.to_titlecase() == f && chars.all(|c| c.to_lowercase() == c)
/// } else {
/// true
/// };
/// assert!(word_is_in_titlecase);
/// ```
///
/// # Note on locale
///
/// In Turkish and Azeri, the equivalent of 'i' in Latin has five forms instead of two:
Expand Down Expand Up @@ -1309,7 +1342,8 @@ impl char {
}

/// Returns an iterator that yields the uppercase mapping of this `char` as one or more
/// `char`s.
/// `char`s. The iterator also has implementations of [`Display`][core::fmt::Display],
/// [`PartialEq`], and [`Eq`].
///
/// Prefer this method when converting a word into ALL CAPS, but consider [`Self::to_titlecase`]
/// instead if you seek to capitalize Only The First Letter.
Expand Down Expand Up @@ -1374,6 +1408,13 @@ impl char {
/// assert_eq!('山'.to_uppercase().to_string(), "山");
/// ```
///
/// Check if a string is in uppercase:
///
/// ```
/// let s = "ABCDE\u{0301} 山";
/// assert!(s.chars().all(|c| c.to_uppercase() == c));
/// ```
///
/// # Note on locale
///
/// In Turkish and Azeri, the equivalent of 'i' in Latin has five forms instead of two:
Expand Down
55 changes: 55 additions & 0 deletions library/core/src/char/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@ macro_rules! casemappingiter_impls {
#[$fusedstab:meta]
#[$exactstab:meta]
#[$displaystab:meta]
#[$eqstab:meta]
$(#[$attr:meta])*
$ITER_NAME:ident
) => {
Expand Down Expand Up @@ -468,6 +469,41 @@ macro_rules! casemappingiter_impls {
fmt::Display::fmt(&self.0, f)
}
}

#[$eqstab]
impl PartialEq<ToUppercase> for $ITER_NAME {
#[inline]
fn eq(&self, other: &ToUppercase) -> bool {
self.0 == other.0
}
}

#[unstable(feature = "titlecase", issue = "153892")]
impl PartialEq<ToTitlecase> for $ITER_NAME {
#[inline]
fn eq(&self, other: &ToTitlecase) -> bool {
self.0 == other.0
}
}

#[$eqstab]
impl PartialEq<ToLowercase> for $ITER_NAME {
#[inline]
fn eq(&self, other: &ToLowercase) -> bool {
self.0 == other.0
}
}

#[$eqstab]
impl PartialEq<char> for $ITER_NAME {
#[inline]
fn eq(&self, other: &char) -> bool {
self.0 == *other
}
}

#[$eqstab]
impl Eq for $ITER_NAME {}
}
}

Expand All @@ -477,6 +513,7 @@ casemappingiter_impls! {
#[stable(feature = "fused", since = "1.26.0")]
#[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")]
#[stable(feature = "char_struct_display", since = "1.16.0")]
#[stable(feature = "iter_partialeq", since = "CURRENT_RUSTC_VERSION")]
/// Returns an iterator that yields the uppercase equivalent of a `char`.
///
/// This `struct` is created by the [`to_uppercase`] method on [`char`]. See
Expand All @@ -492,6 +529,7 @@ casemappingiter_impls! {
#[unstable(feature = "titlecase", issue = "153892")]
#[unstable(feature = "titlecase", issue = "153892")]
#[unstable(feature = "titlecase", issue = "153892")]
#[unstable(feature = "titlecase", issue = "153892")]
/// Returns an iterator that yields the titlecase equivalent of a `char`.
///
/// This `struct` is created by the [`to_titlecase`] method on [`char`]. See
Expand All @@ -507,6 +545,7 @@ casemappingiter_impls! {
#[stable(feature = "fused", since = "1.26.0")]
#[stable(feature = "exact_size_case_mapping_iter", since = "1.35.0")]
#[stable(feature = "char_struct_display", since = "1.16.0")]
#[stable(feature = "iter_partialeq", since = "CURRENT_RUSTC_VERSION")]
/// Returns an iterator that yields the lowercase equivalent of a `char`.
///
/// This `struct` is created by the [`to_lowercase`] method on [`char`]. See
Expand Down Expand Up @@ -622,6 +661,22 @@ impl fmt::Display for CaseMappingIter {
}
}

impl PartialEq for CaseMappingIter {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0.as_slice() == other.0.as_slice()
}
}

impl Eq for CaseMappingIter {}

impl PartialEq<char> for CaseMappingIter {
#[inline]
fn eq(&self, other: &char) -> bool {
self.0.as_slice() == &[*other]
}
}

/// The error type returned when a checked char conversion fails.
#[stable(feature = "u8_from_char", since = "1.59.0")]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
Expand Down
24 changes: 20 additions & 4 deletions library/coretests/tests/char.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,26 @@ fn test_is_cased() {
fn test_char_case() {
for c in '\0'..='\u{10FFFF}' {
match c.case() {
None => assert!(!c.is_cased()),
Some(CharCase::Lower) => assert!(c.is_lowercase()),
Some(CharCase::Upper) => assert!(c.is_uppercase()),
Some(CharCase::Title) => assert!(c.is_titlecase()),
None => {
assert!(
!c.is_cased() && !c.is_lowercase() && !c.is_titlecase() && !c.is_uppercase()
);
assert_eq!(c.to_lowercase(), c);
assert_eq!(c.to_uppercase(), c);
assert_eq!(c.to_titlecase(), c);
}
Some(CharCase::Lower) => {
assert!(c.is_cased() && c.is_lowercase() && !c.is_titlecase() && !c.is_uppercase());
assert_eq!(c.to_lowercase(), c)
}
Some(CharCase::Upper) => {
assert!(c.is_cased() && !c.is_lowercase() && !c.is_titlecase() && c.is_uppercase());
assert_eq!(c.to_uppercase(), c)
}
Some(CharCase::Title) => {
assert!(c.is_cased() && !c.is_lowercase() && c.is_titlecase() && !c.is_uppercase());
assert_eq!(c.to_titlecase(), c)
}
}
}
}
Expand Down