Skip to content

Commit 890be42

Browse files
committed
Convert struct FromBytesWithNulError into enum
One of `CStr` constructors, `CStr::from_bytes_with_nul(bytes: &[u8])` handles 3 cases: 1. `bytes` has one NULL as the last value - creates CStr 2. `bytes` has no NULL - error 3. `bytes` has a NULL in some other position - error The 3rd case is error that may require lossy conversion, but the 2nd case can easily be handled by the user code. Unfortunately, this function returns an opaque `FromBytesWithNulError` error in both 2nd and 3rd case, so the user cannot detect just the 2nd case - having to re-implement the entire function and bring in the `memchr` dependency. In [this code](https://github.com/gquintard/varnish-rs/blob/f86d7a87683b08d2e634d63e77d9dc1d24ed4a13/varnish-sys/src/vcl/ws.rs#L158), my FFI code needs to copy user's `&[u8]` into a C-allocated memory blob in a NUL-terminated `CStr` format. My code must first validate if `&[u8]` has a trailing NUL (case 1), no NUL (adds one on the fly - case 2), or NUL in the middle (3rd case - error). I had to re-implement `from_bytes_with_nul` and add `memchr`dependency just to handle the 2nd case. This PR renames the former `kind` enum from `FromBytesWithNulErrorKind` to `FromBytesWithNulError`, and removes the original struct.
1 parent 4ed8cf4 commit 890be42

File tree

1 file changed

+16
-31
lines changed

1 file changed

+16
-31
lines changed

library/core/src/ffi/c_str.rs

+16-31
Original file line numberDiff line numberDiff line change
@@ -124,37 +124,22 @@ pub struct CStr {
124124
///
125125
/// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err();
126126
/// ```
127-
#[derive(Clone, PartialEq, Eq, Debug)]
127+
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
128128
#[stable(feature = "core_c_str", since = "1.64.0")]
129-
pub struct FromBytesWithNulError {
130-
kind: FromBytesWithNulErrorKind,
131-
}
132-
133-
#[derive(Clone, PartialEq, Eq, Debug)]
134-
enum FromBytesWithNulErrorKind {
135-
InteriorNul(usize),
129+
pub enum FromBytesWithNulError {
130+
/// Data provided contains an interior nul byte at byte `pos`.
131+
InteriorNul { pos: usize },
132+
/// Data provided is not nul terminated.
136133
NotNulTerminated,
137134
}
138135

139-
// FIXME: const stability attributes should not be required here, I think
140-
impl FromBytesWithNulError {
141-
const fn interior_nul(pos: usize) -> FromBytesWithNulError {
142-
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
143-
}
144-
const fn not_nul_terminated() -> FromBytesWithNulError {
145-
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
146-
}
147-
}
148-
149136
#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
150137
impl Error for FromBytesWithNulError {
151138
#[allow(deprecated)]
152139
fn description(&self) -> &str {
153-
match self.kind {
154-
FromBytesWithNulErrorKind::InteriorNul(..) => {
155-
"data provided contains an interior nul byte"
156-
}
157-
FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated",
140+
match self {
141+
Self::InteriorNul(..) => "data provided contains an interior nul byte",
142+
Self::NotNulTerminated => "data provided is not nul terminated",
158143
}
159144
}
160145
}
@@ -199,7 +184,7 @@ impl fmt::Display for FromBytesWithNulError {
199184
#[allow(deprecated, deprecated_in_future)]
200185
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201186
f.write_str(self.description())?;
202-
if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
187+
if let Self::InteriorNul(pos) = self {
203188
write!(f, " at byte pos {pos}")?;
204189
}
205190
Ok(())
@@ -349,25 +334,25 @@ impl CStr {
349334
/// use std::ffi::CStr;
350335
///
351336
/// let cstr = CStr::from_bytes_with_nul(b"hello\0");
352-
/// assert!(cstr.is_ok());
337+
/// assert_eq!(cstr, Ok(c"hello"));
353338
/// ```
354339
///
355340
/// Creating a `CStr` without a trailing nul terminator is an error:
356341
///
357342
/// ```
358-
/// use std::ffi::CStr;
343+
/// use std::ffi::{CStr, FromBytesWithNulError};
359344
///
360345
/// let cstr = CStr::from_bytes_with_nul(b"hello");
361-
/// assert!(cstr.is_err());
346+
/// assert_eq!(cstr, Err(FromBytesWithNulError::NotNulTerminated));
362347
/// ```
363348
///
364349
/// Creating a `CStr` with an interior nul byte is an error:
365350
///
366351
/// ```
367-
/// use std::ffi::CStr;
352+
/// use std::ffi::{CStr, FromBytesWithNulError};
368353
///
369354
/// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0");
370-
/// assert!(cstr.is_err());
355+
/// assert_eq!(cstr, Err(FromBytesWithNulError::InteriorNul(2)));
371356
/// ```
372357
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
373358
#[rustc_const_stable(feature = "const_cstr_methods", since = "1.72.0")]
@@ -379,8 +364,8 @@ impl CStr {
379364
// of the byte slice.
380365
Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
381366
}
382-
Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)),
383-
None => Err(FromBytesWithNulError::not_nul_terminated()),
367+
Some(nul_pos) => Err(FromBytesWithNulError::InteriorNul(nul_pos)),
368+
None => Err(FromBytesWithNulError::NotNulTerminated),
384369
}
385370
}
386371

0 commit comments

Comments
 (0)