diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2022-09-12 22:47:14 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-12 22:47:14 +0200 |
| commit | 7fc3183520bfc20c40bdc1718376378df05716c7 (patch) | |
| tree | 693dbf65a18e6578861333781da228fb3189b5d9 | |
| parent | b7504d6f4f418f991274c6e062111348c55afb3a (diff) | |
| parent | cb02b647dc0441cfe152fa037ee14f4606c477cb (diff) | |
| download | rust-7fc3183520bfc20c40bdc1718376378df05716c7.tar.gz rust-7fc3183520bfc20c40bdc1718376378df05716c7.zip | |
Rollup merge of #100291 - WaffleLapkin:cstr_const_methods, r=oli-obk
constify some `CStr` methods
This PR marks the following public APIs as `const`:
```rust
impl CStr {
// feature(const_cstr_from_bytes)
pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError>;
pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError>;
// feature(const_cstr_to_bytes)
pub const fn to_bytes(&self) -> &[u8];
pub const fn to_bytes_with_nul(&self) -> &[u8];
pub const fn to_str(&self) -> Result<&str, str::Utf8Error>;
}
```
r? ```@oli-obk``` (use of `const_eval_select` :P )
cc ```@mina86``` (you've asked for this <3 )
| -rw-r--r-- | library/core/src/ffi/c_str.rs | 19 | ||||
| -rw-r--r-- | library/core/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/core/src/slice/memchr.rs | 29 |
3 files changed, 37 insertions, 12 deletions
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 970830045b8..21f80ec025a 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -120,10 +120,10 @@ enum FromBytesWithNulErrorKind { } impl FromBytesWithNulError { - fn interior_nul(pos: usize) -> FromBytesWithNulError { + const fn interior_nul(pos: usize) -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) } } - fn not_nul_terminated() -> FromBytesWithNulError { + const fn not_nul_terminated() -> FromBytesWithNulError { FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated } } @@ -294,7 +294,8 @@ impl CStr { /// ``` /// #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] - pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { + #[rustc_const_unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] + pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { Some(nul_pos) => { @@ -343,7 +344,8 @@ impl CStr { /// assert!(cstr.is_err()); /// ``` #[stable(feature = "cstr_from_bytes", since = "1.10.0")] - pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> { let nul_pos = memchr::memchr(0, bytes); match nul_pos { Some(nul_pos) if nul_pos + 1 == bytes.len() => { @@ -493,7 +495,8 @@ impl CStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_bytes(&self) -> &[u8] { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_bytes(&self) -> &[u8] { let bytes = self.to_bytes_with_nul(); // SAFETY: to_bytes_with_nul returns slice with length at least 1 unsafe { bytes.get_unchecked(..bytes.len() - 1) } @@ -520,7 +523,8 @@ impl CStr { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_bytes_with_nul(&self) -> &[u8] { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_bytes_with_nul(&self) -> &[u8] { // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s // is safe on all supported targets. unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } @@ -543,7 +547,8 @@ impl CStr { /// assert_eq!(cstr.to_str(), Ok("foo")); /// ``` #[stable(feature = "cstr_to_str", since = "1.4.0")] - pub fn to_str(&self) -> Result<&str, str::Utf8Error> { + #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")] + pub const fn to_str(&self) -> Result<&str, str::Utf8Error> { // N.B., when `CStr` is changed to perform the length check in `.to_bytes()` // instead of in `from_ptr()`, it may be worth considering if this should // be rewritten to do the UTF-8 check inline with the length calculation diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 5b1e2045fff..5621d15c1cd 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -159,6 +159,7 @@ #![feature(const_slice_from_ref)] #![feature(const_slice_index)] #![feature(const_is_char_boundary)] +#![feature(const_cstr_methods)] // // Language features: #![feature(abi_unadjusted)] diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index dffeaf6a834..e0419f0ffdb 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -2,6 +2,7 @@ // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch use crate::cmp; +use crate::intrinsics; use crate::mem; const LO_USIZE: usize = usize::repeat_u8(0x01); @@ -35,13 +36,31 @@ fn repeat_byte(b: u8) -> usize { /// Returns the first index matching the byte `x` in `text`. #[must_use] #[inline] -pub fn memchr(x: u8, text: &[u8]) -> Option<usize> { - // Fast path for small slices - if text.len() < 2 * USIZE_BYTES { - return text.iter().position(|elt| *elt == x); +pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> { + #[inline] + fn rt_impl(x: u8, text: &[u8]) -> Option<usize> { + // Fast path for small slices + if text.len() < 2 * USIZE_BYTES { + return text.iter().position(|elt| *elt == x); + } + + memchr_general_case(x, text) + } + + const fn const_impl(x: u8, bytes: &[u8]) -> Option<usize> { + let mut i = 0; + while i < bytes.len() { + if bytes[i] == x { + return Some(i); + } + i += 1; + } + + None } - memchr_general_case(x, text) + // SAFETY: The const and runtime versions have identical behavior + unsafe { intrinsics::const_eval_select((x, text), const_impl, rt_impl) } } fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> { |
