Skip to content

Commit aee4570

Browse files
Rollup merge of rust-lang#107429 - tgross35:from-bytes-until-null-stabilization, r=dtolnay
Stabilize feature `cstr_from_bytes_until_nul` This PR seeks to stabilize `cstr_from_bytes_until_nul`. Partially addresses rust-lang#95027 This function has only been on nightly for about 10 months, but I think it is simple enough that there isn't harm discussing stabilization. It has also had at least a handful of mentions on both the user forum and the discord, so it seems like it's already in use or at least known. This needs FCP still. Comment on potential discussion points: - eventual conversion of `CStr` to be a single thin pointer: this function will still be useful to provide a safe way to create a `CStr` after this change. - should this return a length too, to address concerns about the `CStr` change? I don't see it as being particularly useful, and it seems less ergonomic (i.e. returning `Result<(&CStr, usize), FromBytesUntilNulError>`). I think users that also need this length without the additional `strlen` call are likely better off using a combination of other methods, but this is up for discussion - `CString::from_vec_until_nul`: this is also useful, but it doesn't even have a nightly implementation merged yet. I propose feature gating that separately, as opposed to blocking this `CStr` implementation on that Possible alternatives: A user can use `from_bytes_with_nul` on a slice up to `my_slice[..my_slice.iter().find(|c| c == 0).unwrap()]`. However; that is significantly less ergonomic, and is a bit more work for the compiler to optimize compared the direct `memchr` call that this wraps. ## New stable API ```rs // both in core::ffi pub struct FromBytesUntilNulError(()); impl CStr { pub const fn from_bytes_until_nul( bytes: &[u8] ) -> Result<&CStr, FromBytesUntilNulError> } ``` cc ```@ericseppanen``` original author, ```@Mark-Simulacrum``` original reviewer, ```@m-ou-se``` brought up some issues on the thin pointer CStr ```@rustbot``` modify labels: +T-libs-api +needs-fcp
2 parents a478b83 + 877e9f5 commit aee4570

File tree

6 files changed

+18
-13
lines changed

6 files changed

+18
-13
lines changed

library/alloc/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@
116116
#![feature(const_eval_select)]
117117
#![feature(const_pin)]
118118
#![feature(const_waker)]
119-
#![feature(cstr_from_bytes_until_nul)]
120119
#![feature(dispatch_from_dyn)]
121120
#![feature(error_generic_member_access)]
122121
#![feature(error_in_core)]

library/core/src/error.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ impl Error for crate::ffi::FromBytesWithNulError {
505505
}
506506
}
507507

508-
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
508+
#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
509509
impl Error for crate::ffi::FromBytesUntilNulError {}
510510

511511
#[unstable(feature = "get_many_mut", issue = "104642")]

library/core/src/ffi/c_str.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,10 @@ impl FromBytesWithNulError {
150150
/// This error is created by the [`CStr::from_bytes_until_nul`] method.
151151
///
152152
#[derive(Clone, PartialEq, Eq, Debug)]
153-
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
153+
#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
154154
pub struct FromBytesUntilNulError(());
155155

156-
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
156+
#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
157157
impl fmt::Display for FromBytesUntilNulError {
158158
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159159
write!(f, "data provided does not contain a nul")
@@ -306,8 +306,6 @@ impl CStr {
306306
///
307307
/// # Examples
308308
/// ```
309-
/// #![feature(cstr_from_bytes_until_nul)]
310-
///
311309
/// use std::ffi::CStr;
312310
///
313311
/// let mut buffer = [0u8; 16];
@@ -322,8 +320,9 @@ impl CStr {
322320
/// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
323321
/// ```
324322
///
325-
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
326-
#[rustc_const_unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
323+
#[rustc_allow_const_fn_unstable(const_slice_index)]
324+
#[stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
325+
#[rustc_const_stable(feature = "cstr_from_bytes_until_nul", since = "CURRENT_RUSTC_VERSION")]
327326
pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
328327
let nul_pos = memchr::memchr(0, bytes);
329328
match nul_pos {

library/core/src/slice/memchr.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,29 @@ const USIZE_BYTES: usize = mem::size_of::<usize>();
1616
/// bytes where the borrow propagated all the way to the most significant
1717
/// bit."
1818
#[inline]
19+
#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
1920
const fn contains_zero_byte(x: usize) -> bool {
2021
x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0
2122
}
2223

23-
#[cfg(target_pointer_width = "16")]
2424
#[inline]
25+
#[cfg(target_pointer_width = "16")]
26+
#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
2527
const fn repeat_byte(b: u8) -> usize {
2628
(b as usize) << 8 | b as usize
2729
}
2830

29-
#[cfg(not(target_pointer_width = "16"))]
3031
#[inline]
32+
#[cfg(not(target_pointer_width = "16"))]
33+
#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
3134
const fn repeat_byte(b: u8) -> usize {
3235
(b as usize) * (usize::MAX / 255)
3336
}
3437

3538
/// Returns the first index matching the byte `x` in `text`.
36-
#[must_use]
3739
#[inline]
40+
#[must_use]
41+
#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
3842
pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
3943
// Fast path for small slices.
4044
if text.len() < 2 * USIZE_BYTES {
@@ -45,6 +49,7 @@ pub const fn memchr(x: u8, text: &[u8]) -> Option<usize> {
4549
}
4650

4751
#[inline]
52+
#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
4853
const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
4954
let mut i = 0;
5055

@@ -60,6 +65,10 @@ const fn memchr_naive(x: u8, text: &[u8]) -> Option<usize> {
6065
None
6166
}
6267

68+
#[rustc_allow_const_fn_unstable(const_cmp)]
69+
#[rustc_allow_const_fn_unstable(const_slice_index)]
70+
#[rustc_allow_const_fn_unstable(const_align_offset)]
71+
#[rustc_const_stable(feature = "const_memchr", since = "1.65.0")]
6372
const fn memchr_aligned(x: u8, text: &[u8]) -> Option<usize> {
6473
// Scan for a single byte value by reading two `usize` words at a time.
6574
//

library/std/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,6 @@
278278
#![feature(char_error_internals)]
279279
#![feature(char_internals)]
280280
#![feature(core_intrinsics)]
281-
#![feature(cstr_from_bytes_until_nul)]
282281
#![feature(cstr_internals)]
283282
#![feature(duration_constants)]
284283
#![feature(error_generic_member_access)]

src/tools/miri/tests/pass-dep/shims/pthreads.rs

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//@ignore-target-windows: No libc on Windows
2-
#![feature(cstr_from_bytes_until_nul)]
32
use std::ffi::{CStr, CString};
43
use std::thread;
54

0 commit comments

Comments
 (0)