From cb02b647dc0441cfe152fa037ee14f4606c477cb Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 9 Aug 2022 03:20:15 +0400 Subject: [PATCH] constify `CStr` methods --- library/core/src/ffi/c_str.rs | 19 ++++++++++++------- library/core/src/lib.rs | 1 + 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 82e63a7fe1d..ec3cce2a234 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -121,10 +121,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 } } @@ -299,7 +299,8 @@ pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a 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) => { @@ -348,7 +349,8 @@ pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulErro /// 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() => { @@ -497,7 +499,8 @@ pub const fn as_ptr(&self) -> *const c_char { #[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) } @@ -524,7 +527,8 @@ pub fn to_bytes(&self) -> &[u8] { #[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]) } @@ -547,7 +551,8 @@ pub fn to_bytes_with_nul(&self) -> &[u8] { /// 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 24742bb49b9..87ffc5abd2e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -157,6 +157,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 { - // 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 { + #[inline] + fn rt_impl(x: u8, text: &[u8]) -> Option { + // Fast path for small slices + if text.len() < 2 * USIZE_BYTES { + return text.iter().position(|elt| *elt == x); + } + + memchr_general_case(x, text) } - memchr_general_case(x, text) + const fn const_impl(x: u8, bytes: &[u8]) -> Option { + let mut i = 0; + while i < bytes.len() { + if bytes[i] == x { + return Some(i); + } + i += 1; + } + + None + } + + // 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 {