From dedc441fa5e370d8ec4eeb6df8cb13f6ab179e13 Mon Sep 17 00:00:00 2001 From: okaneco <47607823+okaneco@users.noreply.github.com> Date: Mon, 14 Oct 2024 21:02:49 -0400 Subject: [PATCH] Add new unstable feature `const_eq_ignore_ascii_case` Mark `[u8]`, `str` `eq_ignore_ascii_case` functions const --- library/core/src/lib.rs | 1 + library/core/src/slice/ascii.rs | 24 ++++++++++++++++++++++-- library/core/src/str/mod.rs | 3 ++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 87c6bb39ce6..2f4f33dcc85 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -115,6 +115,7 @@ #![feature(const_align_of_val_raw)] #![feature(const_alloc_layout)] #![feature(const_black_box)] +#![feature(const_eq_ignore_ascii_case)] #![feature(const_eval_select)] #![feature(const_float_methods)] #![feature(const_heap)] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 58ba3a1573a..17ad4fd8f67 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -52,10 +52,30 @@ pub const fn as_ascii(&self) -> Option<&[ascii::Char]> { /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, /// but without allocating and copying temporaries. #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_unstable(feature = "const_eq_ignore_ascii_case", issue = "131719")] #[must_use] #[inline] - pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { - self.len() == other.len() && iter::zip(self, other).all(|(a, b)| a.eq_ignore_ascii_case(b)) + pub const fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { + if self.len() != other.len() { + return false; + } + + // FIXME(const-hack): This implementation can be reverted when + // `core::iter::zip` is allowed in const. The original implementation: + // self.len() == other.len() && iter::zip(self, other).all(|(a, b)| a.eq_ignore_ascii_case(b)) + let mut a = self; + let mut b = other; + + while let ([first_a, rest_a @ ..], [first_b, rest_b @ ..]) = (a, b) { + if first_a.eq_ignore_ascii_case(&first_b) { + a = rest_a; + b = rest_b; + } else { + return false; + } + } + + true } /// Converts this slice to its ASCII upper case equivalent in-place. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 58d6e07de8d..0f7c2c999d0 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2474,9 +2474,10 @@ pub const fn as_ascii(&self) -> Option<&[ascii::Char]> { /// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS")); /// ``` #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[rustc_const_unstable(feature = "const_eq_ignore_ascii_case", issue = "131719")] #[must_use] #[inline] - pub fn eq_ignore_ascii_case(&self, other: &str) -> bool { + pub const fn eq_ignore_ascii_case(&self, other: &str) -> bool { self.as_bytes().eq_ignore_ascii_case(other.as_bytes()) }