about summary refs log tree commit diff
path: root/library/core/src
diff options
context:
space:
mode:
authorMaybe Waffle <waffle.lapkin@gmail.com>2022-08-09 03:20:15 +0400
committerMaybe Waffle <waffle.lapkin@gmail.com>2022-09-12 16:29:12 +0400
commitcb02b647dc0441cfe152fa037ee14f4606c477cb (patch)
treeb6281270b85bd18f3c0364ef6c25a278d7aadcff /library/core/src
parent9bbbf60b0442f1d56fc39f30274be77acc79164c (diff)
downloadrust-cb02b647dc0441cfe152fa037ee14f4606c477cb.tar.gz
rust-cb02b647dc0441cfe152fa037ee14f4606c477cb.zip
constify `CStr` methods
Diffstat (limited to 'library/core/src')
-rw-r--r--library/core/src/ffi/c_str.rs19
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/slice/memchr.rs29
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 @@ 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) => {
@@ -348,7 +349,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() => {
@@ -497,7 +499,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) }
@@ -524,7 +527,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]) }
@@ -547,7 +551,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 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<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> {