Skip to content

Commit cb02b64

Browse files
committed
constify CStr methods
1 parent 9bbbf60 commit cb02b64

File tree

3 files changed

+37
-12
lines changed

3 files changed

+37
-12
lines changed

library/core/src/ffi/c_str.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -121,10 +121,10 @@ enum FromBytesWithNulErrorKind {
121121
}
122122

123123
impl FromBytesWithNulError {
124-
fn interior_nul(pos: usize) -> FromBytesWithNulError {
124+
const fn interior_nul(pos: usize) -> FromBytesWithNulError {
125125
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
126126
}
127-
fn not_nul_terminated() -> FromBytesWithNulError {
127+
const fn not_nul_terminated() -> FromBytesWithNulError {
128128
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
129129
}
130130

@@ -299,7 +299,8 @@ impl CStr {
299299
/// ```
300300
///
301301
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
302-
pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
302+
#[rustc_const_unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
303+
pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
303304
let nul_pos = memchr::memchr(0, bytes);
304305
match nul_pos {
305306
Some(nul_pos) => {
@@ -348,7 +349,8 @@ impl CStr {
348349
/// assert!(cstr.is_err());
349350
/// ```
350351
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
351-
pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
352+
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
353+
pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
352354
let nul_pos = memchr::memchr(0, bytes);
353355
match nul_pos {
354356
Some(nul_pos) if nul_pos + 1 == bytes.len() => {
@@ -497,7 +499,8 @@ impl CStr {
497499
#[must_use = "this returns the result of the operation, \
498500
without modifying the original"]
499501
#[stable(feature = "rust1", since = "1.0.0")]
500-
pub fn to_bytes(&self) -> &[u8] {
502+
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
503+
pub const fn to_bytes(&self) -> &[u8] {
501504
let bytes = self.to_bytes_with_nul();
502505
// SAFETY: to_bytes_with_nul returns slice with length at least 1
503506
unsafe { bytes.get_unchecked(..bytes.len() - 1) }
@@ -524,7 +527,8 @@ impl CStr {
524527
#[must_use = "this returns the result of the operation, \
525528
without modifying the original"]
526529
#[stable(feature = "rust1", since = "1.0.0")]
527-
pub fn to_bytes_with_nul(&self) -> &[u8] {
530+
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
531+
pub const fn to_bytes_with_nul(&self) -> &[u8] {
528532
// SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s
529533
// is safe on all supported targets.
530534
unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
@@ -547,7 +551,8 @@ impl CStr {
547551
/// assert_eq!(cstr.to_str(), Ok("foo"));
548552
/// ```
549553
#[stable(feature = "cstr_to_str", since = "1.4.0")]
550-
pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
554+
#[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
555+
pub const fn to_str(&self) -> Result<&str, str::Utf8Error> {
551556
// N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
552557
// instead of in `from_ptr()`, it may be worth considering if this should
553558
// be rewritten to do the UTF-8 check inline with the length calculation

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@
157157
#![feature(const_slice_from_ref)]
158158
#![feature(const_slice_index)]
159159
#![feature(const_is_char_boundary)]
160+
#![feature(const_cstr_methods)]
160161
//
161162
// Language features:
162163
#![feature(abi_unadjusted)]

library/core/src/slice/memchr.rs

+24-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
33

44
use crate::cmp;
5+
use crate::intrinsics;
56
use crate::mem;
67

78
const LO_USIZE: usize = usize::repeat_u8(0x01);
@@ -35,13 +36,31 @@ fn repeat_byte(b: u8) -> usize {
3536
/// Returns the first index matching the byte `x` in `text`.
3637
#[must_use]
3738
#[inline]
38-
pub fn memchr(x: u8, text: &[u8]) -> Option<usize> {
39-
// Fast path for small slices
40-
if text.len() < 2 * USIZE_BYTES {
41-
return text.iter().position(|elt| *elt == x);
39+
pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
40+
#[inline]
41+
fn rt_impl(x: u8, text: &[u8]) -> Option<usize> {
42+
// Fast path for small slices
43+
if text.len() < 2 * USIZE_BYTES {
44+
return text.iter().position(|elt| *elt == x);
45+
}
46+
47+
memchr_general_case(x, text)
48+
}
49+
50+
const fn const_impl(x: u8, bytes: &[u8]) -> Option<usize> {
51+
let mut i = 0;
52+
while i < bytes.len() {
53+
if bytes[i] == x {
54+
return Some(i);
55+
}
56+
i += 1;
57+
}
58+
59+
None
4260
}
4361

44-
memchr_general_case(x, text)
62+
// SAFETY: The const and runtime versions have identical behavior
63+
unsafe { intrinsics::const_eval_select((x, text), const_impl, rt_impl) }
4564
}
4665

4766
fn memchr_general_case(x: u8, text: &[u8]) -> Option<usize> {

0 commit comments

Comments
 (0)