Skip to content

Commit fd78ba1

Browse files
committed
Make {str,[u8]}::eq_ignore_ascii_case const
1 parent cba1407 commit fd78ba1

File tree

6 files changed

+57
-4
lines changed

6 files changed

+57
-4
lines changed

library/core/src/intrinsics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2449,7 +2449,7 @@ extern "rust-intrinsic" {
24492449
/// const fn compiletime() -> i32 { 2 }
24502450
///
24512451
/// unsafe {
2452-
// // ⚠ This code violates the required equivalence of `compiletime`
2452+
/// // ⚠ This code violates the required equivalence of `compiletime`
24532453
/// // and `runtime`.
24542454
/// const_eval_select((), compiletime, runtime)
24552455
/// }

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
#![feature(const_replace)]
147147
#![feature(const_size_of_val)]
148148
#![feature(const_size_of_val_raw)]
149+
#![feature(const_slice_eq_ignore_ascii_case)]
149150
#![feature(const_slice_from_raw_parts_mut)]
150151
#![feature(const_slice_from_ref)]
151152
#![feature(const_slice_index)]

library/core/src/slice/ascii.rs

+26-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use crate::ascii;
44
use crate::fmt::{self, Write};
5+
use crate::intrinsics;
56
use crate::iter;
67
use crate::mem;
78
use crate::ops;
@@ -52,10 +53,33 @@ impl [u8] {
5253
/// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
5354
/// but without allocating and copying temporaries.
5455
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
56+
#[rustc_const_unstable(feature = "const_slice_eq_ignore_ascii_case", issue = "none")]
5557
#[must_use]
5658
#[inline]
57-
pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
58-
self.len() == other.len() && iter::zip(self, other).all(|(a, b)| a.eq_ignore_ascii_case(b))
59+
pub const fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool {
60+
const fn eq_ignore_ascii_case_ct(a: &[u8], b: &[u8]) -> bool {
61+
a.len() == b.len() && {
62+
let mut i = 0;
63+
while i < a.len() {
64+
if !u8::eq_ignore_ascii_case(&a[i], &b[i]) {
65+
return false;
66+
}
67+
i += 1;
68+
}
69+
true
70+
}
71+
}
72+
fn eq_ignore_ascii_case_rt(a: &[u8], b: &[u8]) -> bool {
73+
a.len() == b.len() && iter::zip(a, b).all(|(a, b)| u8::eq_ignore_ascii_case(a, b))
74+
}
75+
// SAFETY: both branches compute the same result, the runtime one is just more optimized
76+
unsafe {
77+
intrinsics::const_eval_select(
78+
(self, other),
79+
eq_ignore_ascii_case_ct,
80+
eq_ignore_ascii_case_rt,
81+
)
82+
}
5983
}
6084

6185
/// Converts this slice to its ASCII upper case equivalent in-place.

library/core/src/str/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2391,9 +2391,10 @@ impl str {
23912391
/// assert!(!"Ferrös".eq_ignore_ascii_case("FERRÖS"));
23922392
/// ```
23932393
#[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")]
2394+
#[rustc_const_unstable(feature = "const_slice_eq_ignore_ascii_case", issue = "none")]
23942395
#[must_use]
23952396
#[inline]
2396-
pub fn eq_ignore_ascii_case(&self, other: &str) -> bool {
2397+
pub const fn eq_ignore_ascii_case(&self, other: &str) -> bool {
23972398
self.as_bytes().eq_ignore_ascii_case(other.as_bytes())
23982399
}
23992400

library/core/tests/ascii.rs

+26
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@ fn test_is_ascii() {
1616
assert!(!"ประเทศไทย中华ệ ".chars().any(|c| c.is_ascii()));
1717
}
1818

19+
#[test]
20+
fn test_is_ascii_const() {
21+
const _: () = {
22+
assert!(b"".is_ascii());
23+
assert!(b"banana\0\x7F".is_ascii());
24+
assert!(!b"Vi\xe1\xbb\x87t Nam".is_ascii());
25+
26+
assert!("".is_ascii());
27+
assert!("banana\0\u{7F}".is_ascii());
28+
assert!(!"ประเทศไทย中华Việt Nam".is_ascii());
29+
};
30+
}
31+
1932
#[test]
2033
fn test_to_ascii_uppercase() {
2134
assert_eq!("url()URL()uRl()ürl".to_ascii_uppercase(), "URL()URL()URL()üRL");
@@ -112,6 +125,19 @@ fn test_eq_ignore_ascii_case() {
112125
}
113126
}
114127

128+
#[test]
129+
fn test_eq_ignore_ascii_case_const() {
130+
const _: () = {
131+
assert!("url()URL()uRl()Ürl".eq_ignore_ascii_case("url()url()url()Ürl"));
132+
assert!(!"Ürl".eq_ignore_ascii_case("ürl"));
133+
// Dotted capital I, Kelvin sign, Sharp S.
134+
assert!("HİKß".eq_ignore_ascii_case("hİKß"));
135+
assert!(!"İ".eq_ignore_ascii_case("i"));
136+
assert!(!"K".eq_ignore_ascii_case("k"));
137+
assert!(!"ß".eq_ignore_ascii_case("s"));
138+
};
139+
}
140+
115141
#[test]
116142
fn inference_works() {
117143
let x = "a".to_string();

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#![feature(const_pointer_is_aligned)]
2020
#![feature(const_ptr_as_ref)]
2121
#![feature(const_ptr_write)]
22+
#![feature(const_slice_eq_ignore_ascii_case)]
2223
#![feature(const_trait_impl)]
2324
#![feature(const_likely)]
2425
#![feature(const_location_fields)]

0 commit comments

Comments
 (0)